entry in the buddy
-allocator's directory. It is 20 bytes long and contains five integers:
-
-=over
-
-=item
-
-The block number of the root node of the B-tree
-
-=item
-
-The number of levels of internal nodes (tree height minus one --- that
-is, for a tree containing only a single, leaf, node this will be zero)
-
-=item
-
-The number of records in the tree
-
-=item
-
-The number of nodes in the tree (tree nodes, not including this header
-block)
-
-=item
-
-Always 0x1000, probably the tree node page size
-
-=back
-
-Individual nodes are either leaf nodes containing a bunch of records,
-or non-leaf (internal) nodes containing N records and N+1 pointers to
-child nodes.
-
-Each node starts with two integers, C and C. If C is 0,
-then this is a leaf node and C is immediately followed by that
-many records. If C is nonzero, then this is an internal node, and
-C is followed by the block number of the leftmost child, then a
-record, then another block number, I, for a total of C
-child pointers and C records. C is itself the rightmost
-child pointer, that is, it is logically at the end of the node.
-
-This relies on 0 not being a valid value for a block number. As far as
-I can tell, 0 is a valid value for a block number but it always holds
-the block containing the buddy allocator's internal information,
-presumably because that block is allocated first.
-
-The ordering of records within the B-tree is by case-insensitive
-comparison of their filenames, secondarily sorted on the structure
-ID (record type) field. My guess is that the string comparison follows
-the same rules as HFS+ described in Apple's TN1150.
-
-=head2 Buddy Allocator
-
-B-tree pages and other info are stored in blocks managed by a buddy
-allocator. The allocator maintains a list of the offsets and sizes of
-blocks (indexed by small integers) and a freelist.
-The allocator also stores a small amount of metadata, including a
-directory or table of contents which maps short strings to block
-numbers. The only entry in that table of contents maps the string
-C ("desktop services database"?) to the B-tree's master block.
-
-The buddy allocator is in charge of all but the first 36 bytes of
-the file, and manages a notional 2GB address space, although the file is
-of course truncated to the last allocated block. All its offsets are
-relative to the fourth byte of the file. Another way to describe this
-is that the file consists of a four-byte header (always C<00 00 00
-01>) followed by a 2GB buddy-allocated area, the first 32-byte block
-of which is allocated but does not appear on the buddy allocator's
-allocation list.
-
-The 32-byte header has the following fields:
-
-=over
-
-=item *
-
-Magic number C (C<42 75 64 31>)
-
-=item *
-
-Offset to the allocator's bookkeeping information block
-
-=item *
-
-Size of the allocator's bookkeeping information block
-
-=item *
-
-A second copy of the offset; the Finder will refuse to read the file
-if this does not match the first copy. Perhaps this is a safeguard
-against corruption from an interrupted write transaction.
-
-=item *
-
-Sixteen bytes of unknown purpose.
-These might simply be the unused space at the end of the block,
-since
-the minimum allocation size is 32 bytes, as will be seen later.
-
-=back
-
-The offset and size indicate where to find the block containing the
-rest of the buddy allocator's state. That block has the following
-fields:
-
-=over
-
-=item Block count
-
-Integer. The number of blocks in the allocated-blocks list.
-
-=item Unknown
-
-Four unknown bytes. Appear to always be 0.
-
-=item Block addresses
-
-Array of integers. There are I block addresses here, with
-unassigned block numbers represented by zeroes. This is followed by
-enough zeroes to round the section up to the next multiple of 256
-entries (1024 bytes).
-
-=item Directory count
-
-Integer, indicates the number of directory entries.
-
-=item Directory entries
-
-Each consists of a 1-byte count, followed by that many bytes of name
-(in ASCII or perhaps some 1-byte superset such as MacRoman), followed
-by a 4-byte integer containing the entry's block number.
-
-=item Free lists
-
-There are 32 freelists, one for each power of two from 2^0 to
-2^31. Each freelist has a count followed by that many offsets.
-
-=back
-
-There are three different ways to refer to a given block. Most of the
-file uses what I call block numbers or block IDs, which are indexes
-into the C table. Block ID 0 always seems to refer to
-the buddy allocator's metadata block itself.
-
-The entries in the block address table are what I call block addresses.
-Each address is a packed offset+size. The least-significant 5 bits of
-the number indicate the block's size, as a power of 2 (from 2^5 to
-2^31). If those bits are masked off, the result is the starting offset
-of the block (keeping in mind the 4-byte fudge factor). Since the
-lower 5 bits are unusable to store an offset, blocks must be allocated
-on 32-byte boundaries, and as a side effect the minimum block size is
-32 bytes
-(in which case the least significant 5 bits are equal to C<0x05>).
-
-The free lists contain actual block offsets, not "addresses". The
-size of the referenced blocks is implied by which freelist the block
-is in; a free block in freelist N is 2^N bytes long.
-
-Although the header block is not explicitly allocated, the allocator
-behaves as if it is; other blocks are split in order to accommodate it
-in the buddy scheme, and its buddy block (at 0x20) is either on the
-freelist or allocated. (Usually it holds the B-tree's master block.)
-
-Other than the 4-byte prefix and the 32-byte header block, every byte
-in the file is either in a block on the allocated blocks list, or is in a
-block on one of the free lists.
-
-=head1 CREDITS
-
-Original reverse-engineering effort by Mark Mentovai,
-L. Some of the text
-describing record types has been copied from that wiki page.
-
-Further investigation and documentation by Wim Lewis
-Ewiml@hhhh.orgE.
-
-Also thanks to Yvan BARTHELEMY for investigation and bugfixes.
diff --git a/packages/dmg-builder/vendor/biplist/__init__.py b/packages/dmg-builder/vendor/biplist/__init__.py
index 17d35178d14..3cbe3341d70 100644
--- a/packages/dmg-builder/vendor/biplist/__init__.py
+++ b/packages/dmg-builder/vendor/biplist/__init__.py
@@ -15,12 +15,12 @@
Date values can only be datetime.datetime objects.
-The exceptions InvalidPlistException and NotBinaryPlistException may be
+The exceptions InvalidPlistException and NotBinaryPlistException may be
thrown to indicate that the data cannot be serialized or deserialized as
a binary plist.
Plist generation example:
-
+
from biplist import *
from datetime import datetime
plist = {'aKey':'aValue',
@@ -84,24 +84,24 @@ class Uid(object):
integer = 0
def __init__(self, integer):
self.integer = integer
-
+
def __repr__(self):
return "Uid(%d)" % self.integer
-
+
def __eq__(self, other):
if isinstance(self, Uid) and isinstance(other, Uid):
return self.integer == other.integer
return False
-
+
def __cmp__(self, other):
return self.integer - other.integer
-
+
def __lt__(self, other):
return self.integer < other.integer
-
+
def __hash__(self):
return self.integer
-
+
def __int__(self):
return int(self.integer)
@@ -222,21 +222,24 @@ class PlistReader(object):
offsets = None
trailer = None
currentOffset = 0
-
+ # Used to detect recursive object references.
+ offsetsStack = []
+
def __init__(self, fileOrStream):
"""Raises NotBinaryPlistException."""
self.reset()
self.file = fileOrStream
-
+
def parse(self):
return self.readRoot()
-
+
def reset(self):
self.trailer = None
self.contents = ''
self.offsets = []
self.currentOffset = 0
-
+ self.offsetsStack = []
+
def readRoot(self):
result = None
self.reset()
@@ -250,13 +253,44 @@ def readRoot(self):
trailerContents = self.contents[-32:]
try:
self.trailer = PlistTrailer._make(unpack("!xxxxxxBBQQQ", trailerContents))
+
+ if pow(2, self.trailer.offsetSize*8) < self.trailer.offsetTableOffset:
+ raise InvalidPlistException("Offset size insufficient to reference all objects.")
+
+ if pow(2, self.trailer.objectRefSize*8) < self.trailer.offsetCount:
+ raise InvalidPlistException("Too many offsets to represent in size of object reference representation.")
+
offset_size = self.trailer.offsetSize * self.trailer.offsetCount
offset = self.trailer.offsetTableOffset
+
+ if offset + offset_size > pow(2, 64):
+ raise InvalidPlistException("Offset table is excessively long.")
+
+ if self.trailer.offsetSize > 16:
+ raise InvalidPlistException("Offset size is greater than maximum integer size.")
+
+ if self.trailer.objectRefSize == 0:
+ raise InvalidPlistException("Object reference size is zero.")
+
+ if offset >= len(self.contents) - 32:
+ raise InvalidPlistException("Offset table offset is too large.")
+
+ if offset < len("bplist00x"):
+ raise InvalidPlistException("Offset table offset is too small.")
+
+ if self.trailer.topLevelObjectNumber >= self.trailer.offsetCount:
+ raise InvalidPlistException("Top level object number is larger than the number of objects.")
+
offset_contents = self.contents[offset:offset+offset_size]
offset_i = 0
+ offset_table_length = len(offset_contents)
+
while offset_i < self.trailer.offsetCount:
begin = self.trailer.offsetSize*offset_i
- tmp_contents = offset_contents[begin:begin+self.trailer.offsetSize]
+ end = begin+self.trailer.offsetSize
+ if end > offset_table_length:
+ raise InvalidPlistException("End of object is at invalid offset %d in offset table of length %d" % (end, offset_table_length))
+ tmp_contents = offset_contents[begin:end]
tmp_sized = self.getSizedInteger(tmp_contents, self.trailer.offsetSize)
self.offsets.append(tmp_sized)
offset_i += 1
@@ -265,24 +299,41 @@ def readRoot(self):
except TypeError as e:
raise InvalidPlistException(e)
return result
-
+
def setCurrentOffsetToObjectNumber(self, objectNumber):
+ if objectNumber > len(self.offsets) - 1:
+ raise InvalidPlistException("Invalid offset number: %d" % objectNumber)
self.currentOffset = self.offsets[objectNumber]
-
+ if self.currentOffset in self.offsetsStack:
+ raise InvalidPlistException("Recursive data structure detected in object: %d" % objectNumber)
+
+ def beginOffsetProtection(self):
+ self.offsetsStack.append(self.currentOffset)
+ return self.currentOffset
+
+ def endOffsetProtection(self, offset):
+ try:
+ index = self.offsetsStack.index(offset)
+ self.offsetsStack = self.offsetsStack[:index]
+ except ValueError as e:
+ pass
+
def readObject(self):
+ protection = self.beginOffsetProtection()
result = None
tmp_byte = self.contents[self.currentOffset:self.currentOffset+1]
+ if len(tmp_byte) != 1:
+ raise InvalidPlistException("No object found at offset: %d" % self.currentOffset)
marker_byte = unpack("!B", tmp_byte)[0]
format = (marker_byte >> 4) & 0x0f
extra = marker_byte & 0x0f
self.currentOffset += 1
-
+
def proc_extra(extra):
if extra == 0b1111:
- #self.currentOffset += 1
extra = self.readObject()
return extra
-
+
# bool, null, or fill byte
if format == 0b0000:
if extra == 0b0000:
@@ -297,11 +348,9 @@ def proc_extra(extra):
raise InvalidPlistException("Invalid object found at offset: %d" % (self.currentOffset - 1))
# int
elif format == 0b0001:
- extra = proc_extra(extra)
result = self.readInteger(pow(2, extra))
# real
elif format == 0b0010:
- extra = proc_extra(extra)
result = self.readReal(extra)
# date
elif format == 0b0011 and extra == 0b0011:
@@ -333,42 +382,50 @@ def proc_extra(extra):
elif format == 0b1101:
extra = proc_extra(extra)
result = self.readDict(extra)
- else:
+ else:
raise InvalidPlistException("Invalid object found: {format: %s, extra: %s}" % (bin(format), bin(extra)))
+ self.endOffsetProtection(protection)
return result
-
+
+ def readContents(self, length, description="Object contents"):
+ end = self.currentOffset + length
+ if end >= len(self.contents) - 32:
+ raise InvalidPlistException("%s extends into trailer" % description)
+ elif length < 0:
+ raise InvalidPlistException("%s length is less than zero" % length)
+ data = self.contents[self.currentOffset:end]
+ return data
+
def readInteger(self, byteSize):
- result = 0
- original_offset = self.currentOffset
- data = self.contents[self.currentOffset:self.currentOffset + byteSize]
- result = self.getSizedInteger(data, byteSize, as_number=True)
- self.currentOffset = original_offset + byteSize
- return result
-
+ data = self.readContents(byteSize, "Integer")
+ self.currentOffset = self.currentOffset + byteSize
+ return self.getSizedInteger(data, byteSize, as_number=True)
+
def readReal(self, length):
- result = 0.0
to_read = pow(2, length)
- data = self.contents[self.currentOffset:self.currentOffset+to_read]
+ data = self.readContents(to_read, "Real")
if length == 2: # 4 bytes
result = unpack('>f', data)[0]
elif length == 3: # 8 bytes
result = unpack('>d', data)[0]
else:
- raise InvalidPlistException("Unknown real of length %d bytes" % to_read)
+ raise InvalidPlistException("Unknown Real of length %d bytes" % to_read)
return result
-
- def readRefs(self, count):
+
+ def readRefs(self, count):
refs = []
i = 0
while i < count:
- fragment = self.contents[self.currentOffset:self.currentOffset+self.trailer.objectRefSize]
+ fragment = self.readContents(self.trailer.objectRefSize, "Object reference")
ref = self.getSizedInteger(fragment, len(fragment))
refs.append(ref)
self.currentOffset += self.trailer.objectRefSize
i += 1
return refs
-
+
def readArray(self, count):
+ if not isinstance(count, (int, long)):
+ raise InvalidPlistException("Count of entries in dict isn't of integer type.")
result = []
values = self.readRefs(count)
i = 0
@@ -378,8 +435,10 @@ def readArray(self, count):
result.append(value)
i += 1
return result
-
+
def readDict(self, count):
+ if not isinstance(count, (int, long)):
+ raise InvalidPlistException("Count of keys/values in dict isn't of integer type.")
result = {}
keys = self.readRefs(count)
values = self.readRefs(count)
@@ -392,39 +451,58 @@ def readDict(self, count):
result[key] = value
i += 1
return result
-
+
def readAsciiString(self, length):
- result = unpack("!%ds" % length, self.contents[self.currentOffset:self.currentOffset+length])[0]
+ if not isinstance(length, (int, long)):
+ raise InvalidPlistException("Length of ASCII string isn't of integer type.")
+ data = self.readContents(length, "ASCII string")
+ result = unpack("!%ds" % length, data)[0]
self.currentOffset += length
return str(result.decode('ascii'))
-
+
def readUnicode(self, length):
+ if not isinstance(length, (int, long)):
+ raise InvalidPlistException("Length of Unicode string isn't of integer type.")
actual_length = length*2
- data = self.contents[self.currentOffset:self.currentOffset+actual_length]
- # unpack not needed?!! data = unpack(">%ds" % (actual_length), data)[0]
+ data = self.readContents(actual_length, "Unicode string")
self.currentOffset += actual_length
return data.decode('utf_16_be')
-
+
def readDate(self):
- result = unpack(">d", self.contents[self.currentOffset:self.currentOffset+8])[0]
+ data = self.readContents(8, "Date")
+ x = unpack(">d", data)[0]
+ if math.isnan(x):
+ raise InvalidPlistException("Date is NaN")
# Use timedelta to workaround time_t size limitation on 32-bit python.
- result = datetime.timedelta(seconds=result) + apple_reference_date
+ try:
+ result = datetime.timedelta(seconds=x) + apple_reference_date
+ except OverflowError:
+ if x > 0:
+ result = datetime.datetime.max
+ else:
+ result = datetime.datetime.min
self.currentOffset += 8
return result
-
+
def readData(self, length):
- result = self.contents[self.currentOffset:self.currentOffset+length]
+ if not isinstance(length, (int, long)):
+ raise InvalidPlistException("Length of data isn't of integer type.")
+ result = self.readContents(length, "Data")
self.currentOffset += length
return Data(result)
-
+
def readUid(self, length):
+ if not isinstance(length, (int, long)):
+ raise InvalidPlistException("Uid length isn't of integer type.")
return Uid(self.readInteger(length+1))
-
+
def getSizedInteger(self, data, byteSize, as_number=False):
"""Numbers of 8 bytes are signed integers when they refer to numbers, but unsigned otherwise."""
result = 0
+ if byteSize == 0:
+ raise InvalidPlistException("Encountered integer with byte size of 0.")
# 1, 2, and 4 byte integers are unsigned
- if byteSize == 1:
+ elif byteSize == 1:
result = unpack('>B', data)[0]
elif byteSize == 2:
result = unpack('>H', data)[0]
@@ -477,16 +555,16 @@ def __repr__(self):
class StringWrapper(object):
__instances = {}
-
+
encodedValue = None
encoding = None
-
+
def __new__(cls, value):
'''Ensure we only have a only one instance for any string,
and that we encode ascii as 1-byte-per character when possible'''
-
+
encodedValue = None
-
+
for encoding in ('ascii', 'utf_16_be'):
try:
encodedValue = value.encode(encoding)
@@ -497,26 +575,26 @@ def __new__(cls, value):
cls.__instances[encodedValue].encodedValue = encodedValue
cls.__instances[encodedValue].encoding = encoding
return cls.__instances[encodedValue]
-
+
raise ValueError('Unable to get ascii or utf_16_be encoding for %s' % repr(value))
-
+
def __len__(self):
'''Return roughly the number of characters in this string (half the byte length)'''
if self.encoding == 'ascii':
return len(self.encodedValue)
else:
return len(self.encodedValue)//2
-
+
def __lt__(self, other):
return self.encodedValue < other.encodedValue
-
+
@property
def encodingMarker(self):
if self.encoding == 'ascii':
return 0b0101
else:
return 0b0110
-
+
def __repr__(self):
return '' % (self.encoding, self.encodedValue)
@@ -530,7 +608,9 @@ class PlistWriter(object):
referencePositions = None
wrappedTrue = None
wrappedFalse = None
-
+ # Used to detect recursive object references.
+ objectsStack = []
+
def __init__(self, file):
self.reset()
self.file = file
@@ -540,19 +620,21 @@ def __init__(self, file):
def reset(self):
self.byteCounts = PlistByteCounts(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
self.trailer = PlistTrailer(0, 0, 0, 0, 0)
-
+
# A set of all the uniques which have been computed.
self.computedUniques = set()
# A list of all the uniques which have been written.
self.writtenReferences = {}
# A dict of the positions of the written uniques.
self.referencePositions = {}
-
+
+ self.objectsStack = []
+
def positionOfObjectReference(self, obj):
"""If the given object has been written already, return its
position in the offset table. Otherwise, return None."""
return self.writtenReferences.get(obj)
-
+
def writeRoot(self, root):
"""
Strategy is:
@@ -575,7 +657,7 @@ def writeRoot(self, root):
self.trailer = self.trailer._replace(**{'objectRefSize':self.intSize(len(self.computedUniques))})
self.writeObjectReference(wrapped_root, output)
output = self.writeObject(wrapped_root, output, setReferencePosition=True)
-
+
# output size at this point is an upper bound on how big the
# object reference offsets need to be.
self.trailer = self.trailer._replace(**{
@@ -584,43 +666,65 @@ def writeRoot(self, root):
'offsetTableOffset':len(output),
'topLevelObjectNumber':0
})
-
+
output = self.writeOffsetTable(output)
output += pack('!xxxxxxBBQQQ', *self.trailer)
self.file.write(output)
+ def beginRecursionProtection(self, obj):
+ if not isinstance(obj, (set, dict, list, tuple)):
+ return
+ if id(obj) in self.objectsStack:
+ raise InvalidPlistException("Recursive containers are not allowed in plists.")
+ self.objectsStack.append(id(obj))
+
+ def endRecursionProtection(self, obj):
+ if not isinstance(obj, (set, dict, list, tuple)):
+ return
+ try:
+ index = self.objectsStack.index(id(obj))
+ self.objectsStack = self.objectsStack[:index]
+ except ValueError as e:
+ pass
+
def wrapRoot(self, root):
+ result = None
+ self.beginRecursionProtection(root)
+
if isinstance(root, bool):
if root is True:
- return self.wrappedTrue
+ result = self.wrappedTrue
else:
- return self.wrappedFalse
+ result = self.wrappedFalse
elif isinstance(root, float):
- return FloatWrapper(root)
+ result = FloatWrapper(root)
elif isinstance(root, set):
n = set()
for value in root:
n.add(self.wrapRoot(value))
- return HashableWrapper(n)
+ result = HashableWrapper(n)
elif isinstance(root, dict):
n = {}
for key, value in iteritems(root):
n[self.wrapRoot(key)] = self.wrapRoot(value)
- return HashableWrapper(n)
+ result = HashableWrapper(n)
elif isinstance(root, list):
n = []
for value in root:
n.append(self.wrapRoot(value))
- return HashableWrapper(n)
+ result = HashableWrapper(n)
elif isinstance(root, tuple):
n = tuple([self.wrapRoot(value) for value in root])
- return HashableWrapper(n)
+ result = HashableWrapper(n)
elif isinstance(root, (str, unicode)) and not isinstance(root, Data):
- return StringWrapper(root)
+ result = StringWrapper(root)
elif isinstance(root, bytes):
- return Data(root)
+ result = Data(root)
else:
- return root
+ result = root
+
+ self.endRecursionProtection(root)
+ return result
def incrementByteCount(self, field, incr=1):
self.byteCounts = self.byteCounts._replace(**{field:self.byteCounts.__getattribute__(field) + incr})
@@ -633,7 +737,7 @@ def check_key(key):
raise InvalidPlistException('Data cannot be dictionary keys in plists.')
elif not isinstance(key, StringWrapper):
raise InvalidPlistException('Keys must be strings.')
-
+
def proc_size(size):
if size > 0b1110:
size += self.intSize(size)
@@ -645,7 +749,7 @@ def proc_size(size):
return
else:
self.computedUniques.add(obj)
-
+
if obj is None:
self.incrementByteCount('nullBytes')
elif isinstance(obj, BoolWrapper):
@@ -659,7 +763,7 @@ def proc_size(size):
elif isinstance(obj, FloatWrapper):
size = self.realSize(obj)
self.incrementByteCount('realBytes', incr=1+size)
- elif isinstance(obj, datetime.datetime):
+ elif isinstance(obj, datetime.datetime):
self.incrementByteCount('dateBytes', incr=2)
elif isinstance(obj, Data):
size = proc_size(len(obj))
@@ -719,15 +823,15 @@ def proc_variable_length(format, length):
else:
result += pack('!B', (format << 4) | length)
return result
-
+
def timedelta_total_seconds(td):
# Shim for Python 2.6 compatibility, which doesn't have total_seconds.
# Make one argument a float to ensure the right calculation.
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10.0**6) / 10.0**6
-
+
if setReferencePosition:
self.referencePositions[obj] = len(output)
-
+
if obj is None:
output += pack('!B', 0b00000000)
elif isinstance(obj, BoolWrapper):
@@ -771,7 +875,7 @@ def timedelta_total_seconds(td):
output += proc_variable_length(0b1100, len(obj))
else:
output += proc_variable_length(0b1010, len(obj))
-
+
objectsToWrite = []
for objRef in sorted(obj) if isinstance(obj, set) else obj:
(isNew, output) = self.writeObjectReference(objRef, output)
@@ -798,7 +902,7 @@ def timedelta_total_seconds(td):
for objRef in objectsToWrite:
output = self.writeObject(objRef, output, setReferencePosition=True)
return output
-
+
def writeOffsetTable(self, output):
"""Writes all of the object reference offsets."""
all_positions = []
@@ -818,12 +922,12 @@ def writeOffsetTable(self, output):
output += self.binaryInt(position, self.trailer.offsetSize)
all_positions.append(position)
return output
-
+
def binaryReal(self, obj):
# just use doubles
result = pack('>d', obj.value)
return result
-
+
def binaryInt(self, obj, byteSize=None, as_number=False):
result = b''
if byteSize is None:
@@ -847,7 +951,7 @@ def binaryInt(self, obj, byteSize=None, as_number=False):
else:
raise InvalidPlistException("Core Foundation can't handle integers with size greater than 16 bytes.")
return result
-
+
def intSize(self, obj):
"""Returns the number of bytes necessary to store the given integer."""
# SIGNED
@@ -868,6 +972,6 @@ def intSize(self, obj):
return 16
else:
raise InvalidPlistException("Core Foundation can't handle integers with size greater than 8 bytes.")
-
+
def realSize(self, obj):
return 8
diff --git a/packages/dmg-builder/vendor/dmgProperties.py b/packages/dmg-builder/vendor/dmgProperties.py
new file mode 100644
index 00000000000..504df8b81c2
--- /dev/null
+++ b/packages/dmg-builder/vendor/dmgProperties.py
@@ -0,0 +1,186 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import os
+
+dsStoreFile = os.path.join(os.environ["volumePath"], '.DS_Store')
+
+options = {
+ 'format': 'UDBZ',
+ 'compression_level': None,
+ 'size': None,
+ 'files': [],
+ 'symlinks': {},
+ 'icon': None,
+ 'badge_icon': None,
+ 'background': None,
+ 'show_status_bar': False,
+ 'show_tab_view': False,
+ 'show_toolbar': False,
+ 'show_pathbar': False,
+ 'show_sidebar': False,
+ 'sidebar_width': 180,
+ 'arrange_by': None,
+ 'grid_offset': (0, 0),
+ 'grid_spacing': 100.0,
+ 'scroll_position': (0.0, 0.0),
+ 'show_icon_preview': False,
+ 'show_item_info': False,
+ 'label_pos': 'bottom',
+ 'text_size': 16.0,
+ 'icon_size': 128.0,
+ 'include_icon_view_settings': 'auto',
+ 'include_list_view_settings': 'auto',
+ 'list_icon_size': 16.0,
+ 'list_text_size': 12.0,
+ 'list_scroll_position': (0, 0),
+ 'list_sort_by': 'name',
+ 'list_use_relative_dates': True,
+ 'list_calculate_all_sizes': False,
+ 'list_columns': ('name', 'date-modified', 'size', 'kind', 'date-added'),
+ 'list_column_widths': {
+ 'name': 300,
+ 'date-modified': 181,
+ 'date-created': 181,
+ 'date-added': 181,
+ 'date-last-opened': 181,
+ 'size': 97,
+ 'kind': 115,
+ 'label': 100,
+ 'version': 75,
+ 'comments': 300,
+ },
+ 'list_column_sort_directions': {
+ 'name': 'ascending',
+ 'date-modified': 'descending',
+ 'date-created': 'descending',
+ 'date-added': 'descending',
+ 'date-last-opened': 'descending',
+ 'size': 'descending',
+ 'kind': 'ascending',
+ 'label': 'ascending',
+ 'version': 'ascending',
+ 'comments': 'ascending',
+ },
+ 'window_rect': ((100, 100), (640, 280)),
+ 'default_view': 'icon-view',
+ 'icon_locations': {},
+ 'license': None,
+ 'defines': {}
+}
+
+bounds = options['window_rect']
+
+bounds_string = '{{%s, %s}, {%s, %s}}' % (bounds[0][0],
+ bounds[0][1],
+ bounds[1][0],
+ bounds[1][1])
+bwsp = {
+ 'ShowStatusBar': options['show_status_bar'],
+ 'WindowBounds': bounds_string,
+ 'ContainerShowSidebar': False,
+ 'PreviewPaneVisibility': False,
+ 'SidebarWidth': options['sidebar_width'],
+ 'ShowTabView': options['show_tab_view'],
+ 'ShowToolbar': options['show_toolbar'],
+ 'ShowPathbar': options['show_pathbar'],
+ 'ShowSidebar': options['show_sidebar']
+}
+
+arrange_options = {
+ 'name': 'name',
+ 'date-modified': 'dateModified',
+ 'date-created': 'dateCreated',
+ 'date-added': 'dateAdded',
+ 'date-last-opened': 'dateLastOpened',
+ 'size': 'size',
+ 'kind': 'kind',
+ 'label': 'label',
+}
+
+icvp = {
+ 'viewOptionsVersion': 1,
+ 'backgroundType': 0,
+ 'backgroundColorRed': 1.0,
+ 'backgroundColorGreen': 1.0,
+ 'backgroundColorBlue': 1.0,
+ 'gridOffsetX': float(options['grid_offset'][0]),
+ 'gridOffsetY': float(options['grid_offset'][1]),
+ 'gridSpacing': float(options['grid_spacing']),
+ 'arrangeBy': str(arrange_options.get(options['arrange_by'], 'none')),
+ 'showIconPreview': options['show_icon_preview'] == True,
+ 'showItemInfo': options['show_item_info'] == True,
+ 'labelOnBottom': options['label_pos'] == 'bottom',
+ 'textSize': float(options['text_size']),
+ 'iconSize': float(options['icon_size']),
+ 'scrollPositionX': float(options['scroll_position'][0]),
+ 'scrollPositionY': float(options['scroll_position'][1])
+}
+
+columns = {
+ 'name': 'name',
+ 'date-modified': 'dateModified',
+ 'date-created': 'dateCreated',
+ 'date-added': 'dateAdded',
+ 'date-last-opened': 'dateLastOpened',
+ 'size': 'size',
+ 'kind': 'kind',
+ 'label': 'label',
+ 'version': 'version',
+ 'comments': 'comments'
+}
+
+default_widths = {
+ 'name': 300,
+ 'date-modified': 181,
+ 'date-created': 181,
+ 'date-added': 181,
+ 'date-last-opened': 181,
+ 'size': 97,
+ 'kind': 115,
+ 'label': 100,
+ 'version': 75,
+ 'comments': 300,
+}
+
+default_sort_directions = {
+ 'name': 'ascending',
+ 'date-modified': 'descending',
+ 'date-created': 'descending',
+ 'date-added': 'descending',
+ 'date-last-opened': 'descending',
+ 'size': 'descending',
+ 'kind': 'ascending',
+ 'label': 'ascending',
+ 'version': 'ascending',
+ 'comments': 'ascending',
+}
+
+lsvp = {
+ 'viewOptionsVersion': 1,
+ 'sortColumn': columns.get(options['list_sort_by'], 'name'),
+ 'textSize': float(options['list_text_size']),
+ 'iconSize': float(options['list_icon_size']),
+ 'showIconPreview': options['show_icon_preview'],
+ 'scrollPositionX': options['list_scroll_position'][0],
+ 'scrollPositionY': options['list_scroll_position'][1],
+ 'useRelativeDates': options['list_use_relative_dates'],
+ 'calculateAllSizes': options['list_calculate_all_sizes'],
+}
+
+lsvp['columns'] = {}
+cndx = {}
+
+with DSStore.open(dsStoreFile, 'w+') as d:
+ d['.']['vSrn'] = ('long', 1)
+ d['.']['bwsp'] = bwsp
+ if include_icon_view_settings:
+ d['.']['icvp'] = icvp
+ if background_bmk:
+ d['.']['pBBk'] = background_bmk
+ if include_list_view_settings:
+ d['.']['lsvp'] = lsvp
+ d['.']['icvl'] = icvl
+
+ for k, v in iteritems(options['icon_locations']):
+ d[k]['Iloc'] = v
diff --git a/packages/dmg-builder/vendor/dmgbuild/__init__.py b/packages/dmg-builder/vendor/dmgbuild/__init__.py
deleted file mode 100644
index e7f985c3223..00000000000
--- a/packages/dmg-builder/vendor/dmgbuild/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .core import build_dmg
-
-__all__ = ['dmgbuild']
diff --git a/packages/dmg-builder/vendor/dmgbuild/core.py b/packages/dmg-builder/vendor/dmgbuild/core.py
index ee1abe6554f..a90bae3379a 100644
--- a/packages/dmg-builder/vendor/dmgbuild/core.py
+++ b/packages/dmg-builder/vendor/dmgbuild/core.py
@@ -1,582 +1,292 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-import json
import os
-import pkg_resources
import re
-import shutil
-import subprocess
import sys
-import tempfile
-import tokenize
+reload(sys) # Reload is a hack
+sys.setdefaultencoding('UTF8')
+
+sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), "..")))
try:
- {}.iteritems
- iteritems = lambda x: x.iteritems()
- iterkeys = lambda x: x.iterkeys()
+ {}.iteritems
+ iteritems = lambda x: x.iteritems()
+ iterkeys = lambda x: x.iterkeys()
except AttributeError:
- iteritems = lambda x: x.items()
- iterkeys = lambda x: x.keys()
+ iteritems = lambda x: x.items()
+ iterkeys = lambda x: x.keys()
try:
- unicode
+ unicode
except NameError:
- unicode = str
+ unicode = str
import biplist
from mac_alias import *
from ds_store import *
-from . import colors
+from colors import parseColor
try:
- from . import badge
+ from badge import badge
except ImportError:
- badge = None
-
-_hexcolor_re = re.compile(r'#[0-9a-f]{3}(?:[0-9a-f]{3})?')
+ badge = None
class DMGError(Exception):
- pass
-
-def hdiutil(cmd, *args, **kwargs):
- plist = kwargs.get('plist', True)
- all_args = ['/usr/bin/hdiutil', cmd]
- all_args.extend(args)
- if plist:
- all_args.append('-plist')
- p = subprocess.Popen(all_args, stdout=subprocess.PIPE, close_fds=True)
- output, errors = p.communicate()
- if plist:
- results = biplist.readPlistFromString(output)
- else:
- results = output
- retcode = p.wait()
- return retcode, results
-
-# On Python 2 we can just execfile() it, but Python 3 deprecated that
-def load_settings(filename, settings):
- if sys.version_info[0] == 2:
- execfile(filename, settings, settings)
- else:
- encoding = 'utf-8'
- with open(filename, 'rb') as fp:
- try:
- encoding = tokenize.detect_encoding(fp.readline)[0]
- except SyntaxError:
- pass
-
- with open(filename, 'r', encoding=encoding) as fp:
- exec(compile(fp.read(), filename, 'exec'), settings, settings)
-
-def load_json(filename, settings):
- """Read an appdmg .json spec. Uses the defaults for appdmg, rather than
- the usual defaults for dmgbuild. """
-
- with open(filename, 'r') as fp:
- json_data = json.load(fp)
-
- if 'title' not in json_data:
- raise ValueError('missing \'title\' in JSON settings file')
- if 'contents' not in json_data:
- raise ValueError('missing \'contents\' in JSON settings file')
-
- settings['volume_name'] = json_data['title']
- settings['icon'] = json_data.get('icon', None)
- settings['badge_icon'] = json_data.get('badge-icon', None)
- bk = json_data.get('background', None)
- if bk is None:
- bk = json_data.get('background-color', None)
- if bk is not None:
- settings['background'] = bk
- settings['icon_size'] = json_data.get('icon-size', 80)
- wnd = json_data.get('window', { 'position': (100, 100),
- 'size': (640, 480) })
- pos = wnd.get('position', { 'x': 100, 'y': 100 })
- siz = wnd.get('size', { 'width': 640, 'height': 480 })
- settings['window_rect'] = ((pos.get('x', 100), pos.get('y', 100)),
- (siz.get('width', 640), siz.get('height', 480)))
- settings['format'] = json_data.get('format', 'UDZO')
- settings['compression_level'] = json_data.get('compression-level', None)
- settings['license'] = json_data.get('license', None)
- files = []
- symlinks = {}
- icon_locations = {}
- for fileinfo in json_data.get('contents', []):
- if 'path' not in fileinfo:
- raise ValueError('missing \'path\' in contents in JSON settings file')
- if 'x' not in fileinfo:
- raise ValueError('missing \'x\' in contents in JSON settings file')
- if 'y' not in fileinfo:
- raise ValueError('missing \'y\' in contents in JSON settings file')
-
- kind = fileinfo.get('type', 'file')
- path = fileinfo['path']
- name = fileinfo.get('name', os.path.basename(path.rstrip('/')))
- if kind == 'file':
- files.append((path, name))
- elif kind == 'link':
- symlinks[name] = path
- elif kind == 'position':
- pass
- icon_locations[name] = (fileinfo['x'], fileinfo['y'])
-
- settings['files'] = files
- settings['symlinks'] = symlinks
- settings['icon_locations'] = icon_locations
-
-def build_dmg(filename, volume_name, settings_file=None, settings={},
- defines={}, lookForHiDPI=True):
- options = {
- # Default settings
- 'filename': filename,
- 'volume_name': volume_name,
- 'format': 'UDBZ',
- 'compression_level': None,
- 'size': None,
- 'files': [],
- 'symlinks': {},
- 'icon': None,
- 'badge_icon': None,
- 'background': None,
- 'show_status_bar': False,
- 'show_tab_view': False,
- 'show_toolbar': False,
- 'show_pathbar': False,
- 'show_sidebar': False,
- 'sidebar_width': 180,
- 'arrange_by': None,
- 'grid_offset': (0, 0),
- 'grid_spacing': 100.0,
- 'scroll_position': (0.0, 0.0),
- 'show_icon_preview': False,
- 'show_item_info': False,
- 'label_pos': 'bottom',
- 'text_size': 16.0,
- 'icon_size': 128.0,
- 'include_icon_view_settings': 'auto',
- 'include_list_view_settings': 'auto',
- 'list_icon_size': 16.0,
- 'list_text_size': 12.0,
- 'list_scroll_position': (0, 0),
- 'list_sort_by': 'name',
- 'list_use_relative_dates': True,
- 'list_calculate_all_sizes': False,
- 'list_columns': ('name', 'date-modified', 'size', 'kind', 'date-added'),
- 'list_column_widths': {
- 'name': 300,
- 'date-modified': 181,
- 'date-created': 181,
- 'date-added': 181,
- 'date-last-opened': 181,
- 'size': 97,
- 'kind': 115,
- 'label': 100,
- 'version': 75,
- 'comments': 300,
- },
- 'list_column_sort_directions': {
- 'name': 'ascending',
- 'date-modified': 'descending',
- 'date-created': 'descending',
- 'date-added': 'descending',
- 'date-last-opened': 'descending',
- 'size': 'descending',
- 'kind': 'ascending',
- 'label': 'ascending',
- 'version': 'ascending',
- 'comments': 'ascending',
- },
- 'window_rect': ((100, 100), (640, 280)),
- 'default_view': 'icon-view',
- 'icon_locations': {},
- 'license': None,
- 'defines': defines
- }
-
- # Execute the settings file
- if settings_file:
- # We now support JSON settings files using appdmg's format
- if settings_file.endswith('.json'):
- load_json(settings_file, options)
- else:
- load_settings(settings_file, options)
-
- # Add any overrides
- options.update(settings)
-
- # Set up the finder data
- bounds = options['window_rect']
-
- bounds_string = '{{%s, %s}, {%s, %s}}' % (bounds[0][0],
- bounds[0][1],
- bounds[1][0],
- bounds[1][1])
- bwsp = {
- 'ShowStatusBar': options['show_status_bar'],
- 'WindowBounds': bounds_string.encode('utf-8'),
- 'ContainerShowSidebar': False,
- 'PreviewPaneVisibility': False,
- 'SidebarWidth': options['sidebar_width'],
- 'ShowTabView': options['show_tab_view'],
- 'ShowToolbar': options['show_toolbar'],
- 'ShowPathbar': options['show_pathbar'],
- 'ShowSidebar': options['show_sidebar']
- }
-
- arrange_options = {
- 'name': 'name',
- 'date-modified': 'dateModified',
- 'date-created': 'dateCreated',
- 'date-added': 'dateAdded',
- 'date-last-opened': 'dateLastOpened',
- 'size': 'size',
- 'kind': 'kind',
- 'label': 'label',
- }
-
- icvp = {
- 'viewOptionsVersion': 1,
- 'backgroundType': 0,
- 'backgroundColorRed': 1.0,
- 'backgroundColorGreen': 1.0,
- 'backgroundColorBlue': 1.0,
- 'gridOffsetX': float(options['grid_offset'][0]),
- 'gridOffsetY': float(options['grid_offset'][1]),
- 'gridSpacing': float(options['grid_spacing']),
- 'arrangeBy': str(arrange_options.get(options['arrange_by'], 'none')),
- 'showIconPreview': options['show_icon_preview'] == True,
- 'showItemInfo': options['show_item_info'] == True,
- 'labelOnBottom': options['label_pos'] == 'bottom',
- 'textSize': float(options['text_size']),
- 'iconSize': float(options['icon_size']),
- 'scrollPositionX': float(options['scroll_position'][0]),
- 'scrollPositionY': float(options['scroll_position'][1])
- }
-
- background = options['background']
-
- columns = {
- 'name': 'name',
- 'date-modified': 'dateModified',
- 'date-created': 'dateCreated',
- 'date-added': 'dateAdded',
- 'date-last-opened': 'dateLastOpened',
- 'size': 'size',
- 'kind': 'kind',
- 'label': 'label',
- 'version': 'version',
- 'comments': 'comments'
- }
-
- default_widths = {
- 'name': 300,
- 'date-modified': 181,
- 'date-created': 181,
- 'date-added': 181,
- 'date-last-opened': 181,
- 'size': 97,
- 'kind': 115,
- 'label': 100,
- 'version': 75,
- 'comments': 300,
- }
-
- default_sort_directions = {
- 'name': 'ascending',
- 'date-modified': 'descending',
- 'date-created': 'descending',
- 'date-added': 'descending',
- 'date-last-opened': 'descending',
- 'size': 'descending',
- 'kind': 'ascending',
- 'label': 'ascending',
- 'version': 'ascending',
- 'comments': 'ascending',
- }
-
- lsvp = {
- 'viewOptionsVersion': 1,
- 'sortColumn': columns.get(options['list_sort_by'], 'name'),
- 'textSize': float(options['list_text_size']),
- 'iconSize': float(options['list_icon_size']),
- 'showIconPreview': options['show_icon_preview'],
- 'scrollPositionX': options['list_scroll_position'][0],
- 'scrollPositionY': options['list_scroll_position'][1],
- 'useRelativeDates': options['list_use_relative_dates'],
- 'calculateAllSizes': options['list_calculate_all_sizes'],
- }
-
- lsvp['columns'] = {}
- cndx = {}
-
- for n, column in enumerate(options['list_columns']):
- cndx[column] = n
- width = options['list_column_widths'].get(column,
- default_widths[column])
- asc = 'ascending' == options['list_column_sort_directions'].get(column,
- default_sort_directions[column])
-
- lsvp['columns'][columns[column]] = {
- 'index': n,
- 'width': width,
- 'identifier': columns[column],
- 'visible': True,
- 'ascending': asc
- }
-
- n = len(options['list_columns'])
- for k in iterkeys(columns):
- if cndx.get(k, None) is None:
- cndx[k] = n
- width = default_widths[k]
- asc = 'ascending' == default_sort_directions[k]
-
- lsvp['columns'][columns[column]] = {
- 'index': n,
- 'width': width,
- 'identifier': columns[column],
- 'visible': False,
- 'ascending': asc
- }
-
- n += 1
-
- default_view = options['default_view']
- views = {
- 'icon-view': b'icnv',
- 'column-view': b'clmv',
- 'list-view': b'Nlsv',
- 'coverflow': b'Flwv'
- }
-
- icvl = (b'type', views.get(default_view, 'icnv'))
-
- include_icon_view_settings = default_view == 'icon-view' \
- or options['include_icon_view_settings'] not in \
- ('auto', 'no', 0, False, None)
- include_list_view_settings = default_view in ('list-view', 'coverflow') \
- or options['include_list_view_settings'] not in \
- ('auto', 'no', 0, False, None)
-
- filename = options['filename']
- volume_name = options['volume_name']
-
- # Construct a writeable image to start with
- dirname, basename = os.path.split(os.path.realpath(filename))
- if not basename.endswith('.dmg'):
- basename += '.dmg'
- writableFile = tempfile.NamedTemporaryFile(dir=dirname, prefix='.temp',
- suffix=basename)
-
- total_size = options['size']
- if total_size == None:
- # Start with a size of 128MB - this way we don't need to calculate the
- # size of the background image, volume icon, and .DS_Store file (and
- # 128 MB should be well sufficient for even the most outlandish image
- # sizes, like an uncompressed 5K multi-resolution TIFF)
- total_size = 128 * 1024 * 1024
-
- def roundup(x, n):
- return x if x % n == 0 else x + n - x % n
-
- for path in options['files']:
- if isinstance(path, tuple):
- path = path[0]
-
- if not os.path.islink(path) and os.path.isdir(path):
- for dirpath, dirnames, filenames in os.walk(path):
- for f in filenames:
- fp = os.path.join(dirpath, f)
- total_size += roundup(os.lstat(fp).st_size, 4096)
- else:
- total_size += roundup(os.lstat(path).st_size, 4096)
-
- for name,target in iteritems(options['symlinks']):
- total_size += 4096
-
- total_size = str(max(total_size / 1024, 1024)) + 'K'
-
- ret, output = hdiutil('create',
- '-ov',
- '-volname', volume_name,
- '-fs', 'HFS+',
- '-fsargs', '-c c=64,a=16,e=16',
- '-size', total_size,
- writableFile.name)
-
- if ret:
- raise DMGError('Unable to create disk image')
-
- ret, output = hdiutil('attach',
- '-nobrowse',
- '-owners', 'off',
- '-noidme',
- writableFile.name)
-
- if ret:
- raise DMGError('Unable to attach disk image')
-
- try:
- for info in output['system-entities']:
- if info.get('mount-point', None):
- device = info['dev-entry']
- mount_point = info['mount-point']
-
- icon = options['icon']
- if badge:
- badge_icon = options['badge_icon']
- else:
- badge_icon = None
- icon_target_path = os.path.join(mount_point, '.VolumeIcon.icns')
- if icon:
- shutil.copyfile(icon, icon_target_path)
- elif badge_icon:
- badge.badge_disk_icon(badge_icon, icon_target_path)
-
- if icon or badge_icon:
- subprocess.call(['/usr/bin/SetFile', '-a', 'C', mount_point])
-
- background_bmk = None
-
- if not isinstance(background, (str, unicode)):
- pass
- elif colors.isAColor(background):
- c = colors.parseColor(background).to_rgb()
-
- icvp['backgroundType'] = 1
- icvp['backgroundColorRed'] = float(c.r)
- icvp['backgroundColorGreen'] = float(c.g)
- icvp['backgroundColorBlue'] = float(c.b)
- else:
- if os.path.isfile(background):
- # look to see if there are HiDPI resources available
-
- if lookForHiDPI is True:
- name, extension = os.path.splitext(os.path.basename(background))
- orderedImages = [background]
- imageDirectory = os.path.dirname(background)
- if imageDirectory == '':
- imageDirectory = '.'
- for candidateName in os.listdir(imageDirectory):
- hasScale = re.match(
- '^(?P.+)@(?P\d+)x(?P\.\w+)$',
- candidateName)
- if hasScale and name == hasScale.group('name') and \
- extension == hasScale.group('extension'):
- scale = int(hasScale.group('scale'))
- if len(orderedImages) < scale:
- orderedImages += [None] * (scale - len(orderedImages))
- orderedImages[scale - 1] = os.path.join(imageDirectory, candidateName)
-
- if len(orderedImages) > 1:
- # compile the grouped tiff
- backgroundFile = tempfile.NamedTemporaryFile(suffix='.tiff')
- background = backgroundFile.name
- output = tempfile.TemporaryFile(mode='w+')
- try:
- subprocess.check_call(
- ['/usr/bin/tiffutil', '-cathidpicheck'] +
- filter(None, orderedImages) +
- ['-out', background], stdout=output, stderr=output)
- except Exception as e:
- output.seek(0)
- raise ValueError(
- 'unable to compile combined HiDPI file "%s" got error: %s\noutput: %s'
- % (background, str(e), output.read()))
-
- _, kind = os.path.splitext(background)
- path_in_image = os.path.join(mount_point, '.background' + kind)
- shutil.copyfile(background, path_in_image)
- elif pkg_resources.resource_exists('dmgbuild', 'resources/' + background + '.tiff'):
- tiffdata = pkg_resources.resource_string(
- 'dmgbuild',
- 'resources/' + background + '.tiff')
- path_in_image = os.path.join(mount_point, '.background.tiff')
-
- with open(path_in_image, 'wb') as f:
- f.write(tiffdata)
- else:
- raise ValueError('background file "%s" not found' % background)
-
- alias = Alias.for_file(path_in_image)
- background_bmk = Bookmark.for_file(path_in_image)
-
- icvp['backgroundType'] = 2
- icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes())
-
- for f in options['files']:
- if isinstance(f, tuple):
- f_in_image = os.path.join(mount_point, f[1])
- f = f[0]
- else:
- basename = os.path.basename(f.rstrip('/'))
- f_in_image = os.path.join(mount_point, basename)
-
- # use system ditto command to preserve code signing, etc.
- subprocess.call(['/usr/bin/ditto', f, f_in_image])
-
- for name,target in iteritems(options['symlinks']):
- name_in_image = os.path.join(mount_point, name)
- os.symlink(target, name_in_image)
-
- userfn = options.get('create_hook', None)
- if callable(userfn):
- userfn(mount_point, options)
-
- image_dsstore = os.path.join(mount_point, '.DS_Store')
-
- with DSStore.open(image_dsstore, 'w+') as d:
- d['.']['vSrn'] = ('long', 1)
- d['.']['bwsp'] = bwsp
- if include_icon_view_settings:
- d['.']['icvp'] = icvp
- if background_bmk:
- d['.']['pBBk'] = background_bmk
- if include_list_view_settings:
- d['.']['lsvp'] = lsvp
- d['.']['icvl'] = icvl
-
- for k,v in iteritems(options['icon_locations']):
- d[k]['Iloc'] = v
-
- # Delete .Trashes, if it gets created
- shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)
- except:
- # Always try to detach
- hdiutil('detach', '-force', device, plist=False)
- raise
-
- ret, output = hdiutil('detach', device, plist=False)
-
- if ret:
- hdiutil('detach', '-force', device, plist=False)
- raise DMGError('Unable to detach device cleanly')
-
- # Shrink the output to the minimum possible size
- ret, output = hdiutil('resize',
- '-quiet',
- '-sectors', 'min',
- writableFile.name,
- plist=False)
-
- if ret:
- raise DMGError('Unable to shrink')
-
- key_prefix = {'UDZO': 'zlib', 'UDBZ': 'bzip2', 'ULFO': 'lzfse'}
- compression_level = options['compression_level']
- if options['format'] in key_prefix and compression_level:
- compression_args = [
- '-imagekey',
- key_prefix[options['format']] + '-level=' + str(compression_level)
- ]
- else:
- compression_args = []
-
- ret, output = hdiutil('convert', writableFile.name,
- '-format', options['format'],
- '-ov',
- '-o', filename, *compression_args)
-
- if ret:
- raise DMGError('Unable to convert')
\ No newline at end of file
+ pass
+
+
+def build_dmg():
+ options = {
+ 'icon': None,
+ 'badge_icon': None,
+ 'show_status_bar': False,
+ 'show_tab_view': False,
+ 'show_toolbar': False,
+ 'show_pathbar': False,
+ 'show_sidebar': False,
+ 'sidebar_width': 180,
+ 'arrange_by': None,
+ 'grid_offset': (0, 0),
+ 'grid_spacing': 100.0,
+ 'scroll_position': (0.0, 0.0),
+ 'show_icon_preview': False,
+ 'show_item_info': False,
+ 'label_pos': 'bottom',
+ 'text_size': os.environ['iconTextSize'],
+ 'icon_size': os.environ['iconSize'],
+ 'include_icon_view_settings': 'auto',
+ 'include_list_view_settings': 'auto',
+ 'list_icon_size': 16.0,
+ 'list_text_size': 12.0,
+ 'list_scroll_position': (0, 0),
+ 'list_sort_by': 'name',
+ 'list_use_relative_dates': True,
+ 'list_calculate_all_sizes': False,
+ 'list_columns': ('name', 'date-modified', 'size', 'kind', 'date-added'),
+ 'list_column_widths': {
+ 'name': 300,
+ 'date-modified': 181,
+ 'date-created': 181,
+ 'date-added': 181,
+ 'date-last-opened': 181,
+ 'size': 97,
+ 'kind': 115,
+ 'label': 100,
+ 'version': 75,
+ 'comments': 300,
+ },
+ 'list_column_sort_directions': {
+ 'name': 'ascending',
+ 'date-modified': 'descending',
+ 'date-created': 'descending',
+ 'date-added': 'descending',
+ 'date-last-opened': 'descending',
+ 'size': 'descending',
+ 'kind': 'ascending',
+ 'label': 'ascending',
+ 'version': 'ascending',
+ 'comments': 'ascending',
+ },
+ 'default_view': 'icon-view',
+ }
+
+ # Set up the finder data
+ bwsp = {
+ 'ShowStatusBar': options['show_status_bar'],
+ 'ContainerShowSidebar': False,
+ 'PreviewPaneVisibility': False,
+ 'SidebarWidth': options['sidebar_width'],
+ 'ShowTabView': options['show_tab_view'],
+ 'ShowToolbar': options['show_toolbar'],
+ 'ShowPathbar': options['show_pathbar'],
+ 'ShowSidebar': options['show_sidebar']
+ }
+
+ window_x = os.environ.get('windowX')
+ if window_x:
+ window_y = os.environ['windowY']
+ bwsp['WindowBounds'] = '{{%s, %s}, {%s, %s}}' % (window_x,
+ window_y,
+ os.environ['windowWidth'],
+ os.environ['windowHeight'])
+
+ arrange_options = {
+ 'name': 'name',
+ 'date-modified': 'dateModified',
+ 'date-created': 'dateCreated',
+ 'date-added': 'dateAdded',
+ 'date-last-opened': 'dateLastOpened',
+ 'size': 'size',
+ 'kind': 'kind',
+ 'label': 'label',
+ }
+
+ icvp = {
+ 'viewOptionsVersion': 1,
+ 'backgroundType': 0,
+ 'backgroundColorRed': 1.0,
+ 'backgroundColorGreen': 1.0,
+ 'backgroundColorBlue': 1.0,
+ 'gridOffsetX': float(options['grid_offset'][0]),
+ 'gridOffsetY': float(options['grid_offset'][1]),
+ 'gridSpacing': float(options['grid_spacing']),
+ 'arrangeBy': str(arrange_options.get(options['arrange_by'], 'none')),
+ 'showIconPreview': options['show_icon_preview'] == True,
+ 'showItemInfo': options['show_item_info'] == True,
+ 'labelOnBottom': options['label_pos'] == 'bottom',
+ 'textSize': float(options['text_size']),
+ 'iconSize': float(options['icon_size']),
+ 'scrollPositionX': float(options['scroll_position'][0]),
+ 'scrollPositionY': float(options['scroll_position'][1])
+ }
+
+ columns = {
+ 'name': 'name',
+ 'date-modified': 'dateModified',
+ 'date-created': 'dateCreated',
+ 'date-added': 'dateAdded',
+ 'date-last-opened': 'dateLastOpened',
+ 'size': 'size',
+ 'kind': 'kind',
+ 'label': 'label',
+ 'version': 'version',
+ 'comments': 'comments'
+ }
+
+ default_widths = {
+ 'name': 300,
+ 'date-modified': 181,
+ 'date-created': 181,
+ 'date-added': 181,
+ 'date-last-opened': 181,
+ 'size': 97,
+ 'kind': 115,
+ 'label': 100,
+ 'version': 75,
+ 'comments': 300,
+ }
+
+ default_sort_directions = {
+ 'name': 'ascending',
+ 'date-modified': 'descending',
+ 'date-created': 'descending',
+ 'date-added': 'descending',
+ 'date-last-opened': 'descending',
+ 'size': 'descending',
+ 'kind': 'ascending',
+ 'label': 'ascending',
+ 'version': 'ascending',
+ 'comments': 'ascending',
+ }
+
+ lsvp = {
+ 'viewOptionsVersion': 1,
+ 'sortColumn': columns.get(options['list_sort_by'], 'name'),
+ 'textSize': float(options['list_text_size']),
+ 'iconSize': float(options['list_icon_size']),
+ 'showIconPreview': options['show_icon_preview'],
+ 'scrollPositionX': options['list_scroll_position'][0],
+ 'scrollPositionY': options['list_scroll_position'][1],
+ 'useRelativeDates': options['list_use_relative_dates'],
+ 'calculateAllSizes': options['list_calculate_all_sizes'],
+ }
+
+ lsvp['columns'] = {}
+ cndx = {}
+
+ for n, column in enumerate(options['list_columns']):
+ cndx[column] = n
+ width = options['list_column_widths'].get(column, default_widths[column])
+ asc = 'ascending' == options['list_column_sort_directions'].get(column, default_sort_directions[column])
+
+ lsvp['columns'][columns[column]] = {
+ 'index': n,
+ 'width': width,
+ 'identifier': columns[column],
+ 'visible': True,
+ 'ascending': asc
+ }
+
+ n = len(options['list_columns'])
+ for k in iterkeys(columns):
+ if cndx.get(k, None) is None:
+ cndx[k] = n
+ width = default_widths[k]
+ asc = 'ascending' == default_sort_directions[k]
+
+ lsvp['columns'][columns[column]] = {
+ 'index': n,
+ 'width': width,
+ 'identifier': columns[column],
+ 'visible': False,
+ 'ascending': asc
+ }
+
+ n += 1
+
+ default_view = options['default_view']
+ views = {
+ 'icon-view': b'icnv',
+ 'column-view': b'clmv',
+ 'list-view': b'Nlsv',
+ 'coverflow': b'Flwv'
+ }
+
+ icvl = (b'type', views.get(default_view, 'icnv'))
+
+ include_icon_view_settings = default_view == 'icon-view' \
+ or options['include_icon_view_settings'] not in \
+ ('auto', 'no', 0, False, None)
+ include_list_view_settings = default_view in ('list-view', 'coverflow') \
+ or options['include_list_view_settings'] not in \
+ ('auto', 'no', 0, False, None)
+
+ try:
+ background_bmk = None
+
+ background_color = os.environ.get('backgroundColor')
+ background_file = os.environ.get('backgroundFile')
+
+ if background_color:
+ c = parseColor(background_color).to_rgb()
+
+ icvp['backgroundType'] = 1
+ icvp['backgroundColorRed'] = float(c.r)
+ icvp['backgroundColorGreen'] = float(c.g)
+ icvp['backgroundColorBlue'] = float(c.b)
+ elif background_file:
+ alias = Alias.for_file(background_file)
+ background_bmk = Bookmark.for_file(background_file)
+
+ icvp['backgroundType'] = 2
+ icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes())
+
+ image_dsstore = os.path.join(os.environ['volumePath'], '.DS_Store')
+
+ f = "icon_locations = {\n" + os.environ['iconLocations'] + "\n}"
+ exec (f, options, options)
+
+ with DSStore.open(image_dsstore, 'w+') as d:
+ d['.']['vSrn'] = ('long', 1)
+ d['.']['bwsp'] = bwsp
+ if include_icon_view_settings:
+ d['.']['icvp'] = icvp
+ if background_bmk:
+ d['.']['pBBk'] = background_bmk
+ if include_list_view_settings:
+ d['.']['lsvp'] = lsvp
+ d['.']['icvl'] = icvl
+
+ d['.background']['Iloc'] = (2560, 170)
+ d['.DS_Store']['Iloc'] = (2610, 170)
+ d['.fseventsd']['Iloc'] = (2660, 170)
+ d['.Trashes']['Iloc'] = (2710, 170)
+ d['.VolumeIcon.icns']['Iloc'] = (2760, 170)
+
+ for k, v in iteritems(options['icon_locations']):
+ d[k]['Iloc'] = v
+ except:
+ raise
+
+build_dmg()
\ No newline at end of file
diff --git a/packages/dmg-builder/vendor/dmgbuild/resources.py b/packages/dmg-builder/vendor/dmgbuild/resources.py
deleted file mode 100644
index d2f58e64a4d..00000000000
--- a/packages/dmg-builder/vendor/dmgbuild/resources.py
+++ /dev/null
@@ -1,355 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-import struct
-
-class Resource (object):
- def __init__(self, res_type, res_id, res_name, data=None, res_attrs=0):
- self.res_type = str(res_type)
- self.res_id = res_id
- if isinstance(res_name, basestring):
- res_name = str(res_name)
- self.res_name = res_name
- self.res_attrs = res_attrs
- if data is None:
- self.data = None
- self.data = str(data)
-
- self.data_offset = None
- self.name_offset = None
-
- def __repr__(self):
- return 'Resource(%r, %r, %r, data=%r, res_attrs=%r)' % (self.res_type,
- self.res_id,
- self.res_name,
- self.data,
- self.res_attrs)
-
-class TMPLResource (Resource):
- def __init__(self, res_id, res_name, tmpl, res_attrs=0):
- data = []
- for name,typecode in tmpl:
- data.append(struct.pack(b'B', len(name)))
- data.append(str(name))
- data.append(str(typecode))
- super(TMPLResource, self).__init__(b'TMPL', res_id, res_name,
- b''.join(data), res_attrs)
-
-class StringListResource (Resource):
- def __init__(self, res_id, res_name, strings, res_attrs=0):
- data = []
- data.append(struct.pack(b'>H', len(strings)))
- for s in strings:
- data.append(struct.pack(b'B', len(s)))
- data.append(str(s))
- super(StringListResource, self).__init__(b'STR#', res_id, res_name,
- b''.join(data), res_attrs)
-
-class TextResource (Resource):
- def __init__(self, res_id, res_name, string, res_attrs=0):
- super(TextResource, self).__init__(b'TEXT', res_id, res_name,
- str(string), res_attrs)
-
-class Style (object):
- # Fonts
- NewYork = 2
- Geneva = 3
- Monaco = 4
- Venice = 5
- London = 6
- Athens = 7
- SanFrancisco = 8
- Toronto = 9
- Cairo = 11
- LosAngeles = 12
- Times = 20
- Helvetica = 21
- Courier = 22
- Symbol = 23
- Mobile = 24
-
- # Styles
- Bold = 0x0100
- Italic = 0x0200
- Underline = 0x0400
- Outline = 0x0800
- Shadow = 0x1000
- Condense = 0x2000
- Expand = 0x4000
-
- def __init__(self, start_character, height, ascent, font_id, face,
- size, color):
- self.start_character = start_character
- self.height = height
- self.ascent = ascent
- self.font_id = font_id
- self.face = face
- self.size = size
- self.color = color
-
- def __repr__(self):
- styles = []
- if self.face & Style.Bold:
- styles.append('Style.Bold')
- if self.face & Style.Italic:
- styles.append('Style.Italic')
- if self.face & Style.Underline:
- styles.append('Style.Underline')
- if self.face & Style.Outline:
- styles.append('Style.Outline')
- if self.face & Style.Shadow:
- styles.append('Style.Shadow')
- if self.face & Style.Condense:
- styles.append('Style.Condense')
- if self.face & Style.Expand:
- styles.append('Style.Expand')
- if self.face & ~0x4f00:
- styles.append('%#06x' % (self.face & ~0x4f00))
- if styles:
- styles = '|'.join(styles)
- else:
- styles = '0'
-
- font_revmap = {
- 2: 'Style.NewYork',
- 3: 'Style.Geneva',
- 4: 'Style.Monaco',
- 5: 'Style.Venice',
- 6: 'Style.London',
- 7: 'Style.Athens',
- 8: 'Style.SanFrancisco',
- 9: 'Style.Toronto',
- 11: 'Style.Cairo',
- 12: 'Style.LosAngeles',
- 20: 'Style.Times',
- 21: 'Style.Helvetica',
- 22: 'Style.Courier',
- 23: 'Style.Symbol',
- 24: 'Style.Mobile'
- }
-
- font = font_revmap.get(self.font_id, '%s' % self.font_id)
-
- return 'Style(%r, %r, %r, %s, %s, %r, %r)' % (
- self.start_character,
- self.height,
- self.ascent,
- font,
- styles,
- self.size,
- self.color)
-
-class StyleResource (Resource):
- def __init__(self, res_id, res_name, styles, res_attrs=0):
- data = []
- data.append(struct.pack(b'>H', len(styles)))
- for style in styles:
- data.append(struct.pack(b'>LHHHHHHHH',
- style.start_character,
- style.height,
- style.ascent,
- style.font_id,
- style.face,
- style.size,
- style.color[0],
- style.color[1],
- style.color[2]))
- super(StyleResource, self).__init__(b'styl', res_id, res_name,
- b''.join(data), res_attrs)
-
-class ResourceFork (object):
- def __init__(self, resources=None):
- self.types = {}
- self.attrs = 0
- if resources is not None:
- for res in resources:
- self.add(res)
-
- @classmethod
- def from_data(clss, data):
- if len(data) < 16:
- raise ValueError('Bad resource data - data too short')
-
- # Read the header
- data_start, map_start, data_len, map_len = struct.unpack(b'>LLLL',
- data[0:16])
-
- if data_start + data_len > len(data):
- raise ValueError('Bad resource data - data out of range')
- if map_start + map_len > len(data):
- raise ValueError('Bad resource data - map out of range')
- if map_len < 30:
- raise ValueError('Bad resource data - map too short')
-
- # Read the map header
- fork_attrs, type_offset, name_offset, max_type_ndx \
- = struct.unpack(b'>HHHH', data[map_start + 22:map_start + 30])
- num_types = max_type_ndx + 1
-
- if type_offset + 8 * num_types > map_len:
- raise ValueError('Bad resource data - type data outside map')
-
- if name_offset > map_len:
- raise ValueError('Bad resource data - names outside map')
-
- type_offset += map_start
- name_offset += map_start
-
- result = ResourceFork()
-
- # Now read the type list
- for ntype in range(0, num_types):
- type_pos = 2 + type_offset + 8 * ntype
- res_type, max_item_ndx, ref_offset \
- = struct.unpack(b'>4sHH', data[type_pos:type_pos+8])
- num_items = max_item_ndx + 1
-
- result.types[res_type] = []
-
- ref_list_offset = type_offset + ref_offset
- if ref_list_offset + 12 * num_items > map_start + map_len:
- raise ValueError('Bad resource data - ref list outside map')
-
- for nitem in range(0, num_items):
- ref_elt = ref_list_offset + 12 * nitem
- res_id, res_name_offset, data_offset \
- = struct.unpack(b'>hHL', data[ref_elt:ref_elt+8])
-
- res_attrs = data_offset >> 24
- data_offset &= 0xffffff
-
- if data_offset >= data_len:
- raise ValueError('Bad resource data - item data out of range')
-
- data_offset += data_start
- res_len = struct.unpack(b'>L', data[data_offset:data_offset+4])[0]
- if data_offset + res_len >= data_start + data_len:
- raise ValueError('Bad resource data - item data too large')
-
- res_data = data[data_offset + 4:data_offset + res_len + 4]
-
- if res_name_offset == 0xffff:
- res_name = None
- else:
- res_name_offset += name_offset
- if res_name_offset >= map_start + map_len:
- raise ValueError('Bad resource data - name out of range')
- res_name_len = struct.unpack(b'B', data[res_name_offset])[0]
- res_name = data[res_name_offset + 1:res_name_offset + res_name_len + 1]
-
- result.types[res_type].append(Resource(res_type, res_id,
- res_name,
- res_data, res_attrs))
-
- return result
-
- @classmethod
- def from_file(clss, filename):
- with open(filename + '/..namedfork/rsrc', 'rb') as f:
- data = f.read()
- return clss.from_data(data)
-
- def to_data(self):
- data = []
- data_len = 0
- names = []
- names_len = 0
- types_len = len(self.types) * 8
- types_data = []
- reflist_data = []
- reflist_len = 0
-
- for res_type, items in self.types.items():
- types_data.append(struct.pack(b'>4sHH',
- res_type,
- len(items) - 1,
- 2 + types_len + reflist_len))
- for item in items:
- data_offset = data_len
-
- if item.res_name is None:
- name_offset = 65535
- else:
- name_offset = names_len
- n = str(item.res_name)
- names.append(struct.pack(b'B', len(n)) + n)
- names_len += 1 + len(n)
-
- if item.data is None:
- data_len += 4
- else:
- data_len += 4 + (len(item.data) + 3) & ~3
-
- reflist_len += 12
- reflist_data.append(struct.pack(b'>hHLL',
- item.res_id,
- name_offset,
- (item.res_attrs << 24) \
- | data_offset,
- 0))
-
- # Header
- data.append(struct.pack(b'>LLLL240s', 256, 256 + data_len, data_len,
- 30 + types_len + reflist_len + names_len,
- b''))
-
- # Resource data
- for res_type, items in self.types.items():
- for item in items:
- if item.data is None:
- dlen = 0
- else:
- dlen = len(item.data)
- plen = (dlen + 3) & ~3
- data.append(struct.pack(b'>L', dlen))
- if item.data is not None:
- data.append(item.data)
- if plen != dlen:
- data.append(b'\0' * (plen - dlen))
-
- # Resource map header
- data.append(struct.pack(b'>16sLHHHHH',
- b'', 0, 0,
- self.attrs, 28, 30 + types_len + reflist_len,
- len(self.types) - 1))
-
- # Type list
- data.append(b''.join(types_data))
-
- # Reference lists
- data.append(b''.join(reflist_data))
-
- # Name list
- data.append(b''.join(names))
-
- return b''.join(data)
-
- def write_to_file(self, filename):
- with open(filename + '/..namedfork/rsrc', 'wb') as f:
- f.write(self.to_data())
-
- def __len__(self):
- return len(self.types)
-
- def __getitem__(self, key):
- return self.types[key]
-
- def __iter__(self):
- for res_type, items in self.types.items():
- for item in items:
- yield item
-
- def __repr__(self):
- output = []
- for item in self:
- output.append(repr(item))
- return 'ResourceFork([%s])' % ', '.join(output)
-
- def add(self, res):
- if res.res_type in self.types:
- self.types[res.res_type].append(res)
- else:
- self.types[res.res_type] = [res]
-
- def remove(self, res):
- self.types[res.res_type].remove(res)
diff --git a/packages/dmg-builder/vendor/ds_store/store.py b/packages/dmg-builder/vendor/ds_store/store.py
index b6f805b24c1..93f02e04fba 100644
--- a/packages/dmg-builder/vendor/ds_store/store.py
+++ b/packages/dmg-builder/vendor/ds_store/store.py
@@ -1146,7 +1146,7 @@ def delete(self, filename, code):
# Find implementation
def _find(self, node, filename_lc, code=None):
- if not isinstance(code, bytes):
+ if code is not None and not isinstance(code, bytes):
code = code.encode('latin_1')
with self._get_block(node) as block:
next_node, count = block.read(b'>II')
diff --git a/packages/electron-builder/package.json b/packages/electron-builder/package.json
index e58bff1686e..7343604859f 100644
--- a/packages/electron-builder/package.json
+++ b/packages/electron-builder/package.json
@@ -51,7 +51,7 @@
"builder-util": "0.0.0-semantic-release",
"fs-extra": "^8.1.0",
"is-ci": "^2.0.0",
- "read-config-file": "4.0.1",
+ "read-config-file": "5.0.0",
"sanitize-filename": "^1.6.1",
"update-notifier": "^3.0.1",
"yargs": "^13.3.0",
diff --git a/test/out/mac/__snapshots__/dmgTest.js.snap b/test/out/mac/__snapshots__/dmgTest.js.snap
index 131c4713223..f8f1c4f35ec 100644
--- a/test/out/mac/__snapshots__/dmgTest.js.snap
+++ b/test/out/mac/__snapshots__/dmgTest.js.snap
@@ -1,5 +1,74 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`background color 1`] = `
+Object {
+ "backgroundColor": "orange",
+ "contents": Array [
+ Object {
+ "x": 130,
+ "y": 220,
+ },
+ Object {
+ "path": "/Applications",
+ "type": "link",
+ "x": 410,
+ "y": 220,
+ },
+ ],
+ "format": "UDRO",
+ "icon": "/Volumes/ramdisk/electron-builder-test/build/icon.icns",
+ "writeUpdateInfo": false,
+}
+`;
+
+exports[`background color 2`] = `
+Object {
+ "mac": Array [
+ Object {
+ "arch": "x64",
+ "file": "BackgroundColor-1.1.0.dmg",
+ },
+ ],
+}
+`;
+
+exports[`background color 3`] = `
+Object {
+ "CFBundleDisplayName": "BackgroundColor",
+ "CFBundleExecutable": "BackgroundColor",
+ "CFBundleIconFile": "BackgroundColor.icns",
+ "CFBundleIdentifier": "org.electron-builder.testApp",
+ "CFBundleInfoDictionaryVersion": "6.0",
+ "CFBundleName": "BackgroundColor",
+ "CFBundlePackageType": "APPL",
+ "CFBundleShortVersionString": "1.1.0",
+ "LSApplicationCategoryType": "your.app.category.type",
+ "NSAppTransportSecurity": Object {
+ "NSAllowsLocalNetworking": true,
+ "NSExceptionDomains": Object {
+ "127.0.0.1": Object {
+ "NSIncludesSubdomains": false,
+ "NSTemporaryExceptionAllowsInsecureHTTPLoads": true,
+ "NSTemporaryExceptionAllowsInsecureHTTPSLoads": false,
+ "NSTemporaryExceptionMinimumTLSVersion": "1.0",
+ "NSTemporaryExceptionRequiresForwardSecrecy": false,
+ },
+ "localhost": Object {
+ "NSIncludesSubdomains": false,
+ "NSTemporaryExceptionAllowsInsecureHTTPLoads": true,
+ "NSTemporaryExceptionAllowsInsecureHTTPSLoads": false,
+ "NSTemporaryExceptionMinimumTLSVersion": "1.0",
+ "NSTemporaryExceptionRequiresForwardSecrecy": false,
+ },
+ },
+ },
+ "NSHighResolutionCapable": true,
+ "NSMainNibFile": "MainMenu",
+ "NSPrincipalClass": "AtomApplication",
+ "NSSupportsAutomaticGraphicsSwitching": true,
+}
+`;
+
exports[`bundleShortVersion 1`] = `
Object {
"mac": Array [
diff --git a/test/src/mac/dmgTest.ts b/test/src/mac/dmgTest.ts
index 25e81a31c1e..e32df8fdd6c 100644
--- a/test/src/mac/dmgTest.ts
+++ b/test/src/mac/dmgTest.ts
@@ -31,6 +31,27 @@ test.ifMac("no build directory", app({
projectDirCreated: projectDir => remove(path.join(projectDir, "build")),
}))
+test.ifMac("background color", app({
+ targets: Platform.MAC.createTarget("dmg"),
+ config: {
+ // dmg can mount only one volume name, so, to test in parallel, we set different product name
+ productName: "BackgroundColor",
+ publish: null,
+ dmg: {
+ backgroundColor: "orange",
+ // speed-up test
+ writeUpdateInfo: false,
+ },
+ },
+ effectiveOptionComputed: async it => {
+ if (!("volumePath" in it)) {
+ return false
+ }
+ expect(it.specification).toMatchSnapshot()
+ return false
+ },
+}))
+
test.ifMac("custom background - new way", () => {
const customBackground = "customBackground.png"
return assertPack("test-app-one", {
@@ -43,6 +64,8 @@ test.ifMac("custom background - new way", () => {
dmg: {
background: customBackground,
icon: "foo.icns",
+ // speed-up test
+ writeUpdateInfo: false,
},
},
effectiveOptionComputed: async it => {
diff --git a/test/src/protonTest.ts b/test/src/protonTest.ts
index 4cc20591256..18b5b9acb41 100644
--- a/test/src/protonTest.ts
+++ b/test/src/protonTest.ts
@@ -15,27 +15,27 @@ const checkOptions: AssertPackOptions = {
test.ifAll.ifMac("mac", app({
targets: Platform.MAC.createTarget(),
config: {
- protonNodeVersion: "current",
+ framework: "proton-native",
},
}, checkOptions))
test.ifAll.ifLinuxOrDevMac("linux", app({
targets: Platform.LINUX.createTarget("appimage"),
config: {
- protonNodeVersion: "current",
+ framework: "proton-native",
},
}, checkOptions))
test.ifAll.ifDevOrWinCi("win", app({
targets: Platform.WINDOWS.createTarget("nsis"),
config: {
- protonNodeVersion: "current",
+ framework: "proton-native",
},
}, checkOptions))
test.ifAll.ifDevOrWinCi("win ia32", app({
targets: Platform.WINDOWS.createTarget("nsis", Arch.ia32),
config: {
- protonNodeVersion: "current",
+ framework: "proton-native",
},
}, checkOptions))
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index b660328c30d..3903115c154 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1326,12 +1326,12 @@ acorn@^6.0.1:
resolved "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3"
integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==
-ajv-keywords@^3.4.1:
+ajv-keywords@^3.1.0:
version "3.4.1"
resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
-ajv@^6.10.1, ajv@^6.5.5:
+ajv@^6.1.0, ajv@^6.5.5:
version "6.10.2"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
@@ -1390,10 +1390,10 @@ anymatch@^2.0.0:
micromatch "^3.1.4"
normalize-path "^2.1.1"
-app-builder-bin@3.4.0:
- version "3.4.0"
- resolved "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.4.0.tgz#620d7f941dad157206c267bb0b437fee43889b33"
- integrity sha512-ZyQqfFnyjAmXep29PmuMIu2KvGlfHiziz2/I38zOFe5kqnkMqeNNn/qmnwD6wdCKKeHqBuZtoWQnft8q0YyLpw==
+app-builder-bin@3.4.1:
+ version "3.4.1"
+ resolved "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.4.1.tgz#81a9268b8ec2fedd1e787052cbfd7ed3f497ae30"
+ integrity sha512-zyNWkkzxTtojn+kg0h9lr3IywicYfocEbJi35YkaVUsP1W5HkbIr+Ld1PoEuUJVrErNQAcLrv3KaXNL5BJLwwQ==
aproba@^1.0.3:
version "1.2.0"
@@ -1967,11 +1967,6 @@ color-convert@^1.9.0:
dependencies:
color-name "1.1.3"
-color-convert@~0.5.0:
- version "0.5.3"
- resolved "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
- integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=
-
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
@@ -4111,9 +4106,9 @@ lodash.union@^4.6.0:
integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14:
- version "4.17.14"
- resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
- integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
+ version "4.17.15"
+ resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
+ integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
loose-envify@^1.0.0:
version "1.4.0"
@@ -4731,13 +4726,6 @@ pako@^1.0.10:
resolved "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
-parse-color@^1.0.0:
- version "1.0.0"
- resolved "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz#7b748b95a83f03f16a94f535e52d7f3d94658619"
- integrity sha1-e3SLlag/A/FqlPU15S1/PZRlhhk=
- dependencies:
- color-convert "~0.5.0"
-
parse-json@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -4945,13 +4933,11 @@ react-is@^16.8.4:
resolved "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
-read-config-file@4.0.1:
- version "4.0.1"
- resolved "https://registry.npmjs.org/read-config-file/-/read-config-file-4.0.1.tgz#ece5f6b1a5e6a46d0d93fdd0339f2f60ab892776"
- integrity sha512-5caED3uo2IAZMPcbh/9hx/O29s2430RLxtnFDdzxpH/epEpawOrQnGBHueotIXUrGPPIgdNQN+S/CIp2WmiSfw==
+read-config-file@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/read-config-file/-/read-config-file-5.0.0.tgz#1487c983fae9c1b672d3acda5cac899a2d451f02"
+ integrity sha512-jIKUu+C84bfnKxyJ5j30CxCqgXWYjZLXuVE/NYlMEpeni+dhESgAeZOZd0JZbg1xTkMmnCdxksDoarkOyfEsOg==
dependencies:
- ajv "^6.10.1"
- ajv-keywords "^3.4.1"
dotenv "^8.0.0"
dotenv-expand "^5.1.0"
fs-extra "^8.1.0"
@@ -5302,6 +5288,14 @@ sax@^1.2.4:
resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+schema-utils@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.0.1.tgz#1eec2e059556af841b7f3a83b61af13d7a3f9196"
+ integrity sha512-HJFKJ4JixDpRur06QHwi8uu2kZbng318ahWEKgBjc0ZklcE4FDvmm2wghb448q0IRaABxIESt8vqPFvwgMB80A==
+ dependencies:
+ ajv "^6.1.0"
+ ajv-keywords "^3.1.0"
+
semver-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"