xulrunner/app/install_app.py

branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
equal deleted inserted replaced
-1:000000000000 0:ad3db7ef504e
1 #!/usr/bin/env python
2
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 # You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 # Min version of python is 2.7
8 import sys
9 if ((sys.version_info.major != 2) or (sys.version_info.minor < 7)):
10 raise Exception("You need to use Python version 2.7 or higher")
11
12 import os, shutil, re, zipfile
13 from ConfigParser import SafeConfigParser
14
15 # Platform-specific support
16 # see https://developer.mozilla.org/en/XULRunner/Deploying_XULRunner_1.8
17 if sys.platform.startswith('linux') or sys.platform == "win32":
18 def installApp(appLocation, installDir, appName, greDir):
19 zipApp, iniParser, appName = validateArguments(appLocation, installDir, appName, greDir)
20 if (zipApp):
21 zipApp.extractAll(installDir)
22 else:
23 shutil.copytree(appLocation, installDir)
24 shutil.copy2(os.path.join(greDir, xulrunnerStubName),
25 os.path.join(installDir, appName))
26 copyGRE(greDir, os.path.join(installDir, "xulrunner"))
27
28 if sys.platform.startswith('linux'):
29 xulrunnerStubName = "xulrunner-stub"
30
31 def makeAppName(leafName):
32 return leafName.lower()
33
34 elif sys.platform == "win32":
35 xulrunnerStubName = "xulrunner-stub.exe"
36
37 def makeAppName(leafName):
38 return leafName + ".exe"
39
40 elif sys.platform == "darwin":
41 xulrunnerStubName = "xulrunner"
42
43 def installApp(appLocation, installDir, appName, greDir):
44 zipApp, iniparser, appName = validateArguments(appLocation, installDir, appName, greDir)
45 installDir += "/" + appName + ".app"
46 resourcesDir = os.path.join(installDir, "Contents/Resources")
47 if (zipApp):
48 zipApp.extractAll(resourcesDir)
49 else:
50 shutil.copytree(appLocation, resourcesDir)
51 MacOSDir = os.path.join(installDir, "Contents/MacOS")
52 os.makedirs(MacOSDir)
53 shutil.copy2(os.path.join(greDir, xulrunnerStubName), MacOSDir)
54 copyGRE(greDir,
55 os.path.join(installDir, "Contents/Frameworks/XUL.framework"))
56
57 # Contents/Info.plist
58 contents = """<?xml version="1.0" encoding="UTF-8"?>
59 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
60 <plist version="1.0">
61 <dict>
62 <key>CFBundleInfoDictionaryVersion</key>
63 <string>6.0</string>
64 <key>CFBundlePackageType</key>
65 <string>APPL</string>
66 <key>CFBundleSignature</key>
67 <string>????</string>
68 <key>CFBundleExecutable</key>
69 <string>xulrunner</string>
70 <key>NSAppleScriptEnabled</key>
71 <true/>
72 <key>CFBundleGetInfoString</key>
73 <string>$infoString</string>
74 <key>CFBundleName</key>
75 <string>$appName</string>
76 <key>CFBundleShortVersionString</key>
77 <string>$version</string>
78 <key>CFBundleVersion</key>
79 <string>$version.$buildID</string>
80 <key>CFBundleIdentifier</key>
81 <string>$reverseVendor</string>
82 </dict>
83 </plist>
84 """
85 version = iniparser.get("App", "Version")
86 buildID = iniparser.get("App", "BuildID")
87 infoString = appName + " " + version
88 reverseVendor = "com.vendor.unknown"
89 appID = iniparser.get("App", "ID")
90 colonIndex = appID.find("@") + 1
91 if (colonIndex != 0):
92 vendor = appID[colonIndex:]
93 reverseVendor = ".".join(vendor.split(".")[::-1])
94 contents = contents.replace("$infoString", infoString)
95 contents = contents.replace("$appName", appName)
96 contents = contents.replace("$version", version)
97 contents = contents.replace("$buildID", buildID)
98 contents = contents.replace("$reverseVendor", reverseVendor)
99 infoPList = open(os.path.join(installDir, "Contents/Info.plist"), "w+b")
100 infoPList.write(contents)
101 infoPList.close()
102
103 def makeAppName(leafName):
104 return leafName
105
106 else:
107 # Implement xulrunnerStubName, installApp and makeAppName as above.
108 raise Exception("This operating system isn't supported for install_app.py yet!")
109 # End platform-specific support
110
111 def resolvePath(path):
112 return os.path.realpath(path)
113
114 def requireINIOption(iniparser, section, option):
115 if not (iniparser.has_option(section, option)):
116 raise Exception("application.ini must have a " + option + " option under the " + section + " section")
117
118 def checkAppINI(appLocation):
119 if (os.path.isdir(appLocation)):
120 zipApp = None
121 appINIPath = os.path.join(appLocation, "application.ini")
122 if not (os.path.isfile(appINIPath)):
123 raise Exception(appINIPath + " does not exist")
124 appINI = open(appINIPath)
125 elif (zipfile.is_zipfile(appLocation)):
126 zipApp = zipfile.ZipFile(appLocation)
127 if not ("application.ini" in zipApp.namelist()):
128 raise Exception("jar:" + appLocation + "!/application.ini does not exist")
129 appINI = zipApp.open("application.ini")
130 else:
131 raise Exception("appLocation must be a directory containing application.ini or a zip file with application.ini at its root")
132
133 # application.ini verification
134 iniparser = SafeConfigParser()
135 iniparser.readfp(appINI)
136 if not (iniparser.has_section("App")):
137 raise Exception("application.ini must have an App section")
138 if not (iniparser.has_section("Gecko")):
139 raise Exception("application.ini must have a Gecko section")
140 requireINIOption(iniparser, "App", "Name")
141 requireINIOption(iniparser, "App", "Version")
142 requireINIOption(iniparser, "App", "BuildID")
143 requireINIOption(iniparser, "App", "ID")
144 requireINIOption(iniparser, "Gecko", "MinVersion")
145
146 return zipApp, iniparser
147 pass
148
149 def copyGRE(greDir, targetDir):
150 shutil.copytree(greDir, targetDir, symlinks=True)
151
152 def validateArguments(appLocation, installDir, appName, greDir):
153 # application directory / zip verification
154 appLocation = resolvePath(appLocation)
155
156 # target directory
157 installDir = resolvePath(installDir)
158
159 if (os.path.exists(installDir)):
160 raise Exception("installDir must not exist: " + cmds.installDir)
161
162 greDir = resolvePath(greDir)
163 xulrunnerStubPath = os.path.isfile(os.path.join(greDir, xulrunnerStubName))
164 if not xulrunnerStubPath:
165 raise Exception("XULRunner stub executable not found: " + os.path.join(greDir, xulrunnerStubName))
166
167 # appName
168 zipApp, iniparser = checkAppINI(appLocation)
169 if not appName:
170 appName = iniparser.get("App", "Name")
171 appName = makeAppName(appName)
172 pattern = re.compile("[\\\/\:*?\"<>|\x00]")
173 if pattern.search(appName):
174 raise Exception("App name has illegal characters for at least one operating system")
175 return zipApp, iniparser, appName
176
177 def handleCommandLine():
178 import argparse
179
180 # Argument parsing.
181 parser = argparse.ArgumentParser(
182 description="XULRunner application installer",
183 usage="""install_app.py appLocation installDir greDir [--appName APPNAME]
184 install_app.py -h
185 install_app.py --version
186 """
187 )
188 parser.add_argument(
189 "appLocation",
190 action="store",
191 help="The directory or ZIP file containing application.ini as a top-level child file"
192 )
193 parser.add_argument(
194 "installDir",
195 action="store",
196 help="The directory to install the application to"
197 )
198 parser.add_argument(
199 "--greDir",
200 action="store",
201 help="The directory containing the Gecko SDK (usually where this Python script lives)",
202 default=os.path.dirname(sys.argv[0])
203 )
204 parser.add_argument(
205 "--appName",
206 action="store",
207 help="The name of the application to install"
208 )
209 parser.add_argument("--version", action="version", version="%(prog)s 1.0")
210
211 # The command code.
212 cmds = parser.parse_args()
213 try:
214 installApp(cmds.appLocation, cmds.installDir, cmds.appName, cmds.greDir)
215 except exn:
216 shutil.rmtree(cmds.installDir)
217 raise exn
218 print cmds.appName + " application installed to " + cmds.installDir
219
220 if __name__ == '__main__':
221 handleCommandLine()

mercurial