usr/src/cmd/auto-install/xslt/old-to-new.py
changeset 862 e9f31f2f2f2d
child 1151 95413393ef67
equal deleted inserted replaced
861:ccd399d2c6f7 862:e9f31f2f2f2d
       
     1 #!/usr/bin/python2.6
       
     2 #
       
     3 # CDDL HEADER START
       
     4 #
       
     5 # The contents of this file are subject to the terms of the
       
     6 # Common Development and Distribution License (the "License").
       
     7 # You may not use this file except in compliance with the License.
       
     8 #
       
     9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
       
    10 # or http://www.opensolaris.org/os/licensing.
       
    11 # See the License for the specific language governing permissions
       
    12 # and limitations under the License.
       
    13 #
       
    14 # When distributing Covered Code, include this CDDL HEADER in each
       
    15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
       
    16 # If applicable, add the following below this CDDL HEADER, with the
       
    17 # fields enclosed by brackets "[]" replaced with your own identifying
       
    18 # information: Portions Copyright [yyyy] [name of copyright owner]
       
    19 #
       
    20 # CDDL HEADER END
       
    21 #
       
    22 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
       
    23 
       
    24 import sys
       
    25 import os
       
    26 import getopt
       
    27 from subprocess import Popen, PIPE
       
    28 
       
    29 
       
    30 XSLT_PROC="/usr/bin/xsltproc"
       
    31 XSLT_FILE="old-to-new.xslt"
       
    32 
       
    33 
       
    34 def usage(exitcode=1):
       
    35     '''
       
    36         Print help page and exit script.
       
    37 
       
    38         Default exit code is 1, which indicates an error.  To exit
       
    39         normally, set keyword param exitcode to 0.
       
    40     '''
       
    41     this_script = os.path.basename(sys.argv[0])
       
    42 
       
    43     print ""
       
    44     print "%s - Convert old-style XML AI Manifests to the new schema." % this_script
       
    45     print ""
       
    46     print "For convenience, the command-line interface has similar semantics to cp(1)."
       
    47     print ""
       
    48     print "Usage:"
       
    49     print "\t%s [options] infile outfile" % this_script
       
    50     print "\t%s [options] infile... outdir" % this_script
       
    51     print "\t%s -r [options] indir... outdir" % this_script
       
    52     print "\nOptions:"
       
    53     print "\t-f        : force overwrite if output already exists"
       
    54     print "\t-r        : recursively transform .xml files in named sub-directory"
       
    55     print "\t-h --help : print this help page and exit"
       
    56 
       
    57     sys.exit(exitcode)
       
    58 
       
    59 
       
    60 def run_cmd(cmd):
       
    61     '''
       
    62         Execute the given command in a subprocess.
       
    63 
       
    64         On success, returns the stdout from running the command.
       
    65         On failure, raises one of:
       
    66             OSError
       
    67             ValueError
       
    68             Exception
       
    69     '''
       
    70 
       
    71     try:
       
    72         cmd_popen = Popen(cmd, shell=True, stdout=PIPE)
       
    73         (cmd_stdout, cmd_stderr) = cmd_popen.communicate()
       
    74     except OSError, err:
       
    75         print "ERROR running [%s] : [%s]" % \
       
    76             (cmd, str(err))
       
    77         raise
       
    78     except ValueError, err:
       
    79         print "ERROR running [%s] : [%s]" % \
       
    80             (cmd, str(err))
       
    81         raise
       
    82 
       
    83     if cmd_popen.returncode != 0:
       
    84         errstr = "ERROR: command [%s] returned [%d] : [%s]" % \
       
    85             (cmd, cmd_popen.returncode, str(cmd_stderr))
       
    86         print errstr
       
    87         raise Exception, (errstr)
       
    88 
       
    89     if cmd_stderr is not None:
       
    90         print "WARNING: command [%s] produced stderr output: [%s]" % \
       
    91             (cmd, cmd_stderr)
       
    92 
       
    93     return cmd_stdout
       
    94 
       
    95 
       
    96 def do_transform(xsltfile, infile, outfile, mkdirs=False, overwrite=False):
       
    97     '''
       
    98         Create the output directory, if appropriate, and run the xsltproc
       
    99         command to transform infile to oufile.
       
   100 
       
   101         On success, returns True.
       
   102         On failure, returns False.
       
   103     '''
       
   104 
       
   105     # Normalize the paths so we can check if they are really the same file
       
   106     # (doesn't always work, eg for paths beginning with "..")
       
   107     infile = os.path.normpath(infile)
       
   108     outfile = os.path.normpath(outfile)
       
   109 
       
   110     if infile == outfile:
       
   111         print "ERROR: source [%s] and target [%s] are the same" % \
       
   112             (infile, outfile)
       
   113         return False
       
   114 
       
   115     outdir = os.path.dirname(outfile)
       
   116     if (len(outdir)) and (not os.path.isdir(outdir)):
       
   117         if os.path.exists(outdir):
       
   118             print "ERROR: target dir [%s] is not a directory" % \
       
   119                 outdir
       
   120             return False
       
   121 
       
   122         if not mkdirs:
       
   123             print "ERROR: target dir [%s] doesn't exist" % \
       
   124                 outdir
       
   125             return False
       
   126 
       
   127         try:
       
   128             os.makedirs(outdir)
       
   129         except OSError, err:
       
   130             print "ERROR: failed to make dir [%s] : [%s]" % \
       
   131                 (outdir, str(err))
       
   132             return False
       
   133 
       
   134     if (os.path.exists(outfile)) and (not overwrite):
       
   135         print "ERROR: target file [%s] already exists. Use -f." % \
       
   136             outfile
       
   137         return False
       
   138 
       
   139     # Construct command
       
   140     cmd = "%s -o %s %s %s" % (XSLT_PROC, outfile, xsltfile, infile)
       
   141 
       
   142     try:
       
   143         output = run_cmd(cmd)
       
   144     except:
       
   145         return False
       
   146 
       
   147     return True
       
   148 
       
   149 
       
   150 def do_main():
       
   151     '''
       
   152         Process command line options and call do_transform() for
       
   153         each file to be processed.
       
   154 
       
   155         Returns: nothing.
       
   156     '''
       
   157 
       
   158     sources = []
       
   159     target = None
       
   160     force_overwrite = False
       
   161     recursive = False
       
   162     target_exists = False
       
   163 
       
   164     # Check xsltproc is installed
       
   165     if not os.access(XSLT_PROC, os.X_OK):
       
   166         print "ERROR: Cannot find %s" % XSLT_PROC
       
   167         print "You may be able to install it with:"
       
   168         print "\tpfexec pkg install pkg:/library/libxslt"
       
   169         sys.exit(1)
       
   170 
       
   171     # Check xsl transform file is available in same dir this
       
   172     # script was run from
       
   173     xsltdir = os.path.dirname(sys.argv[0])
       
   174     xsltfile = "%s/%s" % (xsltdir, XSLT_FILE)
       
   175     if (not os.path.exists(xsltfile)):
       
   176         print "XSLT file [%s] is missing from directory [%s]" % \
       
   177             (XSLT_FILE, xsltdir)
       
   178         sys.exit(1)
       
   179 
       
   180     # Fetch and process command line params and options
       
   181     try:
       
   182         optlist, args = getopt.getopt(sys.argv[1:], "frh", ["help"])
       
   183     except getopt.GetoptError:
       
   184         usage()
       
   185 
       
   186     for opt, arg in optlist:
       
   187         if (opt == "-f"):
       
   188             force_overwrite = True
       
   189         if (opt == "-r"):
       
   190             recursive = True
       
   191         if (opt == "-h") or (opt == "--help"):
       
   192             usage(exitcode=0)
       
   193 
       
   194     # There must be at least 2 params.  The last param is the
       
   195     # target; all the other params are the source(s).
       
   196     if len(args) < 2:
       
   197         usage()
       
   198 
       
   199     sources = args[:len(args) - 1]
       
   200     target = args[len(args) - 1]
       
   201 
       
   202     # note whether the target existed before we started
       
   203     if os.path.exists(target):
       
   204         target_exists = True
       
   205 
       
   206     # Check for invalid paramaters (pt. 1)
       
   207     if ((len(sources) > 1) and
       
   208         (not os.path.isdir(target))):
       
   209         # if there are multiple sources (files or dirs), then
       
   210         # target must be an existing directory
       
   211         print "ERROR: [%s] is not a directory" % \
       
   212             target
       
   213         sys.exit(1)
       
   214 
       
   215     for source in sources:
       
   216         # normalize source path
       
   217         source = os.path.normpath(source)
       
   218 
       
   219         # Check for invalid paramaters (pt. 2)
       
   220         if source == "/":
       
   221             print "ERROR: '/' not allowed"
       
   222             sys.exit(1)
       
   223         if not os.path.exists(source):
       
   224             print "ERROR: no such file or directory: [%s]" % \
       
   225                 source
       
   226             sys.exit(1)
       
   227         if (os.path.isdir(source)) and (not recursive):
       
   228             print "ERROR: [%s] is a directory, but '-r' not specified" % \
       
   229                 source
       
   230             sys.exit(1)
       
   231         if (not os.path.isdir(source)) and (recursive):
       
   232             print "ERROR: [%s] is not a directory, but '-r' was specified" % \
       
   233                 source
       
   234             sys.exit(1)
       
   235         if ((os.path.isdir(source)) and
       
   236             (os.path.exists(target)) and
       
   237             (not os.path.isdir(target))):
       
   238             print "ERROR: [%s] is not a directory" % \
       
   239                 target
       
   240             sys.exit(1)
       
   241 
       
   242         if os.path.isdir(source):
       
   243             # recursively iterate through source dir, processing each file
       
   244             for dirpath, dirnames, filenames in os.walk(source):
       
   245                 # alter dirnames in-place to skip .*
       
   246                 dirnames[:] = [d for d in dirnames if not d.startswith('.')]
       
   247 
       
   248                 for name in filenames:
       
   249                     srcfile = os.path.join(dirpath, name)
       
   250 
       
   251                     partial_dstfile = os.path.join(dirpath, name)
       
   252 
       
   253                     # replicate how cp -r treats sub-dirs:
       
   254                     # 1. if source contains multiple sub-dirs, eg "a/b/c"
       
   255                     # then only create rightmost one, eg "c", under target
       
   256                     index = source.rfind("/", 1)
       
   257                     if index != -1:
       
   258                         # ensure partial_dstfile begins with source
       
   259                         if partial_dstfile.find(source) == 0:
       
   260                             partial_dstfile = partial_dstfile[index+1:]
       
   261 
       
   262                     # replicate how cp -r treats sub-dirs:
       
   263                     # 2. if target already existed then chop off leftmost
       
   264                     # dir of source from target
       
   265                     if not target_exists:
       
   266                         index = partial_dstfile.find("/", 1)
       
   267                         if index != -1:
       
   268                             partial_dstfile = partial_dstfile[index+1:]
       
   269 
       
   270                     dstfile = os.path.join(target, partial_dstfile)
       
   271 
       
   272                     if not do_transform(xsltfile, srcfile, dstfile,
       
   273                         mkdirs=True, overwrite=force_overwrite):
       
   274                         print "ERROR: Transform failed."
       
   275                         sys.exit(1)
       
   276         elif os.path.isdir(target):
       
   277             dstfile = os.path.join(target, os.path.basename(source))
       
   278 
       
   279             if not do_transform(xsltfile, source, dstfile,
       
   280                 mkdirs=False, overwrite=force_overwrite):
       
   281                 print "ERROR: Transform failed."
       
   282                 sys.exit(1)
       
   283         else:
       
   284             # this must be a simple "single infile" -> "single outfile" job
       
   285             if not do_transform(xsltfile, source, target,
       
   286                 mkdirs=False, overwrite=force_overwrite):
       
   287                 print "ERROR: Transform failed."
       
   288                 sys.exit(1)
       
   289 
       
   290 
       
   291 if __name__ == "__main__":
       
   292     do_main()
       
   293 
       
   294     sys.exit(0)