1# -*- coding: utf-8 -*-
2from __future__ import unicode_literals
3
4import os
5import re
6import sys
7reload(sys)  # Reload is a hack
8sys.setdefaultencoding('UTF8')
9
10sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), "..")))
11
12try:
13  {}.iteritems
14  iteritems = lambda x: x.iteritems()
15  iterkeys = lambda x: x.iterkeys()
16except AttributeError:
17  iteritems = lambda x: x.items()
18  iterkeys = lambda x: x.keys()
19try:
20  unicode
21except NameError:
22  unicode = str
23
24import biplist
25from mac_alias import *
26from ds_store import *
27
28from colors import parseColor
29
30try:
31  from badge import badge
32except ImportError:
33  badge = None
34
35class DMGError(Exception):
36  pass
37
38
39def build_dmg():
40  options = {
41    'icon': None,
42    'badge_icon': None,
43    'sidebar_width': 180,
44    'arrange_by': None,
45    'grid_offset': (0, 0),
46    'grid_spacing': 100.0,
47    'scroll_position': (0.0, 0.0),
48    'show_icon_preview': False,
49    'text_size': os.environ['iconTextSize'],
50    'icon_size': os.environ['iconSize'],
51    'include_icon_view_settings': 'auto',
52    'include_list_view_settings': 'auto',
53    'list_icon_size': 16.0,
54    'list_text_size': 12.0,
55    'list_scroll_position': (0, 0),
56    'list_sort_by': 'name',
57    'list_columns': ('name', 'date-modified', 'size', 'kind', 'date-added'),
58    'list_column_widths': {
59      'name': 300,
60      'date-modified': 181,
61      'date-created': 181,
62      'date-added': 181,
63      'date-last-opened': 181,
64      'size': 97,
65      'kind': 115,
66      'label': 100,
67      'version': 75,
68      'comments': 300,
69    },
70    'list_column_sort_directions': {
71      'name': 'ascending',
72      'date-modified': 'descending',
73      'date-created': 'descending',
74      'date-added': 'descending',
75      'date-last-opened': 'descending',
76      'size': 'descending',
77      'kind': 'ascending',
78      'label': 'ascending',
79      'version': 'ascending',
80      'comments': 'ascending',
81    }
82  }
83
84  # Set up the finder data
85  bwsp = {
86    'ShowStatusBar': False,
87    'ContainerShowSidebar': False,
88    'PreviewPaneVisibility': False,
89    'SidebarWidth': options['sidebar_width'],
90    'ShowTabView': False,
91    'ShowToolbar': False,
92    'ShowPathbar': False,
93    'ShowSidebar': False
94  }
95
96  window_x = os.environ.get('windowX')
97  if window_x:
98    window_y = os.environ['windowY']
99    bwsp['WindowBounds'] = '{{%s, %s}, {%s, %s}}' % (window_x,
100                                                     window_y,
101                                                     os.environ['windowWidth'],
102                                                     os.environ['windowHeight'])
103
104  arrange_options = {
105    'name': 'name',
106    'date-modified': 'dateModified',
107    'date-created': 'dateCreated',
108    'date-added': 'dateAdded',
109    'date-last-opened': 'dateLastOpened',
110    'size': 'size',
111    'kind': 'kind',
112    'label': 'label',
113  }
114
115  icvp = {
116    'viewOptionsVersion': 1,
117    'backgroundType': 0,
118    'backgroundColorRed': 1.0,
119    'backgroundColorGreen': 1.0,
120    'backgroundColorBlue': 1.0,
121    'gridOffsetX': float(options['grid_offset'][0]),
122    'gridOffsetY': float(options['grid_offset'][1]),
123    'gridSpacing': float(options['grid_spacing']),
124    'arrangeBy': str(arrange_options.get(options['arrange_by'], 'none')),
125    'showIconPreview': options['show_icon_preview'] == True,
126    'showItemInfo': False,
127    'labelOnBottom': True,
128    'textSize': float(options['text_size']),
129    'iconSize': float(options['icon_size']),
130    'scrollPositionX': float(options['scroll_position'][0]),
131    'scrollPositionY': float(options['scroll_position'][1])
132  }
133
134  columns = {
135    'name': 'name',
136    'date-modified': 'dateModified',
137    'date-created': 'dateCreated',
138    'date-added': 'dateAdded',
139    'date-last-opened': 'dateLastOpened',
140    'size': 'size',
141    'kind': 'kind',
142    'label': 'label',
143    'version': 'version',
144    'comments': 'comments'
145  }
146
147  default_widths = {
148    'name': 300,
149    'date-modified': 181,
150    'date-created': 181,
151    'date-added': 181,
152    'date-last-opened': 181,
153    'size': 97,
154    'kind': 115,
155    'label': 100,
156    'version': 75,
157    'comments': 300,
158  }
159
160  default_sort_directions = {
161    'name': 'ascending',
162    'date-modified': 'descending',
163    'date-created': 'descending',
164    'date-added': 'descending',
165    'date-last-opened': 'descending',
166    'size': 'descending',
167    'kind': 'ascending',
168    'label': 'ascending',
169    'version': 'ascending',
170    'comments': 'ascending',
171  }
172
173  lsvp = {
174    'viewOptionsVersion': 1,
175    'sortColumn': columns.get(options['list_sort_by'], 'name'),
176    'textSize': float(options['list_text_size']),
177    'iconSize': float(options['list_icon_size']),
178    'showIconPreview': options['show_icon_preview'],
179    'scrollPositionX': options['list_scroll_position'][0],
180    'scrollPositionY': options['list_scroll_position'][1],
181    'useRelativeDates': True,
182    'calculateAllSizes': False,
183  }
184
185  lsvp['columns'] = {}
186  cndx = {}
187
188  for n, column in enumerate(options['list_columns']):
189    cndx[column] = n
190    width = options['list_column_widths'].get(column, default_widths[column])
191    asc = 'ascending' == options['list_column_sort_directions'].get(column, default_sort_directions[column])
192
193    lsvp['columns'][columns[column]] = {
194      'index': n,
195      'width': width,
196      'identifier': columns[column],
197      'visible': True,
198      'ascending': asc
199    }
200
201  n = len(options['list_columns'])
202  for k in iterkeys(columns):
203    if cndx.get(k, None) is None:
204      cndx[k] = n
205      width = default_widths[k]
206      asc = 'ascending' == default_sort_directions[k]
207
208    lsvp['columns'][columns[column]] = {
209      'index': n,
210      'width': width,
211      'identifier': columns[column],
212      'visible': False,
213      'ascending': asc
214    }
215
216    n += 1
217
218  default_view = 'icon-view'
219  views = {
220    'icon-view': b'icnv',
221    'column-view': b'clmv',
222    'list-view': b'Nlsv',
223    'coverflow': b'Flwv'
224  }
225
226  icvl = (b'type', views.get(default_view, 'icnv'))
227
228  include_icon_view_settings = default_view == 'icon-view' \
229                               or options['include_icon_view_settings'] not in \
230                               ('auto', 'no', 0, False, None)
231  include_list_view_settings = default_view in ('list-view', 'coverflow') \
232                               or options['include_list_view_settings'] not in \
233                               ('auto', 'no', 0, False, None)
234
235  try:
236    background_bmk = None
237
238    background_color = os.environ.get('backgroundColor')
239    background_file = os.environ.get('backgroundFile')
240
241    if background_color:
242      c = parseColor(background_color).to_rgb()
243
244      icvp['backgroundType'] = 1
245      icvp['backgroundColorRed'] = float(c.r)
246      icvp['backgroundColorGreen'] = float(c.g)
247      icvp['backgroundColorBlue'] = float(c.b)
248    elif background_file:
249      alias = Alias.for_file(background_file)
250      background_bmk = Bookmark.for_file(background_file)
251
252      icvp['backgroundType'] = 2
253      icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes())
254
255    image_dsstore = os.path.join(os.environ['volumePath'], '.DS_Store')
256
257    f =  "icon_locations = {\n" + os.environ['iconLocations'] + "\n}"
258    exec (f, options, options)
259
260    with DSStore.open(image_dsstore, 'w+') as d:
261      d['.']['vSrn'] = ('long', 1)
262      d['.']['bwsp'] = bwsp
263      if include_icon_view_settings:
264        d['.']['icvp'] = icvp
265        if background_bmk:
266          d['.']['pBBk'] = background_bmk
267      if include_list_view_settings:
268        d['.']['lsvp'] = lsvp
269      d['.']['icvl'] = icvl
270
271      d['.background']['Iloc'] = (2560, 170)
272      d['.DS_Store']['Iloc'] = (2610, 170)
273      d['.fseventsd']['Iloc'] = (2660, 170)
274      d['.Trashes']['Iloc'] = (2710, 170)
275      d['.VolumeIcon.icns']['Iloc'] = (2760, 170)
276
277      for k, v in iteritems(options['icon_locations']):
278        d[k]['Iloc'] = v
279  except:
280    raise
281
282build_dmg()