|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 # Generate xpi for the simulator addon by: |
|
6 # - building a special gaia profile for it, as we need: |
|
7 # * more languages, and, |
|
8 # * less apps |
|
9 # than b2g desktop's one |
|
10 # - retrieve usefull app version metadata from the build system |
|
11 # - finally, use addon sdk's cfx tool to build the addon xpi |
|
12 # that ships: |
|
13 # * a small firefox addon registering to the app manager |
|
14 # * b2g desktop runtime |
|
15 # * gaia profile |
|
16 |
|
17 import sys, os, re, subprocess |
|
18 from mozbuild.preprocessor import Preprocessor |
|
19 from mozbuild.base import MozbuildObject |
|
20 from mozbuild.util import ensureParentDir |
|
21 from zipfile import ZipFile |
|
22 from distutils.version import LooseVersion |
|
23 |
|
24 ftp_root_path = "/pub/mozilla.org/labs/fxos-simulator" |
|
25 UPDATE_LINK = "https://ftp.mozilla.org" + ftp_root_path + "/%(update_path)s/%(xpi_name)s" |
|
26 UPDATE_URL = "https://ftp.mozilla.org" + ftp_root_path + "/%(update_path)s/update.rdf" |
|
27 XPI_NAME = "fxos-simulator-%(version)s-%(platform)s.xpi" |
|
28 |
|
29 class GaiaBuilder(object): |
|
30 def __init__(self, build, gaia_path): |
|
31 self.build = build |
|
32 self.gaia_path = gaia_path |
|
33 |
|
34 def clean(self): |
|
35 self.build._run_make(target="clean", directory=self.gaia_path) |
|
36 |
|
37 def profile(self, env): |
|
38 self.build._run_make(target="profile", directory=self.gaia_path, num_jobs=1, silent=False, append_env=env) |
|
39 |
|
40 def override_prefs(self, srcfile): |
|
41 # Note that each time we call `make profile` in gaia, a fresh new pref file is created |
|
42 # cat srcfile >> profile/user.js |
|
43 with open(os.path.join(self.gaia_path, "profile", "user.js"), "a") as userJs: |
|
44 userJs.write(open(srcfile).read()) |
|
45 |
|
46 def process_package_overload(src, dst, version, app_buildid): |
|
47 ensureParentDir(dst) |
|
48 # First replace numeric version like '1.3' |
|
49 # Then replace with 'slashed' version like '1_4' |
|
50 # Finally set the full length addon version like 1.3.20131230 |
|
51 # (reduce the app build id to only the build date |
|
52 # as addon manager doesn't handle big ints in addon versions) |
|
53 defines = { |
|
54 "NUM_VERSION": version, |
|
55 "SLASH_VERSION": version.replace(".", "_"), |
|
56 "FULL_VERSION": ("%s.%s" % (version, app_buildid[:8])) |
|
57 } |
|
58 pp = Preprocessor(defines=defines) |
|
59 pp.do_filter("substitution") |
|
60 with open(dst, "w") as output: |
|
61 with open(src, "r") as input: |
|
62 pp.processFile(input=input, output=output) |
|
63 |
|
64 def add_dir_to_zip(zip, top, pathInZip, blacklist=()): |
|
65 zf = ZipFile(zip, "a") |
|
66 for dirpath, subdirs, files in os.walk(top): |
|
67 dir_relpath = os.path.relpath(dirpath, top) |
|
68 if dir_relpath.startswith(blacklist): |
|
69 continue |
|
70 zf.write(dirpath, os.path.join(pathInZip, dir_relpath)) |
|
71 for filename in files: |
|
72 relpath = os.path.join(dir_relpath, filename) |
|
73 if relpath in blacklist: |
|
74 continue |
|
75 zf.write(os.path.join(dirpath, filename), |
|
76 os.path.join(pathInZip, relpath)) |
|
77 zf.close() |
|
78 |
|
79 def main(platform): |
|
80 build = MozbuildObject.from_environment() |
|
81 topsrcdir = build.topsrcdir |
|
82 distdir = build.distdir |
|
83 |
|
84 srcdir = os.path.join(topsrcdir, "b2g", "simulator") |
|
85 |
|
86 app_buildid = open(os.path.join(build.topobjdir, "config", "buildid")).read().strip() |
|
87 |
|
88 # The simulator uses a shorter version string, |
|
89 # it only keeps the major version digits A.B |
|
90 # whereas MOZ_B2G_VERSION is A.B.C.D |
|
91 b2g_version = build.config_environment.defines["MOZ_B2G_VERSION"].replace('"', '') |
|
92 version = ".".join(str(n) for n in LooseVersion(b2g_version).version[0:2]) |
|
93 |
|
94 # Build a gaia profile specific to the simulator in order to: |
|
95 # - disable the FTU |
|
96 # - set custom prefs to enable devtools debugger server |
|
97 # - set custom settings to disable lockscreen and screen timeout |
|
98 # - only ship production apps |
|
99 gaia_path = build.config_environment.substs["GAIADIR"] |
|
100 builder = GaiaBuilder(build, gaia_path) |
|
101 builder.clean() |
|
102 env = { |
|
103 "NOFTU": "1", |
|
104 "GAIA_APP_TARGET": "production", |
|
105 "SETTINGS_PATH": os.path.join(srcdir, "custom-settings.json") |
|
106 } |
|
107 builder.profile(env) |
|
108 builder.override_prefs(os.path.join(srcdir, "custom-prefs.js")) |
|
109 |
|
110 # Substitute version strings in the package manifest overload file |
|
111 manifest_overload = os.path.join(build.topobjdir, "b2g", "simulator", "package-overload.json") |
|
112 process_package_overload(os.path.join(srcdir, "package-overload.json.in"), |
|
113 manifest_overload, |
|
114 version, |
|
115 app_buildid) |
|
116 |
|
117 # Build the simulator addon xpi |
|
118 xpi_name = XPI_NAME % {"version": version, "platform": platform} |
|
119 xpi_path = os.path.join(distdir, xpi_name) |
|
120 |
|
121 update_path = "%s/%s" % (version, platform) |
|
122 update_link = UPDATE_LINK % {"update_path": update_path, "xpi_name": xpi_name} |
|
123 update_url = UPDATE_URL % {"update_path": update_path} |
|
124 subprocess.check_call([ |
|
125 build.virtualenv_manager.python_path, os.path.join(topsrcdir, "addon-sdk", "source", "bin", "cfx"), "xpi", \ |
|
126 "--pkgdir", srcdir, \ |
|
127 "--manifest-overload", manifest_overload, \ |
|
128 "--strip-sdk", \ |
|
129 "--update-link", update_link, \ |
|
130 "--update-url", update_url, \ |
|
131 "--static-args", "{\"label\": \"Firefox OS %s\"}" % version, \ |
|
132 "--output-file", xpi_path \ |
|
133 ]) |
|
134 |
|
135 # Ship b2g-desktop, but prevent its gaia profile to be shipped in the xpi |
|
136 add_dir_to_zip(xpi_path, os.path.join(distdir, "b2g"), "b2g", ("gaia", "B2G.app/Contents/MacOS/gaia")) |
|
137 # Then ship our own gaia profile |
|
138 add_dir_to_zip(xpi_path, os.path.join(gaia_path, "profile"), "profile") |
|
139 |
|
140 if __name__ == '__main__': |
|
141 if 2 != len(sys.argv): |
|
142 print("""Usage: |
|
143 python {0} MOZ_PKG_PLATFORM |
|
144 """.format(sys.argv[0])) |
|
145 sys.exit(1) |
|
146 main(*sys.argv[1:]) |
|
147 |