build/upload.py

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     1 #!/usr/bin/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
     5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6 #
     7 # When run directly, this script expects the following environment variables
     8 # to be set:
     9 # UPLOAD_HOST    : host to upload files to
    10 # UPLOAD_USER    : username on that host
    11 # UPLOAD_PATH    : path on that host to put the files in
    12 #
    13 # And will use the following optional environment variables if set:
    14 # UPLOAD_SSH_KEY : path to a ssh private key to use
    15 # UPLOAD_PORT    : port to use for ssh
    16 # POST_UPLOAD_CMD: a commandline to run on the remote host after uploading.
    17 #                  UPLOAD_PATH and the full paths of all files uploaded will
    18 #                  be appended to the commandline.
    19 #
    20 # All files to be uploaded should be passed as commandline arguments to this
    21 # script. The script takes one other parameter, --base-path, which you can use
    22 # to indicate that files should be uploaded including their paths relative
    23 # to the base path.
    25 import sys, os
    26 from optparse import OptionParser
    27 from subprocess import PIPE, Popen, check_call
    29 def RequireEnvironmentVariable(v):
    30     """Return the value of the environment variable named v, or print
    31     an error and exit if it's unset (or empty)."""
    32     if not v in os.environ or os.environ[v] == "":
    33         print "Error: required environment variable %s not set" % v
    34         sys.exit(1)
    35     return os.environ[v]
    37 def OptionalEnvironmentVariable(v):
    38     """Return the value of the environment variable named v, or None
    39     if it's unset (or empty)."""
    40     if v in os.environ and os.environ[v] != "":
    41         return os.environ[v]
    42     return None
    44 def FixupMsysPath(path):
    45     """MSYS helpfully translates absolute pathnames in environment variables
    46     and commandline arguments into Windows native paths. This sucks if you're
    47     trying to pass an absolute path on a remote server. This function attempts
    48     to un-mangle such paths."""
    49     if 'OSTYPE' in os.environ and os.environ['OSTYPE'] == 'msys':
    50         # sort of awful, find out where our shell is (should be in msys/bin)
    51         # and strip the first part of that path out of the other path
    52         if 'SHELL' in os.environ:
    53             sh = os.environ['SHELL']
    54             msys = sh[:sh.find('/bin')]
    55             if path.startswith(msys):
    56                 path = path[len(msys):]
    57     return path
    59 def WindowsPathToMsysPath(path):
    60     """Translate a Windows pathname to an MSYS pathname.
    61     Necessary because we call out to ssh/scp, which are MSYS binaries
    62     and expect MSYS paths."""
    63     if sys.platform != 'win32':
    64         return path
    65     (drive, path) = os.path.splitdrive(os.path.abspath(path))
    66     return "/" + drive[0] + path.replace('\\','/')
    68 def AppendOptionalArgsToSSHCommandline(cmdline, port, ssh_key):
    69     """Given optional port and ssh key values, append valid OpenSSH
    70     commandline arguments to the list cmdline if the values are not None."""
    71     if port is not None:
    72         cmdline.append("-P%d" % port)
    73     if ssh_key is not None:
    74         # Don't interpret ~ paths - ssh can handle that on its own
    75         if not ssh_key.startswith('~'):
    76             ssh_key = WindowsPathToMsysPath(ssh_key)
    77         cmdline.extend(["-o", "IdentityFile=%s" % ssh_key])
    79 def DoSSHCommand(command, user, host, port=None, ssh_key=None):
    80     """Execute command on user@host using ssh. Optionally use
    81     port and ssh_key, if provided."""
    82     cmdline = ["ssh"]
    83     AppendOptionalArgsToSSHCommandline(cmdline, port, ssh_key)
    84     cmdline.extend(["%s@%s" % (user, host), command])
    85     cmd = Popen(cmdline, stdout=PIPE)
    86     retcode = cmd.wait()
    87     if retcode != 0:
    88         raise Exception("Command %s returned non-zero exit code: %i" % \
    89           (cmdline, retcode))
    90     return cmd.stdout.read().strip()
    92 def DoSCPFile(file, remote_path, user, host, port=None, ssh_key=None):
    93     """Upload file to user@host:remote_path using scp. Optionally use
    94     port and ssh_key, if provided."""
    95     cmdline = ["scp"]
    96     AppendOptionalArgsToSSHCommandline(cmdline, port, ssh_key)
    97     cmdline.extend([WindowsPathToMsysPath(file),
    98                     "%s@%s:%s" % (user, host, remote_path)])
    99     check_call(cmdline)
   101 def GetRemotePath(path, local_file, base_path):
   102     """Given a remote path to upload to, a full path to a local file, and an
   103     optional full path that is a base path of the local file, construct the
   104     full remote path to place the file in. If base_path is not None, include
   105     the relative path from base_path to file."""
   106     if base_path is None or not local_file.startswith(base_path):
   107         return path
   108     dir = os.path.dirname(local_file)
   109     # strip base_path + extra slash and make it unixy
   110     dir = dir[len(base_path)+1:].replace('\\','/')
   111     return path + dir
   113 def UploadFiles(user, host, path, files, verbose=False, port=None, ssh_key=None, base_path=None, upload_to_temp_dir=False, post_upload_command=None):
   114     """Upload each file in the list files to user@host:path. Optionally pass
   115     port and ssh_key to the ssh commands. If base_path is not None, upload
   116     files including their path relative to base_path. If upload_to_temp_dir is
   117     True files will be uploaded to a temporary directory on the remote server.
   118     Generally, you should have a post upload command specified in these cases
   119     that can move them around to their correct location(s).
   120     If post_upload_command is not None, execute that command on the remote host
   121     after uploading all files, passing it the upload path, and the full paths to
   122     all files uploaded.
   123     If verbose is True, print status updates while working."""
   124     if upload_to_temp_dir:
   125         path = DoSSHCommand("mktemp -d", user, host, port=port, ssh_key=ssh_key)
   126     if not path.endswith("/"):
   127         path += "/"
   128     if base_path is not None:
   129         base_path = os.path.abspath(base_path)
   130     remote_files = []
   131     try:
   132         for file in files:
   133             file = os.path.abspath(file)
   134             if not os.path.isfile(file):
   135                 raise IOError("File not found: %s" % file)
   136             # first ensure that path exists remotely
   137             remote_path = GetRemotePath(path, file, base_path)
   138             DoSSHCommand("mkdir -p " + remote_path, user, host, port=port, ssh_key=ssh_key)
   139             if verbose:
   140                 print "Uploading " + file
   141             DoSCPFile(file, remote_path, user, host, port=port, ssh_key=ssh_key)
   142             remote_files.append(remote_path + '/' + os.path.basename(file))
   143         if post_upload_command is not None:
   144             if verbose:
   145                 print "Running post-upload command: " + post_upload_command
   146             file_list = '"' + '" "'.join(remote_files) + '"'
   147             DoSSHCommand('%s "%s" %s' % (post_upload_command, path, file_list), user, host, port=port, ssh_key=ssh_key)
   148     finally:
   149         if upload_to_temp_dir:
   150             DoSSHCommand("rm -rf %s" % path, user, host, port=port,
   151                          ssh_key=ssh_key)
   152     if verbose:
   153         print "Upload complete"
   155 if __name__ == '__main__':
   156     host = RequireEnvironmentVariable('UPLOAD_HOST')
   157     user = RequireEnvironmentVariable('UPLOAD_USER')
   158     path = OptionalEnvironmentVariable('UPLOAD_PATH')
   159     upload_to_temp_dir = OptionalEnvironmentVariable('UPLOAD_TO_TEMP')
   160     port = OptionalEnvironmentVariable('UPLOAD_PORT')
   161     if port is not None:
   162         port = int(port)
   163     key = OptionalEnvironmentVariable('UPLOAD_SSH_KEY')
   164     post_upload_command = OptionalEnvironmentVariable('POST_UPLOAD_CMD')
   165     if (not path and not upload_to_temp_dir) or (path and upload_to_temp_dir):
   166         print "One (and only one of UPLOAD_PATH or UPLOAD_TO_TEMP must be " + \
   167               "defined."
   168         sys.exit(1)
   169     if sys.platform == 'win32':
   170         if path is not None:
   171             path = FixupMsysPath(path)
   172         if post_upload_command is not None:
   173             post_upload_command = FixupMsysPath(post_upload_command)
   175     parser = OptionParser(usage="usage: %prog [options] <files>")
   176     parser.add_option("-b", "--base-path",
   177                       action="store", dest="base_path",
   178                       help="Preserve file paths relative to this path when uploading. If unset, all files will be uploaded directly to UPLOAD_PATH.")
   179     (options, args) = parser.parse_args()
   180     if len(args) < 1:
   181         print "You must specify at least one file to upload"
   182         sys.exit(1)
   183     try:
   184         UploadFiles(user, host, path, args, base_path=options.base_path,
   185                     port=port, ssh_key=key, upload_to_temp_dir=upload_to_temp_dir,
   186                     post_upload_command=post_upload_command,
   187                     verbose=True)
   188     except IOError, (strerror):
   189         print strerror
   190         sys.exit(1)
   191     except Exception, (err):
   192         print err
   193         sys.exit(2)

mercurial