]> granicus.if.org Git - nethack/commitdiff
NHDT substitution version 2.
authorkeni <keni@his.com>
Tue, 31 Mar 2015 13:50:02 +0000 (09:50 -0400)
committerkeni <keni@his.com>
Tue, 31 Mar 2015 13:50:02 +0000 (09:50 -0400)
Re-run nhgitset.pl to install.
"perldoc DEVEL/hooksdir/nhsub" for details.  General docs still to come.
Quick notes:
- "git nhsub" lets you apply substitutions to a file without involving any
  version control.
- When doing nhadd/nhcommit, the working directory WILL reflect the results
  of the substitutions.
Let's see what this breaks.

18 files changed:
.gitattributes
DEVEL/.gitattributes
DEVEL/hooksdir/NHadd [changed mode: 0755->0644]
DEVEL/hooksdir/nhsub [new file with mode: 0644]
DEVEL/nhgitset.pl
dat/.gitattributes
doc/.gitattributes
sys/amiga/.gitattributes
sys/mac/.gitattributes
sys/msdos/.gitattributes
sys/os2/.gitattributes
sys/share/.gitattributes
sys/unix/.gitattributes
sys/unix/hints/.gitattributes
sys/vms/.gitattributes
sys/wince/.gitattributes
sys/winnt/.gitattributes
util/.gitattributes

index 894a91c8e15295383a81dc3c318cfa34ee9c9c79..9af92ddc6940b76cc9c9fb0d989a3f00eff8ddc3 100644 (file)
@@ -1,5 +1,5 @@
-*.[ch] filter=NHtext merge=NHsubst
-*.sh filter=NHtext merge=NHsubst
+*.[ch] NHSUBST
+*.sh NHSUBST
 * text=auto
 *.hqx -text
 *.sln -text
index 3e157372b5a0384470bc3f6e8deed7e1e964c99f..cc0b542f362a6af7ef040092590ee535bca0870c 100644 (file)
@@ -1,4 +1,4 @@
-Developer.txt filter=NHtext merge=NHsubst
-nhgitset.pl filter=NHtext merge=NHsubst
-hookdir/* filter=NHtext merge=NHsubst
+Developer.txt NHSUBST
+nhgitset.pl NHSUBST
+hooksdir/* NHSUBST
 * text=auto
old mode 100755 (executable)
new mode 100644 (file)
index 55a86ee..55138e7
@@ -1,14 +1,19 @@
 #!/usr/bin/perl
 # wrapper for nhadd and nhcommit aliases
-# $NHDT-Date$
+# $NHDT-Date: 1427408239 2015/03/26 22:17:19 $
 
 %ok = map { $_ => 1 } ('add', 'commit');
 
 die "Bad subcommand '$ARGV[0]'" unless $ok{$ARGV[0]};
 
+# we won't fail on a failure, so just system()
+$rv = system('.git/hooks/nhsub',"--$ARGV[0]",@ARGV[1..$#ARGV]);
+if($rv){
+        print "warning: nhsub failed: $rv $!\n";
+}
+
 if(length $ENV{GIT_PREFIX}){
         chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!";
 }
 
-$ENV{NHMODE} = 1;
 exec "git", @ARGV or die "Can't exec git: $!";
diff --git a/DEVEL/hooksdir/nhsub b/DEVEL/hooksdir/nhsub
new file mode 100644 (file)
index 0000000..b8cdd9f
--- /dev/null
@@ -0,0 +1,376 @@
+#!/usr/bin/perl
+# nhsub
+# $NHDT-Date: 1427408239 2015/03/26 22:17:19 $
+
+# Note: was originally called nhdate; the rename is not reflected in the code.
+
+use strict;
+my %opt;       #cmd v n f F (other single char, but we don't care)
+my $mode;      # a c d f (add, commit, date, date -f)
+
+#SO how do we know if a file has changed?
+#(git status: git status --porcelain --ignored -- FILES.
+#maybe + -z but it's a question of rename operations - probably doesn't
+# matter, but need to experiment.
+
+# key:  [dacf] first character of opt{cmd} (f if nhsub -f or add -f)
+#      first 2 chars of "git status --porcelain --ignored"
+# (see "git help status" for table)
+# No default.  Undef means something unexpected happened.
+my %codes = (
+       'f M'=>1, 'f D'=>1,             #           [MD]   not updated
+       'a M'=>0, 'a D'=>0,
+       'd M'=>0, 'd D'=>0,
+       'c M'=>0, 'c D'=>0,
+
+#           M        [ MD]   updated in index
+
+       'dA '=>1, 'dAM'=>1, 'dAD'=>1,
+       'aA '=>1, 'aAM'=>1, 'aAD'=>1,
+       'cA '=>1, 'cAM'=>1, 'cAD'=>1,
+       'fA '=>1, 'fAM'=>1, 'fAD'=>1,
+                                  # A        [ MD]   added to index
+
+       'dD '=>0, 'dDM'=>0,
+       'aD '=>1, 'aDM'=>1,
+       'cD '=>0, 'cDM'=>0,
+       'fD '=>1, 'fDM'=>1,
+                                  # D         [ M]   deleted from index
+
+#           R        [ MD]   renamed in index
+
+#           C        [ MD]   copied in index
+
+       'aM '=>1, 'aA '=>1, 'aR '=>1, 'aC '=>1,
+       'fM '=>1, 'fA '=>1, 'fR '=>1, 'fC '=>1,
+                                  # [MARC]          index and work tree matches
+
+       'd M'=>1, 'dMM'=>1, 'dAM'=>1, 'dRM'=>1, 'dCM'=>1,
+       'a M'=>1, 'aMM'=>1, 'aAM'=>1, 'aRM'=>1, 'aCM'=>1,
+       'c M'=>1, 'cMM'=>1, 'cAM'=>1, 'cRM'=>1, 'cCM'=>1,
+       'f M'=>1, 'fMM'=>1, 'fAM'=>1, 'fRM'=>1, 'fCM'=>1,
+                                  # [ MARC]     M work tree changed since index
+
+       'd D'=>0, 'dMD'=>0, 'dAD'=>0, 'dRD'=>0, 'dCD'=>0,
+       'a D'=>0, 'aMD'=>0, 'aAD'=>0, 'aRD'=>0, 'aCD'=>0,
+       'c D'=>0, 'cMD'=>0, 'cAD'=>0, 'cRD'=>0, 'cCD'=>0,
+       'f D'=>0, 'fMD'=>0, 'fAD'=>0, 'fRD'=>0, 'fCD'=>0,
+                                  # [ MARC]     D    deleted in work tree
+
+           # -------------------------------------------------
+           # DD    unmerged, both deleted
+           # AU    unmerged, added by us
+           # UD    unmerged, deleted by them
+           # UA    unmerged, added by them
+           # DU    unmerged, deleted by us
+           # AA    unmerged, both added
+           # UU    unmerged, both modified
+           # -------------------------------------------------
+        'a??'=>1, 'f??'=>1,            # ??    untracked
+       'd??'=>0, 'c??'=>0,
+
+       'f!!'=>1,                       # !!    ignored
+       'a!!'=>0, 'd!!'=>0, 'c!!'=>0
+);
+
+# OS hackery
+my $PDS = '/';
+if ($^O eq "MSWin32")
+{
+    $PDS = '\\';
+}
+
+# pick up the prefix for substitutions in this repo
+my $PREFIX = &git_config('nethack','substprefix');
+print "PREFIX: '$PREFIX'\n" if($opt{v});
+
+my @rawlist = &cmdparse(@ARGV);
+push(@rawlist,'.') if($#rawlist == -1);
+
+while(@rawlist){
+       my $raw = shift @rawlist;
+       if(-f $raw){
+               &schedule_work($raw);
+               next;
+       }
+       if(-d $raw){
+               if($raw =~ m!$PDS.git$!o){
+                       print "SKIP $raw\n" if($opt{v}>=2);
+                       next;
+               }
+               opendir RDIR,$raw or die "Can't opendir: $raw";
+               local($_);      # needed until perl 5.11.2
+               while($_ = readdir RDIR){
+                       next if(m/^\.\.?$/);
+                       if(m/^\./ && $opt{f}){
+                               print "       IGNORE-f: $raw$PDS$_\n" if($opt{v}>=2);
+                               next;
+                       }
+                       push(@rawlist, $raw.$PDS.$_);
+               }
+               closedir RDIR;
+       }
+       # ignore other file types
+}
+
+# XXX could batch things up - later
+
+sub schedule_work {
+       my($file) = @_;
+       print "CHECK: '$file'\n" if($opt{v}>=2);
+       local($_) = `git status --porcelain --ignored -- $file`;
+       my $key = $mode . join('',(m/^(.)(.)/));
+       if(length $key == 1){
+               # Hack.  An unmodified, tracked file produces no output from
+               # git status.  Treat as ignored.
+               $key .= '!!';
+       }
+       $key =~ s/-/ /g;        # for Keni's locally mod'ed git
+       if(!exists $codes{$key}){
+               die "I'm lost.\nK='$key' F=$file\nST=$_";
+       }
+       if($codes{$key}==0){
+               if($opt{v}>=2){
+                       print "       IGNORE: $_" if(length);
+                       print "       IGNORE: !! $file\n" if(!length);
+               }
+               return;
+       }
+       if($opt{F}){
+               my $ign = `git check-ignore $file`;
+               if($ign !~ m/^\s*$/){
+                       print "       IGNORE-F: $ign" if($opt{v}>=2);
+                       return;
+               }
+       }
+# FALLTHROUGH and continue
+#print     "ACCEPT TEST\n";    # XXXXXXXXXX TEST
+#return;
+
+       my $attr = `git check-attr NHSUBST -- $file`;
+       if($attr =~ m/NHSUBST:\s+(.*)/){
+# XXX this is a bug in git.  What if the value of an attribute is the
+# string "unset"?  Sigh.
+               if(! $opt{F}){
+                       if($1 eq "unset" || $1 eq "unspecified"){
+                               print "       NOATTR: $attr" if($opt{v}>=2);
+                               return;
+                       }
+               }
+               &process_file($file);
+               return;
+       }
+       die "Can't parse check-attr return: $attr\n";
+}
+
+sub process_file {
+       my($file) = @_;
+       print "DOFIL: $file\n" if($opt{v}>=1);
+
+       # For speed we read in the entire file then do the substitutions.
+       local($_) = '';
+       my $len;
+       open INFILE, "<", $file or die "Can't open $file: $!";
+       while(1){
+                       # On at least some systems we only get 64K.
+               my $len = sysread(INFILE, $_, 999999, length($_));
+               last if($len == 0);
+               die "read failed: $!" unless defined($len);
+       }
+       close INFILE;
+
+       local $::current_file = $file;  # used under handlevar
+       # $1 - var and value (including trailing space but not $)
+       # $2 - var
+       # $4 - value or undef
+#s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\N{DOLLAR SIGN}]+))?)\$/&handlevar($2,$4)/eg;
+my $count = s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\x24]+))?)\$/&handlevar($2,$4)/eg;
+# XXX had o modifier, why?
+       return unless($count>0);
+       return if($opt{n});
+
+       my $ofile = $file . ".nht";
+       open(TOUT, ">", $ofile) or die "Can't open $ofile";
+       die "write failed: $!" unless defined syswrite(TOUT, $_);
+       close TOUT or die "Can't close $ofile";
+       rename $ofile, $file or die "Can't rename $ofile to $file";
+}
+
+sub cmdparse {
+       my(@in) = @_;
+
+               # What are we doing?
+       $opt{cmd} = 'date';     # really nhsub
+       if($in[0] eq '--add'){
+               $opt{cmd} = 'add';
+               shift @in;
+       }
+       if($in[0] eq '--commit'){
+               $opt{cmd} = 'commit';
+               shift @in;
+       }
+
+# add: -n -v
+# commit: --dry-run -v
+# nhsub: -n -v
+       while($in[0] =~ m/^-/){
+               local($_) = $in[0];
+               if($_ eq '--'){
+                       shift @in;
+                       last;
+               }
+               if(m/^--/){
+                       if($opt{cmd} eq 'commit' && $_ eq '--dry-run'){
+                               $opt{'n'} = 1;
+                       }
+                       shift @in;
+                       next;
+               }
+               if(m/^-(.*)/){
+                       foreach my $single ( split(//,$1) ){
+                                       # don't do -v here from add/commit
+                               if($single ne 'v'){
+                                       $opt{$single}++;
+                               } elsif($opt{cmd} eq 'date'){
+                                       $opt{$single}++;
+                               }
+                       }
+               }
+               shift @in;
+       }
+
+       ($mode) = ($opt{cmd} =~ m/^(.)/);
+       $mode = 'f' if($opt{cmd} eq 'date' && ($opt{f}||$opt{F}));
+       $mode = 'f' if($opt{cmd} eq 'add' && $opt{f});
+
+       return @in;     # this is our file list
+}
+
+sub git_config {
+       my($section, $var) = @_;
+       my $raw = `git config --local --get $section.$var`;
+       $raw =~ s/[\r\n]*$//g;
+       return $raw if(length $raw);
+       die "Missing config var: [$section] $var\n";
+}
+
+sub handlevar {
+       my($var, $val) = @_;
+#      print "HIT '$var' '$val'\n" if($debug2);
+
+       my $subname = "PREFIX::$var";
+       if(defined &$subname){
+               no strict;
+               print "   SUBIN: $var '$val'\n" if($opt{v}>=3);
+               $val =~ s/\s+$//;
+               $val = &$subname($val);
+               print "   SUBOT: $var '$val'\n" if($opt{v}>=3);
+       } else {
+               warn "No handler for \$$PREFIX-$var\n";
+       }
+
+       if(length $val){
+               return "\$$PREFIX-$var: $val \$";
+       } else {
+               return "\$$PREFIX-$var\$";
+       }
+}
+
+package PREFIX;
+use POSIX qw(strftime);
+
+# On push, put in the current date because we changed the file.
+# On pull, keep the current value so we can see the last change date.
+sub Date {
+       my($val) = @_;
+       # we add this to make merge easier for now XXX
+       my $now = time; # not %s below - may not be portable
+       # YYYY/MM/DD HH:MM:SS
+       $val = "$now " . strftime("%Y/%m/%d %H:%M:%S", gmtime($now));
+       return $val;
+}
+
+#sub Header {
+#}
+#sub Author {
+#}
+
+# NB: the standard-ish Revision line isn't enough - you need Branch:Revision -
+#     but we split it into 2 so we can use the standard processing code on Revision
+#     and just slip Branch in.
+sub Branch {
+       my($val) = @_;
+       $val = `git symbolic-ref -q --short HEAD`;
+       $val =~ s/[\n\r]*$//;
+       $val =~ s/^\*\s*//;
+       $val = "(unknown)" unless($val =~ m/^[[:print:]]+$/);
+       return $val;
+}
+
+sub Revision {
+       my($val) = @_;
+       my @val = `git log --follow --oneline $::current_file`;
+       my $ver = 0+$#val;
+       $ver = 0 if($ver < 0);
+       $val = "1.$ver";
+       return $val;
+}
+__END__
+
+=head1 NAME
+
+C<nhsub> - NetHack git command for substitution variables
+
+=head1 SYNOPSIS
+
+C<git nhsub [-v[v[v]] [-n] [-f|-F] [--] [file...]>
+
+=head1 DESCRIPTION
+
+C<nhsub> rewrites the specified files by doing variable substitution for
+variables starting with the prefix specified in the repository's
+C<nethack.substprefix> configuration variable.  C<nhsub> is also invoked
+internally from the implementation of the C<nhadd> and C<nhcommit>
+commands.
+
+The program re-writes those files listed on the command line; if the file
+is actually a directory, the program recurses into that directory tree.
+Not all files found are re-written; some are ignored and those with no
+substitution variables are not re-written.  Unless changed by the options,
+files that have not changed are not affected.
+
+If no files are listed on the command line, the current directory is
+checked as if specified as C<.>.
+Files listed directly on the command line are always checked.
+The C<.git> directory is never processed.
+
+The following command line options are available:
+
+=over
+
+=item C<-v[v[v]]>
+
+Verbose output; may be (usefully) specified up to 3 times.  Not available
+when invoked as part of C<nhadd> or C<nhcommit>.
+
+=item C<-n>
+
+Do not write any files.
+
+=item C<-f>
+
+Force, version 1:  
+Perform substitution even if the file has not changed,
+except no dot files are processed unless listed directly on the command line.
+This prevents accidents with editor temprorary files while recursing.  Note
+that this overloads the C<-f> option of C<git add> and C<git commit>.
+
+=item C<-F>
+
+Force, version 2:
+Perform substitution even if the file has not changed,
+even if the NHSUBST attribute is not set for the
+file, and only if the file is not ignored by git.  Not available
+when invoked as part of C<nhadd> or C<nhcommit>.
+
+=back
index 183c73d69b14ea5f2f9b1b7e8e2e43f65875c7c3..08068484a9b3af8248853d402583bc33004ed9d8 100755 (executable)
@@ -3,7 +3,7 @@
 
 # value of nethack.setupversion we will end up with when this is done
 # version 1 is reserved for repos checked out before versioning was added
-my $version_new = 2;
+my $version_new = 3;
 my $version_old = 0;   # current version, if any (0 is no entry ergo new repo)
 
 use Cwd;
@@ -100,16 +100,29 @@ print STDERR "Installing aliases\n" if($opt_v);
 $addpath = catfile(curdir(),'.git','hooks','NHadd');
 &add_alias('nhadd', "!$addpath add");
 &add_alias('nhcommit', "!$addpath commit");
+my $nhsub = catfile(curdir(),'.git','hooks','nhsub');
+&add_alias('nhsub', "!$nhsub");
 
 print STDERR "Installing filter/merge\n" if($opt_v);
 
-if($^O eq "MSWin32"){
-       $cmd = '.git\\\\hooks\\\\NHtext';
-} else {
-       $cmd = catfile(curdir(),'.git','hooks','NHtext');
+# XXXX need it in NHadd to find nhsub???
+# removed at version 3
+#if($^O eq "MSWin32"){
+#      $cmd = '.git\\\\hooks\\\\NHtext';
+#} else {
+#      $cmd = catfile(curdir(),'.git','hooks','NHtext');
+#}
+#&add_config('filter.NHtext.clean', "$cmd --clean %f");
+#&add_config('filter.NHtext.smudge', "$cmd --smudge %f");
+if($version_old == 1 or $version_old == 2){
+       print STDERR "Removing filter.NHtext\n" if($opt_v);
+       system('git','config','--unset','filter.NHtext.clean') unless($opt_n);
+       system('git','config','--unset','filter.NHtext.smudge') unless($opt_n);
+       system('git','config','--remove-section','filter.NHtext') unless($opt_n);
+
+       print STDERR "Removing NHtext\n" if($opt_v);
+       unlink catfile(curdir(),'.git','hooks','NHtext') unless($opt_n);
 }
-&add_config('filter.NHtext.clean', "$cmd --clean %f");
-&add_config('filter.NHtext.smudge', "$cmd --smudge %f");
 
 $cmd = catfile(curdir(),'.git','hooks','NHsubst');
 &add_config('merge.NHsubst.name', 'NetHack Keyword Substitution');
index 72aa05edd6e11f7ac4ecac83ed215b563237e5a5..b59108e49106831c2805fab32f7e9014683c76d4 100644 (file)
@@ -1,3 +1,3 @@
-*.def  filter=NHtext merge=NHsubst
-*.des  filter=NHtext merge=NHsubst
-*.txt  filter=NHtext merge=NHsubst
+*.def  NHSUBST
+*.des  NHSUBST
+*.txt  NHSUBST
index 9ca88107645eaff00da0c8a975216d79d0ca22bb..a9a06f4c85e273d8b6ff650c433a3e3f88c4494f 100644 (file)
@@ -1,5 +1,5 @@
-*.mn   filter=NHtext merge=NHsubst
-*.6    filter=NHtext merge=NHsubst
-fixes.*        filter=NHtext merge=NHsubst
-window.doc filter=NHtext merge=NHsubst
+*.mn   NHSUBST
+*.6    NHSUBST
+fixes.*        NHSUBST
+window.doc NHSUBST
 
index 7a28030a9f3e24c342e0c3b1bf378f2434704acb..7735c64ea60924c458c058d7ade035a5bac7d4b0 100644 (file)
@@ -1 +1 @@
-*.p filter=NHtext merge=NHsubst
+*.p NHSUBST
index 62b9832d72ca9ab1bab9699cb481560d5b083630..8f8defc69a524ef9890a4d41e0d51b6835b913af 100644 (file)
@@ -1 +1 @@
-NHDeflts filter=NHtext merge=NHsubst
+NHDeflts NHSUBST
index baef52e462da2f82adeaaea56ac88a70eb955b11..7e8941f2db56f4e522488fd4f2e6c3f0a5b8f473 100644 (file)
@@ -1,4 +1,4 @@
-*.BC filter=NHtext merge=NHsubst
-*.bat filter=NHtext merge=NHsubst
-Makefile.* filter=NHtext merge=NHsubst
-Install.* filter=NHtext merge=NHsubst
+*.BC NHSUBST
+*.bat NHSUBST
+Makefile.* NHSUBST
+Install.* NHSUBST
index 8cffb77aecb10e1ecdf23abf2de85a34979c0034..31e18fe84cba172bba16b27f56b9fa649dba60c7 100644 (file)
@@ -1 +1 @@
-Makefile.* filter=NHtext merge=NHsubst
+Makefile.* NHSUBST
index 8cffb77aecb10e1ecdf23abf2de85a34979c0034..31e18fe84cba172bba16b27f56b9fa649dba60c7 100644 (file)
@@ -1 +1 @@
-Makefile.* filter=NHtext merge=NHsubst
+Makefile.* NHSUBST
index 8cffb77aecb10e1ecdf23abf2de85a34979c0034..31e18fe84cba172bba16b27f56b9fa649dba60c7 100644 (file)
@@ -1 +1 @@
-Makefile.* filter=NHtext merge=NHsubst
+Makefile.* NHSUBST
index a079959f1f21773984c7687a1ba63e098379efd9..db77844f75d9b29702775b43d338c27c36a57eb5 100644 (file)
@@ -1 +1 @@
-* filter=NHtext merge=NHsubst
+* NHSUBST
index 8cffb77aecb10e1ecdf23abf2de85a34979c0034..31e18fe84cba172bba16b27f56b9fa649dba60c7 100644 (file)
@@ -1 +1 @@
-Makefile.* filter=NHtext merge=NHsubst
+Makefile.* NHSUBST
index e034edc5ecb71b11f86b6f706a920a6e92b605e6..fbe75bcd463156379cb56358eb6f5fde02963646 100644 (file)
@@ -1,3 +1,3 @@
-*.ce filter=NHtext merge=NHsubst
-*.mak filter=NHtext merge=NHsubst
-*.bat filter=NHtext merge=NHsubst
+*.ce NHSUBST
+*.mak NHSUBST
+*.bat NHSUBST
index 2a38b029c5062a16dac59e73c2507808c224fed3..88f970c96f4ac507c6081d4040fa9b8396d588e1 100644 (file)
@@ -1,4 +1,4 @@
-Install.nt filter=NHtext merge=NHsubst
-Makefile.* filter=NHtext merge=NHsubst
-*.rc filter=NHtext merge=NHsubst
-*.bat filter=NHtext merge=NHsubst
+Install.nt NHSUBST
+Makefile.* NHSUBST
+*.rc NHSUBST
+*.bat NHSUBST
index 15e23d2680c717a94b0a9307565f5ee096b80a71..8b2657e618bcf4fceef7845888cea361793383ec 100644 (file)
@@ -1,2 +1,2 @@
-*.pl filter=NHtext merge=NHsubst
-*.[ly] filter=NHtext merge=NHsubst
+*.pl NHSUBST
+*.[ly] NHSUBST