Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # -*- coding: utf-8 -*- |
| 3 | # Copyright 2021 The Chromium OS 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 | """ This script cleans up the vendor directory. |
| 7 | """ |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 8 | import hashlib |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 9 | import json |
| 10 | import os |
| 11 | import pathlib |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 12 | import subprocess |
| 13 | |
| 14 | |
| 15 | def _rerun_checksums(package_path): |
| 16 | """Re-run checksums for given package. |
| 17 | |
| 18 | Writes resulting checksums to $package_path/.cargo-checksum.json. |
| 19 | """ |
| 20 | hashes = {} |
| 21 | checksum_path = os.path.join(package_path, '.cargo-checksum.json') |
| 22 | if not pathlib.Path(checksum_path).is_file(): |
| 23 | return False |
| 24 | |
| 25 | with open(checksum_path, 'r') as fread: |
| 26 | contents = json.load(fread) |
| 27 | |
| 28 | for root, _, files in os.walk(package_path, topdown=True): |
| 29 | for f in files: |
| 30 | # Don't checksum an existing checksum file |
| 31 | if f == ".cargo-checksum.json": |
| 32 | continue |
| 33 | |
| 34 | file_path = os.path.join(root, f) |
| 35 | with open(file_path, 'rb') as frb: |
| 36 | m = hashlib.sha256() |
| 37 | m.update(frb.read()) |
| 38 | d = m.hexdigest() |
| 39 | |
| 40 | # Key is relative to the package path so strip from beginning |
| 41 | key = os.path.relpath(file_path, package_path) |
| 42 | hashes[key] = d |
| 43 | |
| 44 | if hashes: |
| 45 | print("{} regenerated {} hashes".format(package_path, len(hashes.keys()))) |
| 46 | contents['files'] = hashes |
| 47 | |
| 48 | with open(checksum_path, 'w') as fwrite: |
| 49 | json.dump(contents, fwrite) |
| 50 | |
| 51 | return True |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 52 | |
| 53 | |
| 54 | def _remove_OWNERS_checksum(root): |
| 55 | """ Delete all OWNERS files from the checksum file. |
| 56 | |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 57 | Args: |
| 58 | root: Root directory for the vendored crate. |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 59 | |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 60 | Returns: |
| 61 | True if OWNERS was found and cleaned up. Otherwise False. |
| 62 | """ |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 63 | checksum_path = os.path.join(root, '.cargo-checksum.json') |
| 64 | if not pathlib.Path(checksum_path).is_file(): |
| 65 | return False |
| 66 | |
| 67 | with open(checksum_path, 'r') as fread: |
| 68 | contents = json.load(fread) |
| 69 | |
| 70 | del_keys = [] |
| 71 | for cfile in contents['files']: |
| 72 | if 'OWNERS' in cfile: |
| 73 | del_keys.append(cfile) |
| 74 | |
| 75 | for key in del_keys: |
| 76 | del contents['files'][key] |
| 77 | |
| 78 | if del_keys: |
| 79 | print('{} deleted: {}'.format(root, del_keys)) |
| 80 | with open(checksum_path, 'w') as fwrite: |
| 81 | json.dump(contents, fwrite) |
| 82 | |
| 83 | return bool(del_keys) |
| 84 | |
| 85 | |
| 86 | def cleanup_owners(vendor_path): |
| 87 | """ Remove owners checksums from the vendor directory. |
| 88 | |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 89 | We currently do not check in the OWNERS files from vendored crates because |
| 90 | they interfere with the find-owners functionality in gerrit. This cleanup |
| 91 | simply finds all instances of "OWNERS" in the checksum files within and |
| 92 | removes them. |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 93 | |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 94 | Args: |
| 95 | vendor_path: Absolute path to vendor directory. |
| 96 | """ |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 97 | deps_cleaned = [] |
| 98 | for root, dirs, _ in os.walk(vendor_path): |
| 99 | for d in dirs: |
| 100 | removed = _remove_OWNERS_checksum(os.path.join(root, d)) |
| 101 | if removed: |
| 102 | deps_cleaned.append(d) |
| 103 | |
| 104 | if deps_cleaned: |
| 105 | print('Cleanup owners:\n {}'.format("\n".join(deps_cleaned))) |
| 106 | |
| 107 | |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 108 | def apply_single_patch(patch, workdir): |
| 109 | """Apply a single patch and return whether it was successful. |
| 110 | |
| 111 | Returns: |
| 112 | True if successful. False otherwise. |
| 113 | """ |
| 114 | print("-- Applying {}".format(patch)) |
| 115 | proc = subprocess.run(["patch", "-p1", "-i", patch], cwd=workdir) |
| 116 | return proc.returncode == 0 |
| 117 | |
| 118 | |
| 119 | def apply_patches(patches_path, vendor_path): |
| 120 | """Finds patches and applies them to sub-folders in the vendored crates. |
| 121 | |
| 122 | Args: |
| 123 | patches_path: Path to folder with patches. Expect all patches to be one |
| 124 | level down (matching the crate name). |
| 125 | vendor_path: Root path to vendored crates directory. |
| 126 | """ |
| 127 | checksums_for = {} |
| 128 | |
| 129 | # Don't bother running if patches directory is empty |
| 130 | if not pathlib.Path(patches_path).is_dir(): |
| 131 | return |
| 132 | |
| 133 | # Look for all patches and apply them |
| 134 | for d in os.listdir(patches_path): |
| 135 | dir_path = os.path.join(patches_path, d) |
| 136 | |
| 137 | # We don't process patches in root dir |
| 138 | if not os.path.isdir(dir_path): |
| 139 | continue |
| 140 | |
| 141 | for patch in os.listdir(os.path.join(dir_path)): |
| 142 | file_path = os.path.join(dir_path, patch) |
| 143 | |
| 144 | # Skip if not a patch file |
| 145 | if not os.path.isfile(file_path) or not patch.endswith(".patch"): |
| 146 | continue |
| 147 | |
| 148 | # If there are any patches, queue checksums for that folder. |
| 149 | checksums_for[d] = True |
| 150 | |
| 151 | # Apply the patch. Exit from patch loop if patching failed. |
| 152 | success = apply_single_patch(file_path, |
| 153 | os.path.join(vendor_path, d)) |
| 154 | if not success: |
| 155 | print("Failed to apply patch: {}".format(patch)) |
| 156 | break |
| 157 | |
| 158 | |
| 159 | # Re-run checksums for all modified packages since we applied patches. |
| 160 | for key in checksums_for.keys(): |
| 161 | _rerun_checksums(os.path.join(vendor_path, key)) |
| 162 | |
| 163 | |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 164 | def main(): |
| 165 | current_path = pathlib.Path(__file__).parent.absolute() |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 166 | patches = os.path.join(current_path, "patches") |
| 167 | vendor = os.path.join(current_path, "vendor") |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 168 | |
Abhishek Pandit-Subedi | 5065a0f | 2021-06-13 20:38:55 +0000 | [diff] [blame^] | 169 | # Order matters here: |
| 170 | # - Apply patches (also re-calculates checksums) |
| 171 | # - Cleanup any owners files (otherwise, git check-in or checksums are |
| 172 | # unhappy) |
| 173 | apply_patches(patches, vendor) |
| 174 | cleanup_owners(vendor) |
Abhishek Pandit-Subedi | b75bd56 | 2021-02-25 15:32:22 -0800 | [diff] [blame] | 175 | |
| 176 | |
| 177 | if __name__ == '__main__': |
| 178 | main() |