git-findtags.perlon commit git-daemon: timeout, eliminate double DWIM (960decc)
   1#!/usr/bin/perl -w
   2#
   3# Copyright (c) 2005 Martin Langhoff
   4#
   5# Walk the tags and find if they match a commit
   6# expects a SHA1 of a commit. Option -t enables 
   7# searching trees too.
   8#
   9
  10use strict;
  11use File::Basename;
  12use File::Find;
  13use Getopt::Std;
  14
  15my $git_dir = $ENV{GIT_DIR} || '.git';
  16$git_dir =~ s|/$||; # chomp trailing slash
  17
  18# options
  19our $opt_t;
  20getopts("t") || usage();
  21
  22my @tagfiles   = `find $git_dir/refs/tags -follow -type f`; # haystack
  23my $target = shift @ARGV;                     # needle
  24unless ($target) {
  25    usage();
  26}
  27
  28# drive the processing from the find hook
  29# slower, safer (?) than the find utility
  30find( { wanted   => \&process,
  31        no_chdir => 1,
  32        follow   => 1,
  33      }, "$git_dir/refs/tags");
  34
  35
  36sub process {
  37    my ($dev,$ino,$mode,$nlink,$uid,$gid);
  38
  39    # process only regular files
  40    unless ((($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _) {
  41        return 1; # ignored anyway
  42    }
  43
  44    my $tagfile = $_;
  45    chomp $tagfile;
  46    my $tagname = substr($tagfile, length($git_dir.'/refs/tags/'));
  47
  48    my $tagid = quickread($tagfile);
  49    chomp $tagid;
  50
  51    # is it just a soft tag?
  52    if ($tagid eq $target) {
  53        print "$tagname\n";
  54        return 1; # done with this tag
  55    }
  56
  57    # grab the first 2 lines (the whole tag could be large)
  58    my $tagobj = `git-cat-file tag $tagid | head -n2 `;
  59    if ($tagobj =~  m/^type commit$/m) { # only deal with commits
  60
  61        if ($tagobj =~ m/^object $target$/m) { # match on the commit
  62            print "$tagname\n";
  63
  64        } elsif ( $opt_t &&                      # follow the commit
  65                 $tagobj =~ m/^object (\S+)$/m) { # and try to match trees
  66            my $commitid = $1;
  67            my $commitobj = `git-cat-file commit $commitid | head -n1`;
  68            chomp $commitobj;
  69            $commitobj =~ m/^tree (\S+)$/;
  70            my $treeid = $1;
  71            if ($target eq $treeid) {
  72                print "$tagname\n";
  73            }
  74        }
  75    }
  76}
  77
  78sub quickread {
  79    my $file = shift;
  80    local $/; # undef: slurp mode
  81    open FILE, "<$file"
  82        or die "Cannot open $file : $!";
  83    my $content = <FILE>;
  84    close FILE;
  85    return $content;
  86}
  87
  88sub usage {
  89        print STDERR <<END;
  90Usage: ${\basename $0}     # find tags for a commit or tree
  91       [ -t ] <commit-or-tree-sha1>
  92END
  93        exit(1);
  94}