Chris Bracken | 9985bc0 | 2021-07-31 11:09:12 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 3 | # Copyright 2013 The Flutter Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
| 7 | import argparse |
godofredoc | 988e8fc | 2022-03-02 08:26:11 -0800 | [diff] [blame] | 8 | import json |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 9 | import os |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 10 | import stat |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 11 | import sys |
godofredoc | 8ae76c3 | 2022-08-22 08:16:46 -0700 | [diff] [blame] | 12 | import zipfile |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 13 | |
| 14 | |
| 15 | def _zip_dir(path, zip_file, prefix): |
| 16 | path = path.rstrip('/\\') |
godofredoc | 835ba6b | 2022-08-19 22:30:19 -0700 | [diff] [blame] | 17 | for root, directories, files in os.walk(path): |
| 18 | for directory in directories: |
| 19 | if os.path.islink(os.path.join(root, directory)): |
| 20 | add_symlink( |
| 21 | zip_file, |
godofredoc | 8ae76c3 | 2022-08-22 08:16:46 -0700 | [diff] [blame] | 22 | os.path.join(root, directory), |
godofredoc | 835ba6b | 2022-08-19 22:30:19 -0700 | [diff] [blame] | 23 | os.path.join(root.replace(path, prefix), directory), |
| 24 | ) |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 25 | for file in files: |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 26 | if os.path.islink(os.path.join(root, file)): |
| 27 | add_symlink( |
Zachary Anderson | 9e0316d | 2022-06-03 13:00:14 -0700 | [diff] [blame] | 28 | zip_file, os.path.join(root, file), |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 29 | os.path.join(root.replace(path, prefix), file) |
| 30 | ) |
| 31 | continue |
Zachary Anderson | 9e0316d | 2022-06-03 13:00:14 -0700 | [diff] [blame] | 32 | zip_file.write( |
| 33 | os.path.join(root, file), |
| 34 | os.path.join(root.replace(path, prefix), file) |
| 35 | ) |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 36 | |
| 37 | |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 38 | def add_symlink(zip_file, source, target): |
| 39 | """Adds a symlink to a zip file. |
| 40 | |
| 41 | Args: |
| 42 | zip_file: The ZipFile obj where the symlink will be added. |
| 43 | source: The full path to the symlink. |
| 44 | target: The target path for the symlink within the zip file. |
| 45 | """ |
Zachary Anderson | 9e0316d | 2022-06-03 13:00:14 -0700 | [diff] [blame] | 46 | zip_info = zipfile.ZipInfo(target) |
| 47 | zip_info.create_system = 3 # Unix like system |
| 48 | unix_st_mode = ( |
| 49 | stat.S_IFLNK | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP |
| 50 | | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH |
| 51 | ) |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 52 | zip_info.external_attr = unix_st_mode << 16 |
godofredoc | 8ae76c3 | 2022-08-22 08:16:46 -0700 | [diff] [blame] | 53 | zip_file.writestr(zip_info, os.readlink(source)) |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 54 | |
| 55 | |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 56 | def main(args): |
| 57 | zip_file = zipfile.ZipFile(args.output, 'w', zipfile.ZIP_DEFLATED) |
godofredoc | 988e8fc | 2022-03-02 08:26:11 -0800 | [diff] [blame] | 58 | if args.source_file: |
| 59 | with open(args.source_file) as source_file: |
| 60 | file_dict_list = json.load(source_file) |
| 61 | for file_dict in file_dict_list: |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 62 | if os.path.islink(file_dict['source']): |
| 63 | add_symlink(zip_file, file_dict['source'], file_dict['destination']) |
| 64 | continue |
godofredoc | 988e8fc | 2022-03-02 08:26:11 -0800 | [diff] [blame] | 65 | if os.path.isdir(file_dict['source']): |
| 66 | _zip_dir(file_dict['source'], zip_file, file_dict['destination']) |
| 67 | else: |
| 68 | zip_file.write(file_dict['source'], file_dict['destination']) |
| 69 | else: |
| 70 | for path, archive_name in args.input_pairs: |
godofredoc | 59c9daf | 2022-03-25 23:30:02 -0700 | [diff] [blame] | 71 | if os.path.islink(path): |
| 72 | add_symlink(zip_file, path, archive_name) |
| 73 | continue |
godofredoc | 988e8fc | 2022-03-02 08:26:11 -0800 | [diff] [blame] | 74 | if os.path.isdir(path): |
| 75 | _zip_dir(path, zip_file, archive_name) |
| 76 | else: |
| 77 | zip_file.write(path, archive_name) |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 78 | zip_file.close() |
| 79 | |
| 80 | |
| 81 | if __name__ == '__main__': |
Zachary Anderson | 9e0316d | 2022-06-03 13:00:14 -0700 | [diff] [blame] | 82 | parser = argparse.ArgumentParser(description='This script creates zip files.') |
| 83 | parser.add_argument( |
| 84 | '-o', |
| 85 | dest='output', |
| 86 | action='store', |
| 87 | help='The name of the output zip file.' |
| 88 | ) |
| 89 | parser.add_argument( |
| 90 | '-i', |
| 91 | dest='input_pairs', |
| 92 | nargs=2, |
| 93 | action='append', |
| 94 | help='The input file and its destination location in the zip archive.' |
| 95 | ) |
| 96 | parser.add_argument( |
| 97 | '-f', |
| 98 | dest='source_file', |
| 99 | action='store', |
| 100 | help='The path to the file list to zip.' |
| 101 | ) |
Dan Field | a05803a | 2019-10-10 06:56:43 -0700 | [diff] [blame] | 102 | sys.exit(main(parser.parse_args())) |