| #!/usr/bin/env python3 |
| # |
| # Copyright (c) 2018 Advanced Micro Devices, Inc. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # 1. Redistributions of source code must retain the above copyright notice, |
| # this list of conditions and the following disclaimer. |
| # |
| # 2. Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # |
| # 3. Neither the name of the copyright holder nor the names of its contributors |
| # may be used to endorse or promote products derived from this software |
| # without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| # POSSIBILITY OF SUCH DAMAGE. |
| # |
| # Author: Brandon Potter |
| |
| |
| import subprocess |
| from collections import OrderedDict, defaultdict |
| |
| |
| class OrderedDefaultDict(OrderedDict, defaultdict): |
| def __init__(self, default_factory=None, *args, **kwargs): |
| super(OrderedDefaultDict, self).__init__(*args, **kwargs) |
| self.default_factory = default_factory |
| |
| |
| def diff_files(upstream, feature, paths=[]): |
| """Given two git branches and an optional parameter 'path', determine |
| which files differ between the two branches. Afterwards, organize the |
| files with a printer-friendly data structure. |
| |
| Returns: Dictionary of directories with their corresponding files |
| """ |
| |
| raw = subprocess.check_output( |
| ["git", "diff", "--name-status", "%s..%s" % (upstream, feature), "--"] |
| + paths |
| ) |
| |
| path = [line.split("\t")[1] for line in raw.splitlines()] |
| |
| odd = OrderedDefaultDict(list) |
| for p in path: |
| direc = subprocess.check_output(["dirname", p]).strip() + "/" |
| filename = subprocess.check_output(["basename", p]).strip() |
| odd[direc].append("%s" % filename) |
| |
| return odd |
| |
| |
| def cl_hash(upstream, feature, path): |
| """Given two git branches and full path, record the identifier hash |
| for changesets which diff between the upstream branch and feature branch. |
| The changesets are ordered from oldest to youngest changesets in the |
| list. |
| |
| Returns: List of identifier hashes |
| """ |
| |
| raw = subprocess.check_output( |
| ["git", "log", "--oneline", "%s..%s" % (upstream, feature), "--", path] |
| ) |
| |
| return [l.split()[0] for l in raw.splitlines()] |
| |
| |
| def _main(): |
| import argparse |
| |
| parser = argparse.ArgumentParser( |
| description="List all changes between an upstream branch and a " |
| "feature branch by filename(s) and changeset hash(es)." |
| ) |
| |
| parser.add_argument( |
| "--upstream", |
| "-u", |
| type=str, |
| default="origin/master", |
| help="Upstream branch for comparison. " "Default: %(default)s", |
| ) |
| parser.add_argument( |
| "--feature", |
| "-f", |
| type=str, |
| default="HEAD", |
| help="Feature branch for comparison. " "Default: %(default)s", |
| ) |
| parser.add_argument( |
| "paths", |
| metavar="PATH", |
| type=str, |
| nargs="*", |
| help="Paths to list changes for", |
| ) |
| |
| args = parser.parse_args() |
| |
| odd = diff_files(args.upstream, args.feature, paths=args.paths) |
| |
| for key, value in odd.items(): |
| print(key) |
| for entry in value: |
| print(" %s" % entry) |
| path = key + entry |
| sha = cl_hash(args.upstream, args.feature, path) |
| for s in sha: |
| print("\t%s" % s) |
| print() |
| |
| |
| if __name__ == "__main__": |
| _main() |