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/.
7 # When run directly, this script expects the following environment variables
9 # UPLOAD_PATH : path on that host to put the files in
11 # Files are simply copied to UPLOAD_PATH.
13 # All files to be uploaded should be passed as commandline arguments to this
14 # script. The script takes one other parameter, --base-path, which you can use
15 # to indicate that files should be uploaded including their paths relative
21 from optparse
import OptionParser
24 def OptionalEnvironmentVariable(v
):
25 """Return the value of the environment variable named v, or None
26 if it's unset (or empty)."""
27 if v
in os
.environ
and os
.environ
[v
] != "":
32 def FixupMsysPath(path
):
33 """MSYS helpfully translates absolute pathnames in environment variables
34 and commandline arguments into Windows native paths. This sucks if you're
35 trying to pass an absolute path on a remote server. This function attempts
36 to un-mangle such paths."""
37 if "OSTYPE" in os
.environ
and os
.environ
["OSTYPE"] == "msys":
38 # sort of awful, find out where our shell is (should be in msys2/usr/bin
39 # or msys/bin) and strip the first part of that path out of the other path
40 if "SHELL" in os
.environ
:
41 sh
= os
.environ
["SHELL"]
42 msys
= sh
[: sh
.find("/bin")]
43 if path
.startswith(msys
):
44 path
= path
[len(msys
) :]
48 def GetBaseRelativePath(path
, local_file
, base_path
):
49 """Given a remote path to upload to, a full path to a local file, and an
50 optional full path that is a base path of the local file, construct the
51 full remote path to place the file in. If base_path is not None, include
52 the relative path from base_path to file."""
53 if base_path
is None or not local_file
.startswith(base_path
):
56 dir = os
.path
.dirname(local_file
)
57 # strip base_path + extra slash and make it unixy
58 dir = dir[len(base_path
) + 1 :].replace("\\", "/")
62 def CopyFilesLocally(path
, files
, verbose
=False, base_path
=None):
63 """Copy each file in the list of files to `path`. The `base_path` argument is treated
64 as it is by UploadFiles."""
65 if not path
.endswith("/"):
67 if base_path
is not None:
68 base_path
= os
.path
.abspath(base_path
)
70 file = os
.path
.abspath(file)
71 if not os
.path
.isfile(file):
72 raise IOError("File not found: %s" % file)
73 # first ensure that path exists remotely
74 target_path
= GetBaseRelativePath(path
, file, base_path
)
75 if not os
.path
.exists(target_path
):
76 os
.makedirs(target_path
)
78 print("Copying " + file + " to " + target_path
)
79 shutil
.copy(file, target_path
)
82 if __name__
== "__main__":
83 path
= OptionalEnvironmentVariable("UPLOAD_PATH")
85 if sys
.platform
== "win32":
87 path
= FixupMsysPath(path
)
89 parser
= OptionParser(usage
="usage: %prog [options] <files>")
94 help="Preserve file paths relative to this path when uploading. "
95 "If unset, all files will be uploaded directly to UPLOAD_PATH.",
97 (options
, args
) = parser
.parse_args()
99 print("You must specify at least one file to upload")
103 CopyFilesLocally(path
, args
, base_path
=options
.base_path
, verbose
=True)
104 except IOError as strerror
: