1"""SCons.Tool.zip 2 3Tool-specific initialization for zip. 4 5There normally shouldn't be any need to import this module directly. 6It will usually be imported through the generic SCons.Tool.Tool() 7selection method. 8 9""" 10 11# MIT License 12# 13# Copyright The SCons Foundation 14# 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: 22# 23# The above copyright notice and this permission notice shall be included 24# in all copies or substantial portions of the Software. 25# 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. 33 34import os 35 36import SCons.Builder 37import SCons.Defaults 38import SCons.Node.FS 39import SCons.Util 40 41import time 42import zipfile 43 44 45zip_compression = zipfile.ZIP_DEFLATED 46 47 48def _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 58 59 60def zip_builder(target, source, env): 61 compression = env.get('ZIPCOMPRESSION', zipfile.ZIP_STORED) 62 zip_root = str(env.get('ZIPROOT', '')) 63 date_time = env.get('ZIP_OVERRIDE_TIMESTAMP') 64 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)) 75 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()) 83 84 85# Fix PR #3569 - If you don't specify ZIPCOM and ZIPCOMSTR when creating 86# env, then it will ignore ZIPCOMSTR set afterwards. 87zipAction = SCons.Action.Action(zip_builder, "$ZIPCOMSTR", 88 varlist=['ZIPCOMPRESSION', 'ZIPROOT', 'ZIP_OVERRIDE_TIMESTAMP']) 89 90ZipBuilder = 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) 95 96 97def generate(env): 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 104 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('') 111 112 113def exists(env): 114 return True 115 116# Local Variables: 117# tab-width:4 118# indent-tabs-mode:nil 119# End: 120# vim: set expandtab tabstop=4 shiftwidth=4: 121