| #!/usr/bin/env python |
| # Copyright 2015 The Native Client Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Find which packages are effected by a given change. |
| |
| Accepts a list of changed files and outputs a list of effected |
| packages. Outputs 'all' if any shared/non-package-specific |
| file if changed.""" |
| |
| import argparse |
| import fnmatch |
| import os |
| import sys |
| |
| SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| NACLPORTS_ROOT = os.path.dirname(SCRIPT_DIR) |
| sys.path.append(os.path.join(NACLPORTS_ROOT, 'lib')) |
| |
| import webports |
| import webports.source_package |
| |
| |
| def main(args): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument('-v', '--verbose', action='store_true') |
| parser.add_argument('--deps', action='store_true', |
| help='include dependencies of effected packages.') |
| parser.add_argument('files', nargs='+', help='Changes files.') |
| options = parser.parse_args(args) |
| webports.set_verbose(options.verbose) |
| |
| if options.deps: |
| package_filter = sys.stdin.read().split() |
| else: |
| package_filter = None |
| |
| effected_packages = find_effected_packages(options.files, options.deps, |
| package_filter) |
| print '\n'.join(effected_packages) |
| return 0 |
| |
| # Normally when changins files outside of the 'ports' directory will |
| # trigger the rebuilding of all packages. However certainly files are |
| # known to not effect the building on packages and those are listed here. |
| IGNORE_FILES = [ |
| 'build_tools/find_effected_packages.py', |
| 'build_tools/partition*.txt', |
| 'AUTHORS', |
| '*/test_*.py', |
| 'docs/*.md', |
| '*.md', |
| ] |
| |
| |
| def find_effected_packages(files, include_deps, package_filter): |
| packages = [] |
| to_resolve = [] |
| |
| def add_package(package): |
| if package_filter and package.NAME not in package_filter: |
| webports.log_verbose('Filtered out package: %s' % package.NAME) |
| return |
| if package.NAME not in packages: |
| if include_deps: |
| for dep in package.transitive_dependencies(): |
| if dep.NAME not in packages: |
| packages.append(dep.NAME) |
| packages.append(package.NAME) |
| to_resolve.append(package) |
| |
| for filename in files: |
| parts = filename.split(os.path.sep) |
| if parts[0] != 'ports': |
| webports.log_verbose('effected file outside of ports tree: %s' % filename) |
| if any(fnmatch.fnmatch(filename, ignore) for ignore in IGNORE_FILES): |
| continue |
| return ['all'] |
| |
| package_name = parts[1] |
| pkg = webports.source_package.create_package(package_name) |
| add_package(pkg) |
| |
| while to_resolve: |
| pkg = to_resolve.pop() |
| for r in pkg.reverse_dependencies(): |
| add_package(r) |
| |
| if package_filter: |
| packages = [p for p in packages if p in package_filter] |
| return packages |
| |
| |
| if __name__ == '__main__': |
| try: |
| sys.exit(main(sys.argv[1:])) |
| except webports.Error as e: |
| sys.stderr.write('%s\n' % e) |
| sys.exit(-1) |