config/nsinstall.py

changeset 0
6474c204b198
     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:]))

mercurial