1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
import os
import zipfile
import simplejson as json
from cuddlefish.util import filter_filenames, filter_dirnames
class HarnessOptionAlreadyDefinedError(Exception):
"""You cannot use --harness-option on keys that already exist in
harness-options.json"""
ZIPSEP = "/" # always use "/" in zipfiles
def make_zipfile_path(localroot, localpath):
return ZIPSEP.join(localpath[len(localroot)+1:].split(os.sep))
def mkzipdir(zf, path):
dirinfo = zipfile.ZipInfo(path)
dirinfo.external_attr = int("040755", 8) << 16L
zf.writestr(dirinfo, "")
def build_xpi(template_root_dir, manifest, xpi_path,
harness_options, limit_to=None, extra_harness_options={}):
zf = zipfile.ZipFile(xpi_path, "w", zipfile.ZIP_DEFLATED)
open('.install.rdf', 'w').write(str(manifest))
zf.write('.install.rdf', 'install.rdf')
os.remove('.install.rdf')
if 'icon' in harness_options:
zf.write(str(harness_options['icon']), 'icon.png')
del harness_options['icon']
if 'icon64' in harness_options:
zf.write(str(harness_options['icon64']), 'icon64.png')
del harness_options['icon64']
IGNORED_FILES = [".hgignore", ".DS_Store", "install.rdf",
"application.ini", xpi_path]
files_to_copy = {} # maps zipfile path to local-disk abspath
dirs_to_create = set() # zipfile paths, no trailing slash
for dirpath, dirnames, filenames in os.walk(template_root_dir):
filenames = list(filter_filenames(filenames, IGNORED_FILES))
dirnames[:] = filter_dirnames(dirnames)
for dirname in dirnames:
arcpath = make_zipfile_path(template_root_dir,
os.path.join(dirpath, dirname))
dirs_to_create.add(arcpath)
for filename in filenames:
abspath = os.path.join(dirpath, filename)
arcpath = make_zipfile_path(template_root_dir, abspath)
files_to_copy[arcpath] = abspath
new_resources = {}
for resource in harness_options['resources']:
new_resources[resource] = ['resources', resource]
base_arcpath = ZIPSEP.join(['resources', resource])
# Always write the top directory, even if it contains no files, since
# the harness will try to access it.
dirs_to_create.add(base_arcpath)
abs_dirname = harness_options['resources'][resource]
# cp -r stuff from abs_dirname/ into ZIP/resources/RESOURCEBASE/
for dirpath, dirnames, filenames in os.walk(abs_dirname):
goodfiles = list(filter_filenames(filenames, IGNORED_FILES))
dirnames[:] = filter_dirnames(dirnames)
for filename in goodfiles:
abspath = os.path.join(dirpath, filename)
if limit_to is not None and abspath not in limit_to:
continue # strip unused files
arcpath = ZIPSEP.join(
['resources',
resource,
make_zipfile_path(abs_dirname,
os.path.join(dirpath, filename)),
])
files_to_copy[str(arcpath)] = str(abspath)
harness_options['resources'] = new_resources
# now figure out which directories we need: all retained files parents
for arcpath in files_to_copy:
bits = arcpath.split("/")
for i in range(1,len(bits)):
parentpath = ZIPSEP.join(bits[0:i])
dirs_to_create.add(parentpath)
# create zipfile in alphabetical order, with each directory before its
# files
for name in sorted(dirs_to_create.union(set(files_to_copy))):
if name in dirs_to_create:
mkzipdir(zf, name+"/")
if name in files_to_copy:
zf.write(files_to_copy[name], name)
harness_options = harness_options.copy()
for key,value in extra_harness_options.items():
if key in harness_options:
msg = "Can't use --harness-option for existing key '%s'" % key
raise HarnessOptionAlreadyDefinedError(msg)
harness_options[key] = value
open('.options.json', 'w').write(json.dumps(harness_options, indent=1,
sort_keys=True))
zf.write('.options.json', 'harness-options.json')
os.remove('.options.json')
zf.close()
|