--- /dev/null
+#!/usr/bin/env python2
+#
+# Copyright (c) 2018 Advanced Micro Devices, Inc.
+# All rights reserved.
+#
+# For use for simulation and test purposes only
+#
+# 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.iteritems():
+ 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()