113540Sandrea.mondelli@ucf.edu#!/usr/bin/env python2.7
212893Sbrandon.potter@amd.com#
312893Sbrandon.potter@amd.com# Copyright (c) 2018 Advanced Micro Devices, Inc.
412893Sbrandon.potter@amd.com# All rights reserved.
512893Sbrandon.potter@amd.com#
612893Sbrandon.potter@amd.com# For use for simulation and test purposes only
712893Sbrandon.potter@amd.com#
812893Sbrandon.potter@amd.com# Redistribution and use in source and binary forms, with or without
912893Sbrandon.potter@amd.com# modification, are permitted provided that the following conditions are met:
1012893Sbrandon.potter@amd.com#
1112893Sbrandon.potter@amd.com# 1. Redistributions of source code must retain the above copyright notice,
1212893Sbrandon.potter@amd.com# this list of conditions and the following disclaimer.
1312893Sbrandon.potter@amd.com#
1412893Sbrandon.potter@amd.com# 2. Redistributions in binary form must reproduce the above copyright notice,
1512893Sbrandon.potter@amd.com# this list of conditions and the following disclaimer in the documentation
1612893Sbrandon.potter@amd.com# and/or other materials provided with the distribution.
1712893Sbrandon.potter@amd.com#
1812893Sbrandon.potter@amd.com# 3. Neither the name of the copyright holder nor the names of its contributors
1912893Sbrandon.potter@amd.com# may be used to endorse or promote products derived from this software
2012893Sbrandon.potter@amd.com# without specific prior written permission.
2112893Sbrandon.potter@amd.com#
2212893Sbrandon.potter@amd.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2312893Sbrandon.potter@amd.com# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2412893Sbrandon.potter@amd.com# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2512893Sbrandon.potter@amd.com# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2612893Sbrandon.potter@amd.com# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2712893Sbrandon.potter@amd.com# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2812893Sbrandon.potter@amd.com# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2912893Sbrandon.potter@amd.com# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3012893Sbrandon.potter@amd.com# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3112893Sbrandon.potter@amd.com# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3212893Sbrandon.potter@amd.com# POSSIBILITY OF SUCH DAMAGE.
3312893Sbrandon.potter@amd.com#
3412893Sbrandon.potter@amd.com# Author: Brandon Potter
3512893Sbrandon.potter@amd.com
3612893Sbrandon.potter@amd.com
3712893Sbrandon.potter@amd.comimport subprocess
3812893Sbrandon.potter@amd.comfrom collections import OrderedDict, defaultdict
3912893Sbrandon.potter@amd.com
4012893Sbrandon.potter@amd.comclass OrderedDefaultDict(OrderedDict, defaultdict):
4112893Sbrandon.potter@amd.com    def __init__(self, default_factory=None, *args, **kwargs):
4212893Sbrandon.potter@amd.com        super(OrderedDefaultDict, self).__init__(*args, **kwargs)
4312893Sbrandon.potter@amd.com        self.default_factory = default_factory
4412893Sbrandon.potter@amd.com
4512893Sbrandon.potter@amd.comdef diff_files(upstream, feature, paths=[]):
4612893Sbrandon.potter@amd.com    """Given two git branches and an optional parameter 'path', determine
4712893Sbrandon.potter@amd.com    which files differ between the two branches. Afterwards, organize the
4812893Sbrandon.potter@amd.com    files with a printer-friendly data structure.
4912893Sbrandon.potter@amd.com
5012893Sbrandon.potter@amd.com    Returns: Dictionary of directories with their corresponding files
5112893Sbrandon.potter@amd.com    """
5212893Sbrandon.potter@amd.com
5312893Sbrandon.potter@amd.com    raw =  subprocess.check_output(
5412893Sbrandon.potter@amd.com        [ "git", "diff", "--name-status", "%s..%s" % (upstream, feature),
5512893Sbrandon.potter@amd.com        "--" ] + paths
5612893Sbrandon.potter@amd.com    )
5712893Sbrandon.potter@amd.com
5812893Sbrandon.potter@amd.com    path = [line.split('\t')[1] for line in raw.splitlines()]
5912893Sbrandon.potter@amd.com
6012893Sbrandon.potter@amd.com    odd = OrderedDefaultDict(list)
6112893Sbrandon.potter@amd.com    for p in path:
6212893Sbrandon.potter@amd.com        direc = subprocess.check_output(["dirname", p]).strip() + "/"
6312893Sbrandon.potter@amd.com        filename = subprocess.check_output(["basename", p]).strip()
6412893Sbrandon.potter@amd.com        odd[direc].append("%s" % filename)
6512893Sbrandon.potter@amd.com
6612893Sbrandon.potter@amd.com    return odd
6712893Sbrandon.potter@amd.com
6812893Sbrandon.potter@amd.comdef cl_hash(upstream, feature, path):
6912893Sbrandon.potter@amd.com    """Given two git branches and full path, record the identifier hash
7012893Sbrandon.potter@amd.com    for changesets which diff between the upstream branch and feature branch.
7112893Sbrandon.potter@amd.com    The changesets are ordered from oldest to youngest changesets in the
7212893Sbrandon.potter@amd.com    list.
7312893Sbrandon.potter@amd.com
7412893Sbrandon.potter@amd.com    Returns: List of identifier hashes
7512893Sbrandon.potter@amd.com    """
7612893Sbrandon.potter@amd.com
7712893Sbrandon.potter@amd.com    raw = subprocess.check_output(
7812893Sbrandon.potter@amd.com        [ "git", "log", "--oneline", "%s..%s" % (upstream, feature),
7912893Sbrandon.potter@amd.com        "--", path ]
8012893Sbrandon.potter@amd.com    )
8112893Sbrandon.potter@amd.com
8212893Sbrandon.potter@amd.com    return [l.split()[0] for l in raw.splitlines()]
8312893Sbrandon.potter@amd.com
8412893Sbrandon.potter@amd.comdef _main():
8512893Sbrandon.potter@amd.com    import argparse
8612893Sbrandon.potter@amd.com    parser = argparse.ArgumentParser(
8712893Sbrandon.potter@amd.com        description="List all changes between an upstream branch and a " \
8812893Sbrandon.potter@amd.com                    "feature branch by filename(s) and changeset hash(es).")
8912893Sbrandon.potter@amd.com
9012893Sbrandon.potter@amd.com    parser.add_argument("--upstream", "-u", type=str, default="origin/master",
9112893Sbrandon.potter@amd.com                        help="Upstream branch for comparison. " \
9212893Sbrandon.potter@amd.com                        "Default: %(default)s")
9312893Sbrandon.potter@amd.com    parser.add_argument("--feature", "-f", type=str, default="HEAD",
9412893Sbrandon.potter@amd.com                        help="Feature branch for comparison. " \
9512893Sbrandon.potter@amd.com                        "Default: %(default)s")
9612893Sbrandon.potter@amd.com    parser.add_argument("paths", metavar="PATH", type=str, nargs="*",
9712893Sbrandon.potter@amd.com                        help="Paths to list changes for")
9812893Sbrandon.potter@amd.com
9912893Sbrandon.potter@amd.com    args = parser.parse_args()
10012893Sbrandon.potter@amd.com
10112893Sbrandon.potter@amd.com    odd = diff_files(args.upstream, args.feature, paths=args.paths)
10212893Sbrandon.potter@amd.com
10312893Sbrandon.potter@amd.com    for key, value in odd.iteritems():
10412893Sbrandon.potter@amd.com        print key
10512893Sbrandon.potter@amd.com        for entry in value:
10612893Sbrandon.potter@amd.com            print "    %s" % entry
10712893Sbrandon.potter@amd.com            path = key + entry
10812893Sbrandon.potter@amd.com            sha = cl_hash(args.upstream, args.feature, path)
10912893Sbrandon.potter@amd.com            for s in sha:
11012893Sbrandon.potter@amd.com                print "\t%s" % s
11112893Sbrandon.potter@amd.com        print
11212893Sbrandon.potter@amd.com
11312893Sbrandon.potter@amd.comif __name__ == "__main__":
11412893Sbrandon.potter@amd.com    _main()
115