1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/config/nsinstall.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,180 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +# This is a partial python port of nsinstall. 1.9 +# It's intended to be used when there's no natively compile nsinstall 1.10 +# available, and doesn't intend to be fully equivalent. 1.11 +# Its major use is for l10n repackaging on systems that don't have 1.12 +# a full build environment set up. 1.13 +# The basic limitation is, it doesn't even try to link and ignores 1.14 +# all related options. 1.15 +from __future__ import print_function 1.16 +from optparse import OptionParser 1.17 +import os 1.18 +import os.path 1.19 +import sys 1.20 +import shutil 1.21 +import stat 1.22 + 1.23 +def _nsinstall_internal(argv): 1.24 + usage = "usage: %prog [options] arg1 [arg2 ...] target-directory" 1.25 + p = OptionParser(usage=usage) 1.26 + 1.27 + p.add_option('-D', action="store_true", 1.28 + help="Create a single directory only") 1.29 + p.add_option('-t', action="store_true", 1.30 + help="Preserve time stamp") 1.31 + p.add_option('-m', action="store", 1.32 + help="Set mode", metavar="mode") 1.33 + p.add_option('-d', action="store_true", 1.34 + help="Create directories in target") 1.35 + p.add_option('-R', action="store_true", 1.36 + help="Use relative symbolic links (ignored)") 1.37 + p.add_option('-L', action="store", metavar="linkprefix", 1.38 + help="Link prefix (ignored)") 1.39 + p.add_option('-X', action="append", metavar="file", 1.40 + help="Ignore a file when installing a directory recursively.") 1.41 + 1.42 + # The remaining arguments are not used in our tree, thus they're not 1.43 + # implented. 1.44 + def BadArg(option, opt, value, parser): 1.45 + parser.error('option not supported: {0}'.format(opt)) 1.46 + 1.47 + p.add_option('-C', action="callback", metavar="CWD", 1.48 + callback=BadArg, 1.49 + help="NOT SUPPORTED") 1.50 + p.add_option('-o', action="callback", callback=BadArg, 1.51 + help="Set owner (NOT SUPPORTED)", metavar="owner") 1.52 + p.add_option('-g', action="callback", callback=BadArg, 1.53 + help="Set group (NOT SUPPORTED)", metavar="group") 1.54 + 1.55 + (options, args) = p.parse_args(argv) 1.56 + 1.57 + if options.m: 1.58 + # mode is specified 1.59 + try: 1.60 + options.m = int(options.m, 8) 1.61 + except: 1.62 + sys.stderr.write('nsinstall: {0} is not a valid mode\n' 1.63 + .format(options.m)) 1.64 + return 1 1.65 + 1.66 + # just create one directory? 1.67 + def maybe_create_dir(dir, mode, try_again): 1.68 + dir = os.path.abspath(dir) 1.69 + if os.path.exists(dir): 1.70 + if not os.path.isdir(dir): 1.71 + print('nsinstall: {0} is not a directory'.format(dir), file=sys.stderr) 1.72 + return 1 1.73 + if mode: 1.74 + os.chmod(dir, mode) 1.75 + return 0 1.76 + 1.77 + try: 1.78 + if mode: 1.79 + os.makedirs(dir, mode) 1.80 + else: 1.81 + os.makedirs(dir) 1.82 + except Exception as e: 1.83 + # We might have hit EEXIST due to a race condition (see bug 463411) -- try again once 1.84 + if try_again: 1.85 + return maybe_create_dir(dir, mode, False) 1.86 + print("nsinstall: failed to create directory {0}: {1}".format(dir, e)) 1.87 + return 1 1.88 + else: 1.89 + return 0 1.90 + 1.91 + if options.X: 1.92 + options.X = [os.path.abspath(p) for p in options.X] 1.93 + 1.94 + if options.D: 1.95 + return maybe_create_dir(args[0], options.m, True) 1.96 + 1.97 + # nsinstall arg1 [...] directory 1.98 + if len(args) < 2: 1.99 + p.error('not enough arguments') 1.100 + 1.101 + def copy_all_entries(entries, target): 1.102 + for e in entries: 1.103 + e = os.path.abspath(e) 1.104 + if options.X and e in options.X: 1.105 + continue 1.106 + 1.107 + dest = os.path.join(target, os.path.basename(e)) 1.108 + dest = os.path.abspath(dest) 1.109 + handleTarget(e, dest) 1.110 + if options.m: 1.111 + os.chmod(dest, options.m) 1.112 + 1.113 + # set up handler 1.114 + if options.d: 1.115 + # we're supposed to create directories 1.116 + def handleTarget(srcpath, targetpath): 1.117 + # target directory was already created, just use mkdir 1.118 + os.mkdir(targetpath) 1.119 + else: 1.120 + # we're supposed to copy files 1.121 + def handleTarget(srcpath, targetpath): 1.122 + if os.path.isdir(srcpath): 1.123 + if not os.path.exists(targetpath): 1.124 + os.mkdir(targetpath) 1.125 + entries = [os.path.join(srcpath, e) for e in os.listdir(srcpath)] 1.126 + copy_all_entries(entries, targetpath) 1.127 + # options.t is not relevant for directories 1.128 + if options.m: 1.129 + os.chmod(targetpath, options.m) 1.130 + else: 1.131 + if os.path.exists(targetpath): 1.132 + # On Windows, read-only files can't be deleted 1.133 + os.chmod(targetpath, stat.S_IWUSR) 1.134 + os.remove(targetpath) 1.135 + if options.t: 1.136 + shutil.copy2(srcpath, targetpath) 1.137 + else: 1.138 + shutil.copy(srcpath, targetpath) 1.139 + 1.140 + # the last argument is the target directory 1.141 + target = args.pop() 1.142 + # ensure target directory (importantly, we do not apply a mode to the directory 1.143 + # because we want to copy files into it and the mode might be read-only) 1.144 + rv = maybe_create_dir(target, None, True) 1.145 + if rv != 0: 1.146 + return rv 1.147 + 1.148 + copy_all_entries(args, target) 1.149 + return 0 1.150 + 1.151 +# nsinstall as a native command is always UTF-8 1.152 +def nsinstall(argv): 1.153 + return _nsinstall_internal([unicode(arg, "utf-8") for arg in argv]) 1.154 + 1.155 +if __name__ == '__main__': 1.156 + # sys.argv corrupts characters outside the system code page on Windows 1.157 + # <http://bugs.python.org/issue2128>. Use ctypes instead. This is also 1.158 + # useful because switching to Unicode strings makes python use the wide 1.159 + # Windows APIs, which is what we want here since the wide APIs normally do a 1.160 + # better job at handling long paths and such. 1.161 + if sys.platform == "win32": 1.162 + import ctypes 1.163 + from ctypes import wintypes 1.164 + GetCommandLine = ctypes.windll.kernel32.GetCommandLineW 1.165 + GetCommandLine.argtypes = [] 1.166 + GetCommandLine.restype = wintypes.LPWSTR 1.167 + 1.168 + CommandLineToArgv = ctypes.windll.shell32.CommandLineToArgvW 1.169 + CommandLineToArgv.argtypes = [wintypes.LPWSTR, ctypes.POINTER(ctypes.c_int)] 1.170 + CommandLineToArgv.restype = ctypes.POINTER(wintypes.LPWSTR) 1.171 + 1.172 + argc = ctypes.c_int(0) 1.173 + argv_arr = CommandLineToArgv(GetCommandLine(), ctypes.byref(argc)) 1.174 + # The first argv will be "python", the second will be the .py file 1.175 + argv = argv_arr[1:argc.value] 1.176 + else: 1.177 + # For consistency, do it on Unix as well 1.178 + if sys.stdin.encoding is not None: 1.179 + argv = [unicode(arg, sys.stdin.encoding) for arg in sys.argv] 1.180 + else: 1.181 + argv = [unicode(arg) for arg in sys.argv] 1.182 + 1.183 + sys.exit(_nsinstall_internal(argv[1:]))