Blame src/hwloc/contrib/update-my-copyright.pl

Packit Service c5cf8c
#!/usr/bin/env perl
Packit Service c5cf8c
#
Packit Service c5cf8c
# Copyright © 2010-2014 Cisco Systems, Inc.  All rights reserved.
Packit Service c5cf8c
# Copyright © 2011-2018 Inria.  All rights reserved.
Packit Service c5cf8c
# $COPYRIGHT$
Packit Service c5cf8c
#
Packit Service c5cf8c
Packit Service c5cf8c
# Short version:
Packit Service c5cf8c
#
Packit Service c5cf8c
# This script automates the tedious task of updating copyright notices
Packit Service c5cf8c
# in the tops of hwloc source files before committing back to
Packit Service c5cf8c
# the respository.  Set the environment variable
Packit Service c5cf8c
# HWLOC_COPYRIGHT_SEARCH_NAME to a short (case-insensitive) name that
Packit Service c5cf8c
# indicates your copyright line (e.g., "cisco"), and set the env
Packit Service c5cf8c
# variable HWLOC_COPYRIGHT_FORMAL_NAME with your organization's formal
Packit Service c5cf8c
# name and copyright statement (e.g., "Cisco Systems, Inc.  All rights
Packit Service c5cf8c
# reserved.") before running the script.
Packit Service c5cf8c
Packit Service c5cf8c
# More details:
Packit Service c5cf8c
#
Packit Service c5cf8c
# This is a simple script to traverse the tree looking for added and
Packit Service c5cf8c
# changed files (via "git status").  Note that the search starts in
Packit Service c5cf8c
# the current directory -- not the top-level directory.
Packit Service c5cf8c
#
Packit Service c5cf8c
# All added and changed files are examined.  If the special "See
Packit Service c5cf8c
# COPYING in top-level directory" token is found, then lines above
Packit Service c5cf8c
# that token are examined to find the "search" copyright name.
Packit Service c5cf8c
#
Packit Service c5cf8c
# - If the search name is found, that line is examined to see if the
Packit Service c5cf8c
#   current year is in the copyright year range.  If it is not, the line
Packit Service c5cf8c
#   is modified to include the current year.
Packit Service c5cf8c
# - If the search name is not found, a new line is created in the
Packit Service c5cf8c
#   copyright block of the file using the formal name and the current
Packit Service c5cf8c
#   year.
Packit Service c5cf8c
#
Packit Service c5cf8c
# NOTE: this script currently doesn't handle multi-line copyright
Packit Service c5cf8c
# statements, such as:
Packit Service c5cf8c
#
Packit Service c5cf8c
# Copyright © 2010 University of Blabbityblah and the Trustees of
Packit Service c5cf8c
#                    Schblitbittyboo.  All rights reserved.
Packit Service c5cf8c
#
Packit Service c5cf8c
# Someone could certainly extend this script to do so, if they cared
Packit Service c5cf8c
# (my organizations' copyright fits on a single line, so I wasn't
Packit Service c5cf8c
# motivated to handle the multi-line case :-) ).
Packit Service c5cf8c
#
Packit Service c5cf8c
Packit Service c5cf8c
use strict;
Packit Service c5cf8c
use Cwd;
Packit Service c5cf8c
use Getopt::Long;
Packit Service c5cf8c
use File::stat;
Packit Service c5cf8c
use Fcntl ':mode';
Packit Service c5cf8c
Packit Service c5cf8c
# Set to true if the script should merely check for up-to-date copyrights.
Packit Service c5cf8c
# Will exit with status 111 if there are out of date copyrights which this
Packit Service c5cf8c
# script can correct.
Packit Service c5cf8c
my $CHECK_ONLY = 0;
Packit Service c5cf8c
# used by $CHECK_ONLY logic for bookeeping
Packit Service c5cf8c
my $would_replace = 0;
Packit Service c5cf8c
Packit Service c5cf8c
# Set to true to suppress most informational messages.  Only out of date files
Packit Service c5cf8c
# will be printed.
Packit Service c5cf8c
my $QUIET = 0;
Packit Service c5cf8c
Packit Service c5cf8c
# Set to true if we just want to see the help message
Packit Service c5cf8c
my $HELP = 0;
Packit Service c5cf8c
Packit Service c5cf8c
# Defaults
Packit Service c5cf8c
my $my_search_name = "Cisco";
Packit Service c5cf8c
my $my_formal_name = "Cisco Systems, Inc.  All rights reserved.";
Packit Service c5cf8c
Packit Service c5cf8c
my @tokens;
Packit Service c5cf8c
push(@tokens, "See COPYING in top-level directory");
Packit Service c5cf8c
push(@tokens, "\\\$COPYRIGHT\\\$");
Packit Service c5cf8c
Packit Service c5cf8c
# Override the defaults if some values are set in the environment
Packit Service c5cf8c
$my_search_name = $ENV{HWLOC_COPYRIGHT_SEARCH_NAME}
Packit Service c5cf8c
    if (defined($ENV{HWLOC_COPYRIGHT_SEARCH_NAME}));
Packit Service c5cf8c
$my_formal_name = $ENV{HWLOC_COPYRIGHT_FORMAL_NAME}
Packit Service c5cf8c
    if (defined($ENV{HWLOC_COPYRIGHT_FORMAL_NAME}));
Packit Service c5cf8c
Packit Service c5cf8c
print "==> Copyright search name: $my_search_name\n";
Packit Service c5cf8c
print "==> Copyright formal name: $my_formal_name\n";
Packit Service c5cf8c
Packit Service c5cf8c
GetOptions(
Packit Service c5cf8c
    "help" => \$HELP,
Packit Service c5cf8c
    "quiet" => \$QUIET,
Packit Service c5cf8c
    "check-only" => \$CHECK_ONLY,
Packit Service c5cf8c
    "search-name=s" => \$my_search_name,
Packit Service c5cf8c
    "formal-name=s" => \$my_formal_name,
Packit Service c5cf8c
) or die "unable to parse options, stopped";
Packit Service c5cf8c
Packit Service c5cf8c
if ($HELP) {
Packit Service c5cf8c
    print <
Packit Service c5cf8c
$0 [options] [directory]
Packit Service c5cf8c
Packit Service c5cf8c
[directory] is "." unless specified.
Packit Service c5cf8c
Packit Service c5cf8c
--help | -h          This help message
Packit Service c5cf8c
--quiet | -q         Only output critical messages to stdout
Packit Service c5cf8c
--check-only         exit(111) if there are files with copyrights to edit
Packit Service c5cf8c
--search-name=NAME   Set search name to NAME
Packit Service c5cf8c
--formal-same=NAME   Set formal name to NAME
Packit Service c5cf8c
EOT
Packit Service c5cf8c
    exit(0);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#-------------------------------------------------------------------------------
Packit Service c5cf8c
# predeclare sub for print-like syntax
Packit Service c5cf8c
sub quiet_print {
Packit Service c5cf8c
    unless ($QUIET) {
Packit Service c5cf8c
        print @_;
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#-------------------------------------------------------------------------------
Packit Service c5cf8c
Packit Service c5cf8c
quiet_print "==> Copyright search name: $my_search_name\n";
Packit Service c5cf8c
quiet_print "==> Copyright formal name: $my_formal_name\n";
Packit Service c5cf8c
Packit Service c5cf8c
# Get the year
Packit Service c5cf8c
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
Packit Service c5cf8c
$year += 1900;
Packit Service c5cf8c
quiet_print "==> This year: $year\n";
Packit Service c5cf8c
Packit Service c5cf8c
# Find the top-level HWLOC source tree dir
Packit Service c5cf8c
my $start = defined $ARGV[0] ? $ARGV[0] : cwd();
Packit Service c5cf8c
my $top = $start;
Packit Service c5cf8c
while (! -d "$top/hwloc" && ! -d "$top/netloc") {
Packit Service c5cf8c
    chdir("..");
Packit Service c5cf8c
    $top = cwd();
Packit Service c5cf8c
    die "Can't find top-level hwloc directory"
Packit Service c5cf8c
        if ($top eq "/");
Packit Service c5cf8c
}
Packit Service c5cf8c
chdir($start);
Packit Service c5cf8c
Packit Service c5cf8c
quiet_print "==> Top-level hwloc dir: $top\n";
Packit Service c5cf8c
quiet_print "==> Current directory: $start\n";
Packit Service c5cf8c
Packit Service c5cf8c
my @files = find_modified_files();
Packit Service c5cf8c
Packit Service c5cf8c
if ($#files < 0) {
Packit Service c5cf8c
    quiet_print "No added / changed files -- nothing to do\n";
Packit Service c5cf8c
    exit(0);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Examine each of the files and see if they need an updated copyright
Packit Service c5cf8c
foreach my $f (@files) {
Packit Service c5cf8c
    quiet_print "Processing added/changed file: $f\n";
Packit Service c5cf8c
    open(FILE, $f) || die "Can't open file: $f";
Packit Service c5cf8c
Packit Service c5cf8c
    # Read in the file, and look for the special tokens; that's the
Packit Service c5cf8c
    # end of the copyright block that we're allowed to edit.  Do not
Packit Service c5cf8c
    # edit any copyright notices that may appear below that.
Packit Service c5cf8c
Packit Service c5cf8c
    my $i = 0;
Packit Service c5cf8c
    my $found_copyright = 0;
Packit Service c5cf8c
    my $found_me = 0;
Packit Service c5cf8c
    my @lines;
Packit Service c5cf8c
    my $my_line_index;
Packit Service c5cf8c
    my $token_line_index;
Packit Service c5cf8c
    my $token;
Packit Service c5cf8c
    while (<FILE>) {
Packit Service c5cf8c
        push(@lines, $_);
Packit Service c5cf8c
        foreach my $t (@tokens) {
Packit Service c5cf8c
            if ($_ =~ /$t/) {
Packit Service c5cf8c
                $token_line_index = $i;
Packit Service c5cf8c
                $token = $t;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        $my_line_index = $i
Packit Service c5cf8c
            if (!defined($token_line_index) && $_ =~ /$my_search_name/i);
Packit Service c5cf8c
        ++$i;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    close(FILE);
Packit Service c5cf8c
Packit Service c5cf8c
    # If there was not copyright token, don't do anything
Packit Service c5cf8c
    if (!defined($token_line_index)) {
Packit Service c5cf8c
        quiet_print "==> WARNING: Did not find any end-of-copyright tokens!\n";
Packit Service c5cf8c
        quiet_print "    File left unchanged\n";
Packit Service c5cf8c
        next;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    # don't modify ourself while running
Packit Service c5cf8c
    if ($f =~ m/update-my-copyright\.pl$/) {
Packit Service c5cf8c
        quiet_print "==> WARNING: Cannot modify myself while running!\n";
Packit Service c5cf8c
        quiet_print "    File left unchanged\n";
Packit Service c5cf8c
        next;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    # Figure out the line prefix
Packit Service c5cf8c
    $lines[$token_line_index] =~ m/^(.+)$token/;
Packit Service c5cf8c
    my $prefix = $1;
Packit Service c5cf8c
Packit Service c5cf8c
    # Now act on it
Packit Service c5cf8c
    if (!defined($my_line_index)) {
Packit Service c5cf8c
        quiet_print "--- My copyright line not found; adding:\n";
Packit Service c5cf8c
        my $str = "${prefix}Copyright © $year $my_formal_name\n";
Packit Service c5cf8c
        quiet_print "    $str";
Packit Service c5cf8c
        $lines[$token_line_index] = $str . $lines[$token_line_index];
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        quiet_print "--- Found existing copyright line:\n";
Packit Service c5cf8c
        quiet_print "    $lines[$my_line_index]";
Packit Service c5cf8c
        $lines[$my_line_index] =~ m/([\d+\-]+)/;
Packit Service c5cf8c
        my $years = $1;
Packit Service c5cf8c
        die "Could not find years in copyright line!"
Packit Service c5cf8c
            if (!defined($years));
Packit Service c5cf8c
Packit Service c5cf8c
        # If it's a range, separate them out
Packit Service c5cf8c
        my $first_year;
Packit Service c5cf8c
        my $last_year;
Packit Service c5cf8c
        if ($years =~ /\-/) {
Packit Service c5cf8c
            $years =~ m/(\d+)\s*-\s*(\d+)/;
Packit Service c5cf8c
            $first_year = $1;
Packit Service c5cf8c
            $last_year = $2;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            $first_year = $last_year = $years;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        # Sanity check
Packit Service c5cf8c
        die "Copyright looks like it extends before 1990...?"
Packit Service c5cf8c
            if ($first_year < 1990);
Packit Service c5cf8c
        die "Copyright in the future...?"
Packit Service c5cf8c
            if ($last_year > $year);
Packit Service c5cf8c
Packit Service c5cf8c
        # Do we need to do anything?
Packit Service c5cf8c
        if ($year > $last_year) {
Packit Service c5cf8c
            $lines[$my_line_index] = "${prefix}Copyright © $first_year-$year $my_formal_name\n";
Packit Service c5cf8c
            quiet_print "    Updated to:\n";
Packit Service c5cf8c
            quiet_print "    $lines[$my_line_index]";
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            quiet_print "    This year already included in copyright; not changing file\n";
Packit Service c5cf8c
            next;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    # If we got this far, we want to write out a new file
Packit Service c5cf8c
    my $newf = "$f.new-copyright";
Packit Service c5cf8c
    unlink($newf);
Packit Service c5cf8c
    open(FILE, ">$newf") || die "Can't open file: $newf";
Packit Service c5cf8c
    print FILE join('', @lines);
Packit Service c5cf8c
    close(FILE);
Packit Service c5cf8c
Packit Service c5cf8c
    if ($CHECK_ONLY) {
Packit Service c5cf8c
        # intentional "loud" print to be more useful in a pre-commit hook
Packit Service c5cf8c
        print "==> '$f' has a stale/missing copyright\n";
Packit Service c5cf8c
        unlink($newf);
Packit Service c5cf8c
        ++$would_replace;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    else {
Packit Service c5cf8c
        # Now replace the old one, keeping its mode
Packit Service c5cf8c
        my $mode = (stat($f))->mode;
Packit Service c5cf8c
        chmod $mode, $newf;
Packit Service c5cf8c
        unlink($f);
Packit Service c5cf8c
        rename($newf, $f);
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
if ($CHECK_ONLY and $would_replace) {
Packit Service c5cf8c
    exit(111);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#-------------------------------------------------------------------------------
Packit Service c5cf8c
Packit Service c5cf8c
# Returns a list of file names (relative to pwd) which git considers
Packit Service c5cf8c
# to be modified.
Packit Service c5cf8c
sub find_modified_files {
Packit Service c5cf8c
    my @files = ();
Packit Service c5cf8c
Packit Service c5cf8c
    # Number of path entries to remove from ${top}-relative paths.
Packit Service c5cf8c
    # (--show-cdup either returns the empty string or sequence of "../"
Packit Service c5cf8c
    # entries, always ending in a "/")
Packit Service c5cf8c
    my $n_strip = scalar(split(m!/!, scalar(`git rev-parse --show-cdup`))) - 1;
Packit Service c5cf8c
Packit Service c5cf8c
    # "." restricts scope, but does not get us relative path names
Packit Service c5cf8c
    my $cmd = "git status -z --porcelain --untracked-files=no .";
Packit Service c5cf8c
    quiet_print "==> Running: \"$cmd\"\n";
Packit Service c5cf8c
    my $lines = `$cmd`;
Packit Service c5cf8c
Packit Service c5cf8c
    # From git-status(1):
Packit Service c5cf8c
    # X          Y     Meaning
Packit Service c5cf8c
    # -------------------------------------------------
Packit Service c5cf8c
    #           [MD]   not updated
Packit Service c5cf8c
    # M        [ MD]   updated in index
Packit Service c5cf8c
    # A        [ MD]   added to index
Packit Service c5cf8c
    # D         [ M]   deleted from index
Packit Service c5cf8c
    # R        [ MD]   renamed in index
Packit Service c5cf8c
    # C        [ MD]   copied in index
Packit Service c5cf8c
    # [MARC]           index and work tree matches
Packit Service c5cf8c
    # [ MARC]     M    work tree changed since index
Packit Service c5cf8c
    # [ MARC]     D    deleted in work tree
Packit Service c5cf8c
    # -------------------------------------------------
Packit Service c5cf8c
    # D           D    unmerged, both deleted
Packit Service c5cf8c
    # A           U    unmerged, added by us
Packit Service c5cf8c
    # U           D    unmerged, deleted by them
Packit Service c5cf8c
    # U           A    unmerged, added by them
Packit Service c5cf8c
    # D           U    unmerged, deleted by us
Packit Service c5cf8c
    # A           A    unmerged, both added
Packit Service c5cf8c
    # U           U    unmerged, both modified
Packit Service c5cf8c
    # -------------------------------------------------
Packit Service c5cf8c
    # ?           ?    untracked
Packit Service c5cf8c
    # -------------------------------------------------
Packit Service c5cf8c
    foreach my $line (split /\x{00}/, $lines) {
Packit Service c5cf8c
        my $keep = 0;
Packit Service c5cf8c
        my ($s1, $s2, $fullname) = $line =~ m/^(.)(.) (.*)$/;
Packit Service c5cf8c
Packit Service c5cf8c
        # ignore all merge cases
Packit Service c5cf8c
        next if ($s1 eq "D" and $s2 eq "D");
Packit Service c5cf8c
        next if ($s1 eq "A" and $s2 eq "A");
Packit Service c5cf8c
        next if ($s1 eq "U" or $s2 eq "U");
Packit Service c5cf8c
Packit Service c5cf8c
        # only update for actually added/modified cases, no copies,
Packit Service c5cf8c
        # renames, etc.
Packit Service c5cf8c
        $keep = 1 if ($s1 eq "M" or $s2 eq "M");
Packit Service c5cf8c
        $keep = 1 if ($s1 eq "A");
Packit Service c5cf8c
Packit Service c5cf8c
        if ($keep) {
Packit Service c5cf8c
            my $relname = $fullname;
Packit Service c5cf8c
            $relname =~ s!^([^/]*/){$n_strip}!!g;
Packit Service c5cf8c
Packit Service c5cf8c
            push @files, $relname
Packit Service c5cf8c
                if (-f $relname);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return @files;
Packit Service c5cf8c
}