Merge pull request #4655 from bdbaddog/fix_new_ninja_package
[scons.git] / SCons / Tool / zip.py
blob4c04afcebaaae2dedbd39058b7bd2314becc8a89
1 """SCons.Tool.zip
3 Tool-specific initialization for zip.
5 There normally shouldn't be any need to import this module directly.
6 It will usually be imported through the generic SCons.Tool.Tool()
7 selection method.
9 """
11 # MIT License
13 # Copyright The SCons Foundation
15 # Permission is hereby granted, free of charge, to any person obtaining
16 # a copy of this software and associated documentation files (the
17 # "Software"), to deal in the Software without restriction, including
18 # without limitation the rights to use, copy, modify, merge, publish,
19 # distribute, sublicense, and/or sell copies of the Software, and to
20 # permit persons to whom the Software is furnished to do so, subject to
21 # the following conditions:
23 # The above copyright notice and this permission notice shall be included
24 # in all copies or substantial portions of the Software.
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 import os
36 import SCons.Builder
37 import SCons.Defaults
38 import SCons.Node.FS
39 import SCons.Util
41 import time
42 import zipfile
45 zip_compression = zipfile.ZIP_DEFLATED
48 def _create_zipinfo_for_file(fname, arcname, date_time, compression):
49 st = os.stat(fname)
50 if not date_time:
51 mtime = time.localtime(st.st_mtime)
52 date_time = mtime[0:6]
53 zinfo = zipfile.ZipInfo(filename=arcname, date_time=date_time)
54 zinfo.external_attr = (st.st_mode & 0xFFFF) << 16 # Unix attributes
55 zinfo.compress_type = compression
56 zinfo.file_size = st.st_size
57 return zinfo
60 def zip_builder(target, source, env) -> None:
61 compression = env.get('ZIPCOMPRESSION', zipfile.ZIP_STORED)
62 zip_root = str(env.get('ZIPROOT', ''))
63 date_time = env.get('ZIP_OVERRIDE_TIMESTAMP')
65 files = []
66 for s in source:
67 if s.isdir():
68 for dirpath, dirnames, filenames in os.walk(str(s)):
69 for fname in filenames:
70 path = os.path.join(dirpath, fname)
71 if os.path.isfile(path):
72 files.append(path)
73 else:
74 files.append(str(s))
76 with zipfile.ZipFile(str(target[0]), 'w', compression) as zf:
77 for fname in files:
78 arcname = os.path.relpath(fname, zip_root)
79 # TODO: Switch to ZipInfo.from_file when 3.6 becomes the base python version
80 zinfo = _create_zipinfo_for_file(fname, arcname, date_time, compression)
81 with open(fname, "rb") as f:
82 zf.writestr(zinfo, f.read())
85 # Fix PR #3569 - If you don't specify ZIPCOM and ZIPCOMSTR when creating
86 # env, then it will ignore ZIPCOMSTR set afterwards.
87 zipAction = SCons.Action.Action(zip_builder, "$ZIPCOMSTR",
88 varlist=['ZIPCOMPRESSION', 'ZIPROOT', 'ZIP_OVERRIDE_TIMESTAMP'])
90 ZipBuilder = SCons.Builder.Builder(action=SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'),
91 source_factory=SCons.Node.FS.Entry,
92 source_scanner=SCons.Defaults.DirScanner,
93 suffix='$ZIPSUFFIX',
94 multi=1)
97 def generate(env) -> None:
98 """Add Builders and construction variables for zip to an Environment."""
99 try:
100 bld = env['BUILDERS']['Zip']
101 except KeyError:
102 bld = ZipBuilder
103 env['BUILDERS']['Zip'] = bld
105 env['ZIP'] = 'zip'
106 env['ZIPFLAGS'] = SCons.Util.CLVar('')
107 env['ZIPCOM'] = zipAction
108 env['ZIPCOMPRESSION'] = zip_compression
109 env['ZIPSUFFIX'] = '.zip'
110 env['ZIPROOT'] = SCons.Util.CLVar('')
113 def exists(env) -> bool:
114 return True
116 # Local Variables:
117 # tab-width:4
118 # indent-tabs-mode:nil
119 # End:
120 # vim: set expandtab tabstop=4 shiftwidth=4: