#!/usr/bin/python
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# When run directly, this script expects the following environment variables
# to be set:
# UPLOAD_PATH : path on that host to put the files in
#
# Files are simply copied to UPLOAD_PATH.
#
# All files to be uploaded should be passed as commandline arguments to this
# script. The script takes one other parameter, --base-path, which you can use
# to indicate that files should be uploaded including their paths relative
# to the base path.
import os
import shutil
import sys
from optparse
import OptionParser
def OptionalEnvironmentVariable(v):
"""Return the value of the environment variable named v, or None
if it
's unset (or empty)."""
if v
in os.environ
and os.environ[v] !=
"":
return os.environ[v]
return None
def FixupMsysPath(path):
"""MSYS helpfully translates absolute pathnames in environment variables
and commandline arguments into Windows native paths. This sucks
if you
're
trying to
pass an absolute path on a remote server. This function attempts
to un-mangle such paths.
"""
if "OSTYPE" in os.environ
and os.environ[
"OSTYPE"] ==
"msys":
# sort of awful, find out where our shell is (should be in msys2/usr/bin
# or msys/bin) and strip the first part of that path out of the other path
if "SHELL" in os.environ:
sh = os.environ[
"SHELL"]
msys = sh[: sh.find(
"/bin")]
if path.startswith(msys):
path = path[len(msys) :]
return path
def GetBaseRelativePath(path, local_file, base_path):
"""Given a remote path to upload to, a full path to a local file, and an
optional full path that
is a base path of the local file, construct the
full remote path to place the file
in.
If base_path
is not None, include
the relative path
from base_path to file.
"""
if base_path
is None or not local_file.startswith(base_path):
return path
dir = os.path.dirname(local_file)
# strip base_path + extra slash and make it unixy
dir = dir[len(base_path) + 1 :].replace(
"\\",
"/")
return path + dir
def CopyFilesLocally(path, files, verbose=
False, base_path=
None):
"""Copy each file in the list of files to `path`. The `base_path` argument is treated
as it
is by UploadFiles.
"""
if not path.endswith(
"/"):
path +=
"/"
if base_path
is not None:
base_path = os.path.abspath(base_path)
for file
in files:
file = os.path.abspath(file)
if not os.path.isfile(file):
raise IOError(
"File not found: %s" % file)
# first ensure that path exists remotely
target_path = GetBaseRelativePath(path, file, base_path)
if not os.path.exists(target_path):
os.makedirs(target_path)
if verbose:
print(
"Copying " + file +
" to " + target_path)
shutil.copy(file, target_path)
if __name__ ==
"__main__":
path = OptionalEnvironmentVariable(
"UPLOAD_PATH")
if sys.platform ==
"win32":
if path
is not None:
path = FixupMsysPath(path)
parser = OptionParser(usage=
"usage: %prog [options] ")
parser.add_option(
"-b",
"--base-path",
action=
"store",
help=
"Preserve file paths relative to this path when uploading. "
"If unset, all files will be uploaded directly to UPLOAD_PATH.",
)
(options, args) = parser.parse_args()
if len(args) < 1:
print(
"You must specify at least one file to upload")
sys.exit(1)
try:
CopyFilesLocally(path, args, base_path=options.base_path, verbose=
True)
except IOError
as strerror:
print(strerror)
sys.exit(1)