From 36e8d9e6fc4a2fc7aa45546d594b8b19b09c8343 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Mon, 7 Oct 2024 13:45:35 -0400 Subject: [PATCH] nhgitset version 4 To update, run "perl DEVEL/nhgitset.pl" Fixes: - "nhcommit -a" has been fixed - NHDT was hardwired in places - no longer complain about a missing dat directory outside of the NetHack source tree - make update of gitinfo atomic - Replace some hardwired directory separators with OS-dependent constructs Backwards Incompatibilities: - NH_DATESUB's DATE() is now Date() to match the other variables - MSYS2 requires an additional Perl package - the MSYS2 docs have been updated New Help System: - git nhhelp This command mirrors "git help" for nh* commands. - See git nhhelp nhsub for general help on substitution variables New Substitution Variables: -Brev() An aBREViation of $PREFIX-Branch$:$PREFIX-Revision$ - this may help get line length under control in file headers. -Assert(TYPE=VALUE) If TYPE does not match VALUE, do not substitute on this line. TYPE P checks VALUE against nethack.substprefix -Project(arg) Returns nethack.projectname if there is no arg and an uppercase version if arg is uc. Other New Features: - Add nethack.projectname - Documentation updates - see "git nhhelp nhsub" - On checkout or merge of a branch, check for nhgitset version updates and provide an optional message to the user. - Move NH_DATESUB substitutions here from cron job to keep dates in sync - PREFIX-* keywords now available in NH_DATESUB templates - Support use of nhgitset.pl from a different repo; note that update checks will be dependent on keeping the original source repo up-to-date and in the same location. --- DEVEL/Developer.txt | 9 +- DEVEL/VERSION | 40 ++ DEVEL/hooksdir/NHadd | 25 +- DEVEL/hooksdir/NHgithook.pm | 311 ++++++++--- DEVEL/hooksdir/NHsubst | 182 ++++--- DEVEL/hooksdir/NHtext | 8 +- DEVEL/hooksdir/nhhelp | 79 +++ DEVEL/hooksdir/nhsub | 879 +++++++++++++++++++----------- DEVEL/hooksdir/post-applypatch | 8 +- DEVEL/hooksdir/post-checkout | 9 +- DEVEL/hooksdir/post-commit | 11 +- DEVEL/hooksdir/post-merge | 9 +- DEVEL/hooksdir/post-rewrite | 6 +- DEVEL/hooksdir/pre-applypatch | 6 +- DEVEL/hooksdir/pre-auto-gc | 6 +- DEVEL/hooksdir/pre-commit | 6 +- DEVEL/hooksdir/pre-push | 6 +- DEVEL/hooksdir/pre-rebase | 6 +- DEVEL/hooksdir/prepare-commit-msg | 8 +- DEVEL/nhgitset.pl | 446 +++++++++------ doc/Guidebook.mn | 7 +- doc/Guidebook.tex | 2 +- doc/dlb.6 | 12 +- doc/makedefs.6 | 2 +- doc/nethack.6 | 2 +- doc/recover.6 | 2 +- sys/windows/build-msys2.txt | 2 + 27 files changed, 1412 insertions(+), 677 deletions(-) create mode 100644 DEVEL/VERSION create mode 100644 DEVEL/hooksdir/nhhelp diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index c7d7683c9..f43f88f43 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -92,10 +92,11 @@ B. Specify the prefix for variable substitution: tree you cloned from git. I use ~/nethack/GITADDDIR; for that base, create the needed directories and edit the file: ~/nethack/GITADDDIR/DOTGIT/PRE - Put this in it (if your OS is not Unix-like you may need to change - the first line): + Put this in it, adapting it to your variant (if your OS is not Unix-like + you may need to change the first line): #!/bin/sh git config nethack.substprefix MINE + git config nethack.projectname MineHack Now make it executable: chmod +x ~/nethack/GITADDDIR/DOTGIT/PRE C. Configure the repository: @@ -169,8 +170,8 @@ A. Introduction The PREFIX is the value in the git config variable nethack.substprefix. VARNAME is one of: Date - Branch (experimental) - Revision (experimental) + Branch + Revision other names will give a warning. B. Enabling variable expansion diff --git a/DEVEL/VERSION b/DEVEL/VERSION new file mode 100644 index 000000000..01a759d53 --- /dev/null +++ b/DEVEL/VERSION @@ -0,0 +1,40 @@ +4 +Fixes: +- "nhcommit -a" has been fixed +- NHDT was hardwired in places +- no longer complain about a missing dat directory outside of the + NetHack source tree +- make update of gitinfo atomic +- Replace some hardwired directory separators with OS-dependent constructs + +Backwards Incompatibilities: +- NH_DATESUB's DATE() is now Date() to match the other variables +- MSYS2 requires an additional Perl package - the MSYS2 docs have + been updated + +New Help System: +- git nhhelp + This command mirrors "git help" for nh* commands. +- See git nhhelp nhsub for general help on substitution variables + +New Substitution Variables: +-Brev() + An aBREViation of $PREFIX-Branch$:$PREFIX-Revision$ - this + may help get line length under control in file headers. +-Assert(TYPE=VALUE) + If TYPE does not match VALUE, do not substitute on this line. + TYPE P checks VALUE against nethack.substprefix +-Project(arg) + Returns nethack.projectname if there is no arg and an uppercase + version if arg is uc. + +Other New Features: +- Add nethack.projectname +- Documentation updates - see "git nhhelp nhsub" +- On checkout or merge of a branch, check for nhgitset version updates +- Move NH_DATESUB substitutions here from cron job to keep dates in sync +- PREFIX-* keywords now available in NH_DATESUB templates +- Support use of nhgitset.pl from a different repo; note that update + checks will be dependent on keeping the original source repo up-to-date + and in the same location. + diff --git a/DEVEL/hooksdir/NHadd b/DEVEL/hooksdir/NHadd index c4d6e547d..f4386c81d 100644 --- a/DEVEL/hooksdir/NHadd +++ b/DEVEL/hooksdir/NHadd @@ -12,11 +12,32 @@ 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"; + print "warning: nhsub failed: $rv $!\n"; } if(length $ENV{GIT_PREFIX}){ - chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; + chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; } exec "git", @ARGV or die "Can't exec git: $!"; + +__END__ +=for nhgitset nhadd Add file contents to the index with NetHack additions +=for nhgitset nhcommit Record changes to the repository with NetHack additions + +=head1 NAME + +C - NetHack internal common code for nhadd and nhcommit + +=head1 SYNOPSIS + +Cgit add optionsE> + +Cgit add optionsE> + +=head1 DESCRIPTION + +Run nhsub with the given arguments, then run C or C +with the given arguments. Note that only basic arguments for those commands +are understood; more complex situations may be handled by running C +manually before running C or C. diff --git a/DEVEL/hooksdir/NHgithook.pm b/DEVEL/hooksdir/NHgithook.pm index c7c3456f5..3f52008c0 100644 --- a/DEVEL/hooksdir/NHgithook.pm +++ b/DEVEL/hooksdir/NHgithook.pm @@ -16,9 +16,11 @@ my $tracefile = "/tmp/nhgitt.$$"; # OS hackery my $DS = quotemeta('/'); +my $PDS = '/'; if ($^O eq "MSWin32") { $DS = quotemeta('\\'); + $PDS = '\\'; } our %saved_env; @@ -26,25 +28,23 @@ our @saved_argv; our $saved_input; sub saveSTDIN { - @saved_input = ; + @saved_input = ; - if($trace){ - print TRACE "STDIN:\n"; - print TRACE $saved_input; - print TRACE "ENDSTDIN\n"; - } + if($trace){ + print TRACE "STDIN:\n"; + print TRACE $saved_input; + print TRACE "ENDSTDIN\n"; + } - tie *STDIN, 'NHIO::STDIN', @saved_input; + tie *STDIN, 'NHIO::STDIN', @saved_input; } -# XXX this needs a re-write (don't tie and untie, just set NEXT=0) -# (the sensitive thing is @foo = ) sub resetSTDIN{ - my $x = tied(*STDIN); - my %x = %$x; - my $data = @$x{DATA}; - untie *STDIN; - tie *STDIN, 'NHIO::STDIN', $data; + my $x = tied(*STDIN); + my %x = %$x; + my $data = @$x{DATA}; + untie *STDIN; + tie *STDIN, 'NHIO::STDIN', $data; } # don't need this now @@ -55,21 +55,142 @@ sub resetSTDIN{ #} sub PRE { - &do_hook("PRE"); + &do_hook("PRE"); } sub POST { - &do_hook("POST"); + &do_hook("POST"); +} + +### +### versioning for nhgitset and friends +### + +# values of nethack.setupversion and DEVEL/VERSION: +# 1 is reserved for repos checked out before versioning was added +# 2 used clean/smudge filter, poorly +# 3 was first production version +# 4 added the version file and version checking; nhhelp, NH_DATESUB support, etc. + +sub version_in_devel { + # (1) check for a non-null nethack.setuppath - this handles + # any repo that has already been set up (but NOT checking + # out =v4 since nethack.setuppath will exist but + # DEVEL/VERSION will not). + # XXX if the source repo has been removed, we'll fall back to + # the third case - hopefully that's ok. + # XXX there's no way to recover from a missing source repo + # without editing .git/config. + my $path = `git config --local nethack.setuppath`; + chomp $path; + $path =~ s/DEVEL$//; # NOP if config not set + + # (2) else check the local directory; that will be correct for NHsource. + if(0 == length $path){ + $path = `git rev-parse --show-toplevel`; + chomp $path; + $path = '' unless(-d "$path${PDS}DEVEL"); + } + # (3) If that doesn't exist, check using the invocation path; that will be + # correct for other repos during nhgitset (but will also fail for + # checking out 3 over 4). + if(0 == length $path){ + # strip out "DEVEL" + $path = ($0 =~ m!^(.*)${PDS}DEVEL${PDS}.*?(*nla:DEVEL)!)[0]; + } + # Uh oh? + if(0==length($path) or (! -d "$path${PDS}DEVEL")){ + die "Can't locate DEVEL directory in '$path'."; + } + + # Handle checking out version <4 over version >=4. If + # this seems to be the situation, don't revert the code. + return 0 if(! -f "$path${PDS}DEVEL${PDS}VERSION"); + + my $version; + my $verfile = "$path${PDS}DEVEL${PDS}VERSION"; + open VERFH,"<",$verfile or die "xCan't open $verfile: $!"; + $version = 0+; + my $message = join('',); + close VERFH; + die "Valid version not found in $verfile" unless($version >= 4); + return ($version,$message) if($version > 0); + return 0; +} + +sub version_in_git { + my $vtemp = `git config --local --get nethack.setupversion`; + chomp($vtemp); + return $vtemp if($vtemp > 0); + return 0; +} + +sub version_set_git { + my $version_new = $_[0]; + + system("git config nethack.setupversion $version_new"); + if($?){ + die "Can't set nethack.setupversion $version_new: $?,$!\n"; + } } ### ### store githash and gitbranch in dat/gitinfo.txt ### +# CAUTION! This is run not just from git hooks, but also from +# sys/unix/gitinfo.sh sub nhversioning { use strict; use warnings; + # See if we're (probably) in a "git pull", in which case we need to + # check for upgrades. + my $check_upgrade = 1 if($_[0]); + + # Check for pre-v4 source repo. + my $is_sourcerepo; + { + chomp($is_sourcerepo = `git config --type=int --get nethack.is-sourcerepo`); + if(0 == length $is_sourcerepo){ # not set - assume old repo + $is_sourcerepo = 1; + }elsif($is_sourcerepo==1){ + ; + }elsif($is_sourcerepo==0){ + ; + } + } + + # Skip the skipping tests if we're being called directly. + # NB: post-commit has no args, but that will be caught by + # the next test for non-source repos. + if($#ARGV != -1){ + # Skip this if we didn't change branches, but see if we need to warn. + if(defined($ARGV[2]) and ($ARGV[2] == 0)){ + # Because we can create an out of sync state, possibly warn. + my $ref = $ARGV[1]; + if($is_sourcerepo and (0 != 0+`git diff --name-only $ref $ref^ |grep ^DEVEL|wc -l`)){ + warn "WARNING: DEVEL directory changed. Versioning may be inconsistent\n"; + } + return + } + } + + if($check_upgrade){ + my $current_version = version_in_git(); + my($new_version,$message) = version_in_devel(); + if($new_version > $current_version){ + warn "nhgitset.pl and/or related programs have changed.\n"; + warn "Please re-run nhgitset.pl to update from version $current_version to $new_version.\n"; + if(length $message){ + warn "Additional information\n$message\n"; + } + } + } + + # Skip versioning if we aren't in a source repo. + return if(0==$is_sourcerepo); + my $git_sha = `git rev-parse HEAD`; $git_sha =~ s/\s+//g; my $git_branch = `git rev-parse --abbrev-ref HEAD`; @@ -77,7 +198,14 @@ sub nhversioning { die "git rev-parse failed" unless(length $git_sha and length $git_branch); my $exists = 0; - if (open my $fh, '<', 'dat/gitinfo.txt') { + no strict 'refs'; + no strict 'subs'; + my $file_gitinfo = "dat${PDS}gitinfo.txt"; + my $file_gittemp = "dat${PDS}TMPgitinfo.txt"; + use strict 'subs'; + use strict 'refs'; + + if (open my $fh, '<', $file_gitinfo) { $exists = 1; my $hashok = 0; my $branchok = 0; @@ -91,61 +219,71 @@ sub nhversioning { } close $fh; if ($hashok && $branchok) { - print "dat/gitinfo.txt unchanged, githash=".$git_sha."\n"; + print "$file_gitinfo unchanged, githash=".$git_sha."\n"; return; } } else { - print "WARNING: Can't find dat directory\n" unless(-d "dat"); + warn "WARNING: Can't find dat directory\n" unless(-d "dat"); + return; } - if (open my $fh, '>', 'dat/gitinfo.txt') { + if (open my $fh, '>', $file_gittemp) { my $how = ($exists ? "updated" : "created"); print $fh 'githash='.$git_sha."\n"; print $fh 'gitbranch='.$git_branch."\n"; - print "dat/gitinfo.txt ".$how.", githash=".$git_sha."\n"; + print "$file_gitinfo ".$how.", githash=".$git_sha."\n"; + if(close($fh)){ + if(rename($file_gittemp, $file_gitinfo)){ + ; # all ok + } else { + warn "WARNING: Can't rename $file_gittemp -> $file_gitinfo"; + } + } else { + warn "WARNING: Can't close temp file: $!"; + } } else { - print "WARNING: Unable to open dat/gitinfo.txt: $!\n"; + warn "WARNING: Unable to open $file_gitinfo: $!\n"; } } # PRIVATE sub do_hook { - my($p) = @_; - my $hname = $0; - $hname =~ s!^((.*$DS)|())(.*)!$1$p-$4!; - if(-x $hname){ - print TRACE "START $p: $hname\n" if($trace); + my($p) = @_; + my $hname = $0; + $hname =~ s!^((.*$DS)|())(.*)!$1$p-$4!; + if(-x $hname){ + print TRACE "START $p: $hname\n" if($trace); - open TOHOOK, "|-", $hname or die "open $hname: $!"; - print TOHOOK ; - close TOHOOK or die "close $hname: $! $?"; + open TOHOOK, "|-", $hname or die "open $hname: $!"; + print TOHOOK ; + close TOHOOK or die "close $hname: $! $?"; - print TRACE "END $p\n" if($trace); - } + print TRACE "END $p\n" if($trace); + } } sub trace_start { - return unless($trace); - my $self = shift; - open TRACE, ">>", $tracefile; - print TRACE "START CLIENT PID:$$ ARGV:\n"; - print TRACE "CWD: " . cwd() . "\n"; - print TRACE "[0] $0\n"; - my $x1; - for(my $x=0;$x $ENV{$k}\n"; - } + return unless($trace); + my $self = shift; + open TRACE, ">>", $tracefile; + print TRACE "START CLIENT PID:$$ ARGV:\n"; + print TRACE "CWD: " . cwd() . "\n"; + print TRACE "[0] $0\n"; + my $x1; + for(my $x=0;$x $ENV{$k}\n"; + } } BEGIN { - %saved_env = %ENV; - @saved_argv = @ARGV; - &trace_start; + %saved_env = %ENV; + @saved_argv = @ARGV; + &trace_start; } ### @@ -153,42 +291,41 @@ BEGIN { ### package NHIO::STDIN; sub TIEHANDLE { - my $class = shift; - my %fh; - # XXX yuck - if(ref @_[0]){ - $fh{DATA} = @_[0]; - } else { - $fh{DATA} = \@_; - } - $fh{NEXT} = 0; - return bless \%fh, $class; + my $class = shift; + my %fh; + if(ref @_[0]){ + $fh{DATA} = @_[0]; + } else { + $fh{DATA} = \@_; + } + $fh{NEXT} = 0; + return bless \%fh, $class; } sub READLINE { - my $self = shift; - return undef if($self->{EOF}); - if(wantarray){ - my $lim = $#{$self->{DATA}}; - my @ary = @{$self->{DATA}}[$self->{NEXT}..$lim]; - my @rv = @ary[$self->{NEXT}..$#ary]; - $self->{EOF} = 1; - return @rv; - } else{ - my $rv = $self->{DATA}[$self->{NEXT}]; - if(length $rv){ - $self->{NEXT}++; - return $rv; - } else { - $self->{EOF} = 1; - return undef; - } - } + my $self = shift; + return undef if($self->{EOF}); + if(wantarray){ + my $lim = $#{$self->{DATA}}; + my @ary = @{$self->{DATA}}[$self->{NEXT}..$lim]; + my @rv = @ary[$self->{NEXT}..$#ary]; + $self->{EOF} = 1; + return @rv; + } else{ + my $rv = $self->{DATA}[$self->{NEXT}]; + if(length $rv){ + $self->{NEXT}++; + return $rv; + } else { + $self->{EOF} = 1; + return undef; + } + } } sub EOF { - $self = shift; - return $self->{EOF}; + $self = shift; + return $self->{EOF}; } 1; @@ -223,11 +360,20 @@ NHgithook - common code for NetHack git hooks (and other git bits) (core hook code) &NHgithook::POST; +__END__ +=for nhgitset NHgithook Infrastructure for NetHack git hooks. + =head1 DESCRIPTION +Perl module for infrastructure of NetHack Git hooks. + Buffers call information so multiple independent actions may be coded for Git hooks and similar Git callouts. +Maintains C. + +Common routines for dealing with nethack.setupversion git config variable. + =head1 SETUP Changing the C<$trace> and C<$tracefile> variables requires editing the @@ -247,6 +393,9 @@ may be useful since multiple processes may be live at the same time. Some features not well tested, especially under Windows. +Not well documented, but almost no one needs to change (or even call) +this code. + =head1 AUTHOR Kenneth Lorber (keni@his.com) diff --git a/DEVEL/hooksdir/NHsubst b/DEVEL/hooksdir/NHsubst index 99621fc57..0c7aeb067 100755 --- a/DEVEL/hooksdir/NHsubst +++ b/DEVEL/hooksdir/NHsubst @@ -17,24 +17,24 @@ my $dbgfile = ($^O eq "MSWin32") ? "$ENV{TEMP}.$$" : "/tmp/trace.$$"; open TRACE, ">>", $rawin?"/dev/tty":(($debug==0)? $sink : $dbgfile); print TRACE "TEST TRACE\n"; if($debug){ - print TRACE "START CLIENT ARGV:\n"; - print TRACE "[0] $0\n"; - my $x1; - for(my $x=0;$x $ENV{$k}\n"; - } - print TRACE "CWD: " . `pwd`; - &dumpfile($ARGV[0], "[0O]"); - &dumpfile($ARGV[1], "[1A]"); - &dumpfile($ARGV[2], "[2B]"); - print TRACE "L=$ARGV[3]\n"; - print TRACE "END\n"; + print TRACE "START CLIENT ARGV:\n"; + print TRACE "[0] $0\n"; + my $x1; + for(my $x=0;$x $ENV{$k}\n"; + } + print TRACE "CWD: " . `pwd`; + &dumpfile($ARGV[0], "[0O]"); + &dumpfile($ARGV[1], "[1A]"); + &dumpfile($ARGV[2], "[2B]"); + print TRACE "L=$ARGV[3]\n"; + print TRACE "END\n"; } my $mark_len = $ARGV[3]; @@ -47,37 +47,37 @@ my $mark_end = '>' x $mark_len; my $PREFIX; # pick up the prefix for substitutions in this repo if($rawin){ - $PREFIX = "TEST"; + $PREFIX = "TEST"; } else { - $PREFIX = `git config --local --get nethack.substprefix`; - chomp($PREFIX); + $PREFIX = `git config --local --get nethack.substprefix`; + chomp($PREFIX); } my @out; my $cntout; if($rawin){ - @out = ; + @out = ; } else { - #system "git merge-file -p .... > temp - my $tags = "-L CURRENT -L ANCESTOR -L OTHER"; # XXX should "CURRENT" be "MINE"? - @out = `git merge-file -p $tags $ARGV[1] $ARGV[0] $ARGV[2]`; + #system "git merge-file -p .... > temp + my $tags = "-L CURRENT -L ANCESTOR -L OTHER"; # XXX should "CURRENT" be "MINE"? + @out = `git merge-file -p $tags $ARGV[1] $ARGV[0] $ARGV[2]`; #NB: we don't check the exit value because it's useless - print TRACE "MERGE-FILE START\n".join("",@out)."MERGE-FILE END\n"; + print TRACE "MERGE-FILE START\n".join("",@out)."MERGE-FILE END\n"; } ($cntout,@out) = &edit_merge(@out); if($rawin){ - print "COUNT: $cntout\n"; - print @out; + print "COUNT: $cntout\n"; + print @out; } else { - # spit @out to $ARGV[1] (careful: what about EOL character?) - open OUT, ">$ARGV[1]" or die "Can't open $ARGV[1]"; - print OUT @out; - close OUT; + # spit @out to $ARGV[1] (careful: what about EOL character?) + open OUT, ">$ARGV[1]" or die "Can't open $ARGV[1]"; + print OUT @out; + close OUT; - print TRACE "WRITING START ($ARGV[1])\n".join("",@out)."WRITING END\n"; - &dumpfile($ARGV[1], "READBACK"); + print TRACE "WRITING START ($ARGV[1])\n".join("",@out)."WRITING END\n"; + &dumpfile($ARGV[1], "READBACK"); } print TRACE "COUNT: $cntout\n"; @@ -95,37 +95,37 @@ exit( ($cntout>0) ? 1 : 0); # keep failing so we don't need to keep changing the setup while building this script sub dumpfile { - my($file, $tag) = @_; - print TRACE "FILE $tag START\n"; - print TRACE `hexdump -C $file`; - print TRACE "FILE END\n"; + my($file, $tag) = @_; + print TRACE "FILE $tag START\n"; + print TRACE `hexdump -C $file`; + print TRACE "FILE END\n"; } sub edit_merge { - my(@input) = @_; - # $::count is a bit ugly XXX - local $::count = 0; # we need the number of conflicts for exit() - my @out; + my(@input) = @_; + # $::count is a bit ugly XXX + local $::count = 0; # we need the number of conflicts for exit() + my @out; - local $_; - while($_ = shift @input){ - if(m/^$mark_start /){ - print TRACE "FOUND A CONFLICT\n"; - my @conflict; - push(@conflict, $_); - while($_ = shift @input){ - push(@conflict, $_); - if(m/^$mark_end /){ - last; - } - } - push(@out, &edit_conflict(@conflict)); - } else { - push(@out, $_); + local $_; + while($_ = shift @input){ + if(m/^$mark_start /){ + print TRACE "FOUND A CONFLICT\n"; + my @conflict; + push(@conflict, $_); + while($_ = shift @input){ + push(@conflict, $_); + if(m/^$mark_end /){ + last; } + } + push(@out, &edit_conflict(@conflict)); + } else { + push(@out, $_); } - print TRACE "RETURN count=$::count\n"; - return($::count, @out); + } + print TRACE "RETURN count=$::count\n"; + return($::count, @out); } sub edit_conflict { @@ -305,41 +305,41 @@ print TRACE "MVM: -$varname-$oursval-$theirval-\n"; package PREFIX; # Resolve the conflict of a single var's 2 values. Return undef to leave the conflict. sub Date { - my($PREFIX, $varname, $mine, $theirs) = @_; - my $m = ($mine =~ m/(\d+)/)[0]; - my $t = ($theirs =~ m/(\d+)/)[0]; - return undef unless ($m>0) && ($t>0); + my($PREFIX, $varname, $mine, $theirs) = @_; + my $m = ($mine =~ m/(\d+)/)[0]; + my $t = ($theirs =~ m/(\d+)/)[0]; + return undef unless ($m>0) && ($t>0); - return "\$$PREFIX-$varname: " . (($m>$t)?$mine:$theirs) .' $'; + return "\$$PREFIX-$varname: " . (($m>$t)?$mine:$theirs) .' $'; } #sub Header { #sub Author { sub Branch { - my($PREFIX, $varname, $mine, $theirs) = @_; - $mine =~ s/^\s+//; $mine =~ s/\s+$//; - $theirs =~ s/^\s+//; $theirs =~ s/\s+$//; - return "\$$PREFIX-$varname: $mine \$" if(length $mine); - return "\$$PREFIX-$varname: $theirs \$" if(length $theirs); - return "\$$PREFIX-$varname\$" if(length $theirs); + my($PREFIX, $varname, $mine, $theirs) = @_; + $mine =~ s/^\s+//; $mine =~ s/\s+$//; + $theirs =~ s/^\s+//; $theirs =~ s/\s+$//; + return "\$$PREFIX-$varname: $mine \$" if(length $mine); + return "\$$PREFIX-$varname: $theirs \$" if(length $theirs); + return "\$$PREFIX-$varname\$" if(length $theirs); } sub Revision { - my($PREFIX, $varname, $mine, $theirs) = @_; - my($m) = ($mine =~ m/1.(\d+)/); - my($t) = ($theirs =~ m/1.(\d+)/); - if($m > 0 && $t > 0){ - my $q = ($m > $t) ? $m : $t; - return "\$$PREFIX-$varname: 1.$q \$"; - } - if($m > 0){ - return "\$$PREFIX-$varname: 1.$m \$"; - } - if($t > 0){ - return "\$$PREFIX-$varname: 1.$t \$"; - } - return "\$$PREFIX-$varname\$"; + my($PREFIX, $varname, $mine, $theirs) = @_; + my($m) = ($mine =~ m/1.(\d+)/); + my($t) = ($theirs =~ m/1.(\d+)/); + if($m > 0 && $t > 0){ + my $q = ($m > $t) ? $m : $t; + return "\$$PREFIX-$varname: 1.$q \$"; + } + if($m > 0){ + return "\$$PREFIX-$varname: 1.$m \$"; + } + if($t > 0){ + return "\$$PREFIX-$varname: 1.$t \$"; + } + return "\$$PREFIX-$varname\$"; } __END__ @@ -396,3 +396,17 @@ TEST 8: === /* NetHack 3.7 objnam.c $TEST-Date: 1426977394 2015/03/21 22:36:34 $ $TEST-Branch: master $:$TEST-Revision: 1.108 $ */ >>> d3 + +=for nhgitset NHsubst NetHack merge driver + +=head1 NAME + +C - NetHack merge driver + +=head1 SYNOPSIS + +(called from C, do not invoke directly) + +=head1 DESCRIPTION + +This is invoked by git through .git/config. diff --git a/DEVEL/hooksdir/NHtext b/DEVEL/hooksdir/NHtext index 7128c0d31..01848675b 100755 --- a/DEVEL/hooksdir/NHtext +++ b/DEVEL/hooksdir/NHtext @@ -3,6 +3,8 @@ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. +# Not in use as of v3, but could come back in the future. + # clean/smudge filter for handling substitutions use strict; @@ -54,9 +56,9 @@ if($ARGV[0] eq "--clean"){ exit 1; } -# XXX for now, there isn't any - if we get called, we subst. No options for now. +# XX for now, there isn't any - if we get called, we subst. No options for now. # get relevant config info -#XXX +#XX #git check-attr -a $ARGV[1] # Process stdin to stdout. @@ -109,7 +111,7 @@ sub Date { my($val, $mode, $submode) = @_; if($mode eq "c"){ if($submode==0){ - # we add this to make merge easier for now XXX + # we add this to make merge easier for now XX 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)); diff --git a/DEVEL/hooksdir/nhhelp b/DEVEL/hooksdir/nhhelp new file mode 100644 index 000000000..90fb7d68f --- /dev/null +++ b/DEVEL/hooksdir/nhhelp @@ -0,0 +1,79 @@ +#!/usr/bin/perl +# $NHDT-Date: 1730238507 2024/10/29 21:48:27 $ $NHDT-Brev: keni-gitset:1.0 $ +# Copyright (c) 2024 by Kenneth Lorber, Kensington, Maryland +# NetHack may be freely redistributed. See license for details. + +# This deals with a git problem: there is no way to do: +# git help alias-name +# (yes, that will show the definition of the alias, but not show an actual +# help document). +# +# So we implement this: +# nhhelp +# With no arguments, run perldoc on this file. +# nhhelp FOO +# Run perldoc on .git/hooks/FOO (if it exists). + +if($#ARGV == -1){ + system("perldoc $0")==0 or die "perldoc error: $!\n"; + exit 0; +} +if($#ARGV == 0){ + if($ARGV[0] eq "-a"){ + &listhelp; + exit 0; + } + + chomp(my $target = `git config nethack.aliashelp.$ARGV[0]`); + my $file = ".git/hooks/$target"; + if(-f $file){ + system("perldoc $file")==0 or die "perldoc error: $!\n"; + } else { + print "Unknown name '$ARGV[0]'\n"; + &usage; + } + exit 0; +} +&usage; +exit 0; + +sub usage { +print <|-a] +E_O_M +} + +sub listhelp { + print "nhhelp is available for:\n"; + my @namelist = `git config --name-only --get-regexp 'nethack.aliashelp.*'`; + print "NAMELIST $?\n" if($?); + @namelist = map { + if(m/^nethack.aliashelp.(.*)/){ + chomp(my $x = `git config 'nethack.aliasdesc.$1'`); + sprintf("%-12s %s",$1,$x); + } + } sort @namelist; + print " " . join("\n ", @namelist)."\n"; + exit 0; +} + +__END__ +=for nhgitset nhhelp Help on NetHack git commands + +=head1 NAME + +C - NetHack git command for help on NetHack git commands + +=head1 SYNOPSIS + +C + +=head1 DESCRIPTION + +With no arguments, print this message. + +With one argument matching a NetHack git command, print the +documentation for that command. + +With the argument C<-a>, show all available nhhelp topics with one line +summaries. diff --git a/DEVEL/hooksdir/nhsub b/DEVEL/hooksdir/nhsub index 7e5fdbd2f..7aa183b65 100644 --- a/DEVEL/hooksdir/nhsub +++ b/DEVEL/hooksdir/nhsub @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $NHDT-Date: 1524689646 2018/04/25 20:54:06 $ Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.7 $ +# $NHDT-Date: 1524689646 2018/04/25 20:54:06 $ Branch: NetHack-3.7 $:$NHDT-Revision: 1.7 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -8,9 +8,11 @@ use strict; our %opt; #cmd v n f F m (other single char, but we don't care) my $mode; # a c d f (add, commit, date, date -f) +our $count; +our $skip; if(length $ENV{GIT_PREFIX}){ - chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; + chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; } #SO how do we know if a file has changed? @@ -23,74 +25,78 @@ if(length $ENV{GIT_PREFIX}){ # (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, + # [MD] not updated + 'f M'=>1, 'f D'=>1, + 'a M'=>0, 'a D'=>0, + 'd M'=>0, 'd D'=>0, + 'c M'=>0, 'c D'=>0, - 'dM '=>0, 'dMM'=>1, 'dMD'=>0, - 'aM '=>0, 'aMM'=>1, 'aMD'=>0, - 'cM '=>0, 'cMM'=>1, 'cMD'=>0, - 'fM '=>0, 'fMM'=>1, 'fMD'=>0, - # M [ MD] updated in index + 'dM '=>0, 'dMM'=>1, 'dMD'=>0, + 'aM '=>0, 'aMM'=>1, 'aMD'=>0, + 'cM '=>0, 'cMM'=>1, 'cMD'=>0, + 'fM '=>0, 'fMM'=>1, 'fMD'=>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 + '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 + 'dD '=>0, 'dDM'=>0, + 'aD '=>1, 'aDM'=>1, + 'cD '=>0, 'cDM'=>0, + 'fD '=>1, 'fDM'=>1, + # D [ M] deleted from index - 'dR '=>0, 'dRM'=>1, 'dRD'=>0, - 'aR '=>0, 'aRM'=>1, 'aRD'=>0, - 'cR '=>0, 'cRM'=>1, 'cRD'=>0, - 'fR '=>0, 'fRM'=>1, 'fRD'=>0, - # R [ MD] renamed in index + 'dR '=>0, 'dRM'=>1, 'dRD'=>0, + 'aR '=>0, 'aRM'=>1, 'aRD'=>0, + 'cR '=>0, 'cRM'=>1, 'cRD'=>0, + 'fR '=>0, 'fRM'=>1, 'fRD'=>0, + # R [ MD] renamed in index - 'dC '=>0, 'dCM'=>1, 'dCD'=>0, - 'aC '=>0, 'aCM'=>1, 'aCD'=>0, - 'cC '=>0, 'cCM'=>1, 'cCD'=>0, - 'fC '=>0, 'fCM'=>1, 'fCD'=>0, - # C [ MD] copied in index + 'dC '=>0, 'dCM'=>1, 'dCD'=>0, + 'aC '=>0, 'aCM'=>1, 'aCD'=>0, + 'cC '=>0, 'cCM'=>1, 'cCD'=>0, + 'fC '=>0, 'fCM'=>1, 'fCD'=>0, + # 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 + '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 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 + '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, + # ------------------------------------------------- + # 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 + # ------------------------------------------------- + # ?? untracked + 'a??'=>1, 'f??'=>1, + 'd??'=>0, 'c??'=>0, - 'f!!'=>1, # !! ignored - 'a!!'=>0, 'd!!'=>0, 'c!!'=>0, + # !! ignored + 'f!!'=>1, - 'f@@'=>1, # @@ internal ignored - 'a@@'=>0, 'd@@'=>0, 'c@@'=>0 + 'a!!'=>0, 'd!!'=>0, 'c!!'=>0, + + 'f@@'=>1, # @@ internal ignored + 'a@@'=>0, 'd@@'=>0, 'c@@'=>0 ); # OS hackery @@ -123,309 +129,430 @@ my @rawlist0 = &cmdparse(@ARGV); # Let's try this for all commands. my @rawlist; foreach my $e (@rawlist0){ - if($e =~ m/[?*[\\]/){ - my @rv = &lsfiles(undef, $e); - push(@rawlist, @rv) if(@rv); - if($opt{f}){ - my @rv = &lsfiles('-i', $e); - push(@rawlist, @rv) if(@rv); - } - } else { - push(@rawlist, $e); + if($e =~ m/[?*[\\]/){ + my @rv = &lsfiles(undef, $e); + push(@rawlist, @rv) if(@rv); + if($opt{f}){ + my @rv = &lsfiles('-i', $e); + push(@rawlist, @rv) if(@rv); } + } else { + push(@rawlist, $e); + } } push(@rawlist,'.') if($#rawlist == -1); # pick up the prefix for substitutions in this repo -#TEST my $PREFIX = &git_config('nethack','substprefix'); -my $PREFIX = "NHDT"; +my $PREFIX = &git_config('nethack','substprefix'); +die "nethack.substprefix not set in git config" unless(length($PREFIX) > 0); print "PREFIX: '$PREFIX'\n" if($opt{v}); while(@rawlist){ - my $raw = shift @rawlist; - if(-f $raw){ + 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; } - 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; + 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 - if(! -e $raw){ - print "warning: missing file $raw\n"; + if(! -e $raw){ + print "warning: missing file $raw\n"; + } +} + +sub checkattr { + my($kw, $file) = @_; + my $attr = `git check-attr $kw -- $file`; + if($attr =~ m/$kw:\s+(.*)/){ + # 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 0; + } } + return 1; + } + return 0; } # 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){ + 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 another version of 'ignored'. - $key .= '@@'; + $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); } - $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; - } - 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"; + my $do_nhsubst = &checkattr('NHSUBST', $file); + my $do_nhdatesub = &checkattr('NH_DATESUB', $file); + &process_file($file, $do_nhsubst, $do_nhdatesub); +# XXX no longer reachable - parse errors not caught properly? +# die "Can't parse check-attr return: $attr\n"; } sub process_file { - my($file) = @_; - print "DOFIL: $file\n" if($opt{v}>=1); + my($file, $do_nhsubst, $do_nhdatesub) = @_; + print "DOFIL: $file\n" if($opt{v}>=1); + $count=0; # if we don't change anything, don't re-write the file - # 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; + # 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 $mode = 0777 & (stat($file))[2]; + local $::current_file = $file; # used under handle* + if($do_nhsubst){ + # TODO: This doesn't handle PREFIX-Assert. To do that, + # we need to capture an entire line, call new sub handlevars() + # and let it iterate across all PREFIX-Foo while + # maintaining $::skip and reverting (like &handledatesub does). + # Also: capture optional arg: $NHDT-Foo(arg)$ $NHDT-Foo(arg): value $ - my $ofile = $file . ".nht"; - open(TOUT, ">", $ofile) or die "Can't open $ofile"; + # $1 - var and value (including trailing space but not $) + # $2 - var + # $4 - value or undef + # \x24 == $ + s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\x24]+) )?)\$/&handlevar($2,$4,1)/eg; + } -# die "write failed: $!" unless defined syswrite(TOUT, $_); - my $offset = 0; - my $sent; -#print STDERR "L=",length,"\n"; - while($offset < length){ - $sent = syswrite(TOUT, $_, (length($_) - $offset), $offset); - die "write failed: $!" unless defined($sent); -#print STDERR "rv=$sent\n"; - last if($sent == (length($_) - $offset)); - $offset += $sent; -#print STDERR "loop: O=$offset\n"; - } + if($do_nhdatesub){ + # e.g: + #.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "DATE(%-d %B %Y)" NETHACK + #.TH MAKEDEFS 6 "8 February 2022" NETHACK - close TOUT or die "Can't close $ofile"; - # Do the right thing for *nix and hope for the best elsewhere: - chmod($mode, $ofile)==1 or warn "Can't set filemode on $ofile"; - rename $ofile, $file or die "Can't rename $ofile to $file"; + # locate the keyword and the rest of the line, capturing the rest of the line (the pattern) + # use zero width assertions so we can capture them but not replace them (DOES THIS WORK?) + #and grab the next line (the replaced text) + + # $1 - pattern + # $2 - the next line (the expanded pattern) + s/ + \sNH_DATESUB\s+ # our trigger + (.*)[\n\r]+ # save the pattern in $1 + \K # but don't replace it + (.*) # save the oldvalue in $2 + / + &handledatesub($2, $1) # replace oldvalue + /emxg; + + #/m so ^$ match at each line + #/x this will be a mess, so attempt to comment it + } + +#print STDERR "COUNT = $count\n"; + return unless($count>0); + return if($opt{n}); + + my $ofile = $file . ".nht"; + my $mode = 0777 & (stat($file))[2]; # save the original mode + open(TOUT, ">", $ofile) or die "Can't open $ofile"; + + my $offset = 0; + my $sent; + while($offset < length){ + $sent = syswrite(TOUT, $_, (length($_) - $offset), $offset); + die "write failed: $!" unless defined($sent); + last if($sent == (length($_) - $offset)); + $offset += $sent; + } + + close TOUT or die "Can't close $ofile"; + # Do the right thing for *nix and hope for the best elsewhere: + chmod($mode, $ofile)==1 or warn "Can't set filemode on $ofile"; + rename $ofile, $file or die "Can't rename $ofile to $file"; } -# XXX docs for --fixup and --squash are wrong in git's synopsis. --file missing -# --message --template -t sub cmdparse { - my(@in) = @_; + 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; - } + # 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 'add' && $_ eq '--dry-run'){ - exit 0; - } - if($opt{cmd} eq 'commit' && $_ eq '--dry-run'){ - exit 0; - } - if($opt{cmd} eq 'add' && $_ eq '--refresh'){ - exit 0; - } - shift @in; - next; - } -# XXX this is messy - time for a rewrite? - if(m/^-(.*)/){ - foreach my $single ( split(//,$1) ){ - # don't do -v here from add/commit - if($single ne 'v'){ - # don't use -m from add/commit - if($opt{cmd} eq 'date' || $single ne 'm'){ - $opt{$single}++; - } - } elsif($opt{cmd} eq 'date'){ - $opt{$single}++; - } + while($in[0] =~ m/^-/){ + local($_) = $in[0]; + if($_ eq '--'){ + shift @in; + last; + } + if(m/^--/){ + if($opt{cmd} eq 'add' && $_ eq '--dry-run'){ + exit 0; + } + if($opt{cmd} eq 'commit' && $_ eq '--dry-run'){ + exit 0; + } + if($opt{cmd} eq 'add' && $_ eq '--refresh'){ + exit 0; + } + shift @in; + next; + } - if($opt{cmd} eq 'add' && $single eq 'n'){ - exit 0; - } + if(m/^-(.*)/){ + foreach my $single ( split(//,$1) ){ + # don't do -v here from add/commit + if($single ne 'v'){ + # don't use -m from add/commit + if($opt{cmd} eq 'date' || $single ne 'm'){ + $opt{$single}++; + } + } elsif($opt{cmd} eq 'date'){ + $opt{$single}++; + } + + if($opt{cmd} eq 'add' && $single eq 'n'){ + exit 0; + } #need to deal with options that eat a following element (-m, -F etc etc) #add: nothing? #commit: -c -C -F -m # -u mode is optional # -S keyid is optional - if($opt{cmd} eq 'commit'){ - if($single =~ m/[uS]/){ - last; - } - if($single =~ m/[cCFm]/){ -#XXX this will be a mess if the argument is wrong, but can we tell? No. - shift @in; - last; - } - } - } + if($opt{cmd} eq 'commit'){ + if($single =~ m/[uS]/){ + last; + } + if($single =~ m/[cCFm]/){ + # This will be a mess if the argument is wrong, but can we tell? No. + shift @in; + last; + } } - shift @in; + } } + 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}); + ($mode) = ($opt{cmd} =~ m/^(.)/); + $mode = 'f' if($opt{cmd} eq 'date' && ($opt{f}||$opt{F})); + $mode = 'f' if($opt{cmd} eq 'add' && $opt{f}); - if($opt{cmd} eq 'add' && $#in == -1){ - exit 0; - } - if($opt{cmd} eq 'commit' && $#in == -1){ - exit 0; - } - if($opt{cmd} eq 'add' && $opt{a} && $#in != -1){ - exit 0; - } - if($opt{cmd} eq 'add' && $opt{a}){ - my $x = `git rev-parse --show-toplevel`; - $x =~ s/[\n\r]+$//; - push(@in, $x); - } - return @in; # this is our file list + if($opt{cmd} eq 'add' && $#in == -1){ + # "git nhadd" with no files has nothing to work on + exit 0; + } + if($opt{cmd} eq 'commit' && $#in == -1){ + # "git nhcommit" with no args handles files already + # added, we assume with "git nhadd" + exit 0; + } + if($opt{cmd} eq 'commit' && $opt{a} && $#in == -1){ + # "git commit -a" does multiple things; we only care + # about modigied files. +#XXX this assumes $RS is set properly for Windows - need to check that + my @x = split(/$::RS/,`git ls-files -m`); + chomp(@x); + push(@in, @x); + } + if($opt{cmd} eq 'commit' && $opt{a} && $#in != -1){ + # Let git complain about this for us. + exit 0; + } +# "git add" doesn't have a -a option +# if($opt{cmd} eq 'add' && $opt{a} && $#in != -1){ +# exit 0; +# } +# I don't know what this was trying to do, but it's wrong. +# if($opt{cmd} eq 'add' && $opt{a}){ +# my $x = `git rev-parse --show-toplevel`; +# $x =~ s/[\n\r]+$//; +# push(@in, $x); +# } + 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"; + 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); +# (oldvalue, pattern) +sub handledatesub { + my $oldval = $_[0]; # used if assert fails + $skip = 0; # one if assert fails + my $out = $_[1]; # the pattern, which we'll edit in place +#print "OLD: '$oldval;\n"; +#print "PAT: '$out'\n"; + my $newvalue = $_[1]; + $out =~ s/ + \b # don't substitute on a partial word + (Assert|Date|Branch|Revision|Brev|Project) # $1 - keyword + \( # ( + ([^)]*) # $2 - argument + \) # ) + /&onedatesub($1,$2) + /egx; - 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"; + { + local $::x = $_[0] ne $out; + if ($::x){ + $count += $::x; +# warn "COUNT++"; } + } +#print STDERR "OUT SKIP=$skip count=$count\n"; +#print STDERR "OUT old='$oldval'\n new='$out'\n"; + return ($skip>0 or $count==0) ? $oldval : $out; +} + +sub onedatesub { + my($kw, $arg) = @_; + my $sname = "PREFIX::$kw"; + die "internal error, '$sname' not defined" unless defined(&$sname); + + no strict; + my $rv = &$sname(undef, $arg); + return $rv; +} + +# Assert(P=prefix) +# Date(format) +# Branch() +# Revision() +# Brev() Branch:Rev (aBREViated) + +sub handlevar { + my($var, $val, $wrap) = @_; +#print "HV '$var' '$val'\n"; + my $oldval = $val; + my $subname = "PREFIX::$var"; + if(defined &$subname){ + no strict; + print " SUBIN: $var '$val'\n" if($opt{v}>=3); + $val =~ s/\s+$//; + $val = &$subname($val, undef); + print " SUBOT: $var '$val'\n" if($opt{v}>=3); + { + local $::x = ($oldval ne $val); + if ($::x){ + $count += $::x; +# warn "COUNT2++ o='$oldval' v='$val'"; + } + } + } else { + warn "No handler for \$$PREFIX-$var\n"; + } + + if($wrap){ if(length $val){ return "\$$PREFIX-$var: $val \$"; } else { return "\$$PREFIX-$var\$"; } + } else { + return $val; + } } sub lsfiles { - my ($flags, $ps) = @_; - open RV, "-|", "git ls-files $flags '$ps'" or die "Can't ls-files"; - my @rv = ; - map { s/[\r\n]+$// } @rv; - if(!close RV){ - return undef if($! == 0); - die "close ls-files failed: $!"; - } - return undef if($#rv == -1); - return @rv; + my ($flags, $ps) = @_; + open RV, "-|", "git ls-files $flags '$ps'" or die "Can't ls-files"; + my @rv = ; + map { s/[\r\n]+$// } @rv; + if(!close RV){ + return undef if($! == 0); + die "close ls-files failed: $!"; + } + return undef if($#rv == -1); + return @rv; } 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) = @_; - my $now; - if($opt{m}){ - my $hash = `git log -1 '--format=format:%H' $::current_file`; - #author keni 1429884677 -0400 - chomp($now = `git cat-file -p $hash | awk '/author/{print \$4}'`); + my(undef, $val) = @_; + my $now; + +# DONE XXX after several bug fixes, this set of ifs needs some cleanup +my $hash = `git log -1 '--format=format:%H' $::current_file`; + $now = $^T; +# if($opt{m} or not defined $hash){ + + # cope with file not yet added to git + if(not defined $hash){ + if(-f $::current_file){ + $now = (stat($::current_file))[9]; } else { - $now = time; + die "Can't find file '$::current_file'\n"; } + } elsif($opt{m}) { + #author keni 1429884677 -0400 + chomp($now = `git cat-file -p $hash | awk '/author/{print \$4}'`); + } +# } else { +# } + +# DONE XXX simplify this with %s ? +# my $fmt = length $val ? $val : "%Y/%m/%d %H:%M:%S"; + my $fmt = length $val ? $val : "%s %Y/%m/%d %H:%M:%S"; # YYYY/MM/DD HH:MM:SS - $val = "$now " . strftime("%Y/%m/%d %H:%M:%S", gmtime($now)); - return $val; +# $val = ((length $val==0)?"$now ":"") . strftime($fmt, gmtime($now)); + $val = strftime($fmt, gmtime($now)); + return $val; } #sub Header { @@ -434,26 +561,84 @@ sub Date { #} # 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. +# but we split it into 2 so we can use the standard processing code on +# Revision and just slip Branch in. +# But see new Brev below. 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; + 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; + my $val; + my @val = `git log --follow --oneline $::current_file`; + my $ver = 0+$#val; + $ver = 0 if($ver < 0); + $val = "1.$ver"; + return $val; } + +sub Brev { + my $branch; + $branch = `git symbolic-ref -q --short HEAD`; + $branch =~ s/[\n\r]*$//; + $branch =~ s/^\*\s*//; + $branch = "(unknown)" unless($branch =~ m/^[[:print:]]+$/); + + my @val = `git log --follow --oneline $::current_file`; + my $ver = 0+$#val; + $ver = 0 if($ver < 0); + $ver = "1.$ver"; + + my $val = "$branch:$ver"; + + return $val; +} + +sub Project { + my(undef, $arg) = @_; + my $pn = &::git_config('nethack','projectname'); + if(length $arg == 0){ + ; + } elsif($arg eq 'uc'){ + $pn = uc($pn); + } else { + warn "unknown argument '$arg' to Project()\n"; + } + return $pn; +} + + +sub Assert { + my(undef, $val) = @_; + + my($key, $arg) = ($val =~ m/^(.)=(.*)/); + if(!defined $arg){ + warn "syntax error: Assert($val)\n"; + $::skip = 1; + } + my $prefix = $2; + + # P assert arg matches saved prefix + if('P' eq $key){ + my $repoid = &::git_config('nethack','substprefix'); + if($repoid ne $prefix){ + $::skip = 1 + } + return ''; + } + + warn "Unknown Assert type '$key'\n"; + + return ''; +} + __END__ +=for nhgitset nhsub Update substitution variables =head1 NAME @@ -473,9 +658,15 @@ 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. +Not all files found are re-written; only those with the attribute +NHSUBST (for inline substitutions) or NH_DATESUB (for template +substitution) are considered; finally those with no substitution +variables or no changes due to subtitution variables are not +re-written. Unless changed by the options, files that have not +changed are not affected. + +As a special case, a file not yet added to Git may be the target of +C. If no files are listed on the command line, the current directory is checked as if specified as C<.>. @@ -519,3 +710,83 @@ updated when last changed. (Do not use C/C after C assertions compare the current Git config variable +C +with the C and succeed if they are identical. + +=back + +=item Date(format) / PREFIX-Date + +This variable usually substitutes the current time but see C<-m> above. + +The format of the resulting date varies. For C or C with +no format, "%s %Y/%m/%d %H:%M:%S" is used. Otherwise the given strftime +format is used. + +=item Branch() / PREFIX-Branch + +This variable is replaced with the name of the currently checked out Git +branch. + +=item Revision() / PREFIX-Revision + +This variable's value emulates a RCS or CVS style revision number. +It consists of "1." followed by the number of commits affecting the +current file. + +=item Brev() / PREFIX-Brev + +This is a convenience variable that concatenates C, a colon, and +C. Short for "aBREViated". + +=item Project() + +Returns git variable nethack.projectname. If given the argument C, returns +an upper-case version of nethack.projectname. + +=back + +=head1 SUBSTITUTION STYLES + +=head2 Prefix Substitution + +If a file has the Git attribute C, any +text that looks like a RCS/CVS variable substitution will perform +that substitution. That is, either of the following forms: + + $Var$ + $Var: Value $ + +=head2 Template Substitution + +If a file has the Git attribute C, any line that has +the token C will replace the I line with the +variable expansion of everything after that token. For example: + + .\"DO NOT REMOVE NH_DATESUB .ds f2 DATE(%B %-d, %Y) + .ds f2 September 13, 2024 + +=head1 SEE ALSO + +git help gitattributes + +perldoc nhgitset.pl diff --git a/DEVEL/hooksdir/post-applypatch b/DEVEL/hooksdir/post-applypatch index ec6af70be..37170a48e 100755 --- a/DEVEL/hooksdir/post-applypatch +++ b/DEVEL/hooksdir/post-applypatch @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 post-applypatch $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/post-checkout b/DEVEL/hooksdir/post-checkout index d7e6c5724..db8578f94 100755 --- a/DEVEL/hooksdir/post-checkout +++ b/DEVEL/hooksdir/post-checkout @@ -24,10 +24,15 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; -&NHgithook::nhversioning; +eval { &NHgithook::nhversioning unless($nogithook) }; +warn "nhversioning failed: $@" if($@); &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-commit b/DEVEL/hooksdir/post-commit index cb37b3800..753cb4a04 100755 --- a/DEVEL/hooksdir/post-commit +++ b/DEVEL/hooksdir/post-commit @@ -24,10 +24,17 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; -&NHgithook::nhversioning; +eval { &NHgithook::nhversioning unless($nogithook) }; +warn "nhversioning failed: $@" if($@); &NHgithook::POST; exit 0; + + diff --git a/DEVEL/hooksdir/post-merge b/DEVEL/hooksdir/post-merge index a634f51ef..ca9e45e5f 100755 --- a/DEVEL/hooksdir/post-merge +++ b/DEVEL/hooksdir/post-merge @@ -25,10 +25,15 @@ BEGIN { push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; -&NHgithook::nhversioning; +eval { &NHgithook::nhversioning(1) unless($nogithook) }; +warn "nhversioning failed: $@" if($@); &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-rewrite b/DEVEL/hooksdir/post-rewrite index 655c1a0cd..3dcc7c18c 100755 --- a/DEVEL/hooksdir/post-rewrite +++ b/DEVEL/hooksdir/post-rewrite @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::saveSTDIN; diff --git a/DEVEL/hooksdir/pre-applypatch b/DEVEL/hooksdir/pre-applypatch index 3b57a6f53..2ec0588a9 100755 --- a/DEVEL/hooksdir/pre-applypatch +++ b/DEVEL/hooksdir/pre-applypatch @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/pre-auto-gc b/DEVEL/hooksdir/pre-auto-gc index d1ab9b005..22e45b666 100755 --- a/DEVEL/hooksdir/pre-auto-gc +++ b/DEVEL/hooksdir/pre-auto-gc @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/pre-commit b/DEVEL/hooksdir/pre-commit index bb5dbfe84..b19fc2fd4 100755 --- a/DEVEL/hooksdir/pre-commit +++ b/DEVEL/hooksdir/pre-commit @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/pre-push b/DEVEL/hooksdir/pre-push index c2639fa2e..a578ce529 100755 --- a/DEVEL/hooksdir/pre-push +++ b/DEVEL/hooksdir/pre-push @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::saveSTDIN; diff --git a/DEVEL/hooksdir/pre-rebase b/DEVEL/hooksdir/pre-rebase index 7f447a082..4c472ef63 100755 --- a/DEVEL/hooksdir/pre-rebase +++ b/DEVEL/hooksdir/pre-rebase @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/prepare-commit-msg b/DEVEL/hooksdir/prepare-commit-msg index b6813851a..a1ff14292 100755 --- a/DEVEL/hooksdir/prepare-commit-msg +++ b/DEVEL/hooksdir/prepare-commit-msg @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $NHDT-Date: 1524689633 2018/04/25 20:53:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 prepare-commit-msg $NHDT-Date: 1524689633 2018/04/25 20:53:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/nhgitset.pl b/DEVEL/nhgitset.pl index e29cae2b4..984d45a32 100755 --- a/DEVEL/nhgitset.pl +++ b/DEVEL/nhgitset.pl @@ -3,32 +3,29 @@ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. -# 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 = 3; -my $version_old = 0; # current version, if any (0 is no entry ergo new repo) use Cwd; use Getopt::Std; # Activestate Perl doesn't include File::Spec. Grr. BEGIN { - eval "require File::Spec::Functions"; - if($@){ - die <import; + } + File::Spec::Functions->import; } exit 1 unless(getopts('nvf')); # TODO: this can probably have better output -# OS hackery -my $DS = quotemeta('/'); # Directory Separator (for regex) -my $DSP = '/'; # ... for printing +BEGIN { + # OS hackery + $DS = quotemeta('/'); # Directory Separator (for regex) + $PDS = '/'; # ... for printing # Temporarily disabled; there's something weird about msys # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). #if($^O eq "msys"){ @@ -37,78 +34,129 @@ my $DSP = '/'; # ... for printing # # NB: We don't need to do anything about File::Spec. It doesn't know # # about msys but it defaults to Unix, so we'll be ok. #} -if($^O eq "MSWin32"){ + if($^O eq "MSWin32"){ $DS = quotemeta('\\'); - $DSP = '\\'; + $PDS = '\\'; + } + + # Fix @INC so we can 'use NHgithook' before it's installed. + # Set $is_sourcerepo while we're at it - same logic. + { + # Special case for running nhgitset against a different repo. + # Must preceed the normal case! + # NB: we use $DEVhooksdir later in the program + $DEVhooksdir = ($0 =~ m!^(.*)$DS!)[0]; + chomp($DEVhooksdir); + $DEVhooksdir .= $PDS."hooksdir"; + push(@INC, $DEVhooksdir) if(-d $DEVhooksdir); + # This one is for the normal case (in NHsource) + my $topdir = `git rev-parse --show-toplevel`; + chomp $topdir; + $topdir .= "${PDS}DEVEL${PDS}hooksdir"; + push(@INC, $topdir) if(-d $topdir); + $is_sourcerepo = 0; + $is_sourcerepo = 1 if(-d $topdir); + } } +use NHgithook; + # current (installed) version, if any (0 is no entry ergo new repo) +my $version_old = NHgithook::version_in_git; + # version this program will install +my($version_new,$message_new) = NHgithook::version_in_devel; + +if(0==$version_new and !opt_f){ + # Edge case: this repo has been set up using version >= 4, but now we're running + # nhgitset after checking out DEVEL supporting version <4. + # Use -f to recover from broken DEVEL code. + print STDERR "DEVEL has version <4 code but version >=4 code already installed. Stopping.\n"; + print STDERR "(If you need to reinstall the old code, rerun with -f\n"; + exit 0; +} + + +die "Valid version not found in DEVEL/VERSION" unless(0==$version_new or $version_new >= 4); + # make sure we're at the top level of a repo if(! -d ".git"){ - die "This is not the top level of a git repository.\n"; + die "This is not the top level of a git repository.\n"; } -my $vtemp = `git config --local --get nethack.setupversion`; -chomp($vtemp); -if($vtemp > 0){ - $version_old = 0+$vtemp; - if($version_old != $version_new){ - print STDERR "Migrating from setup version $version_old to $version_new\n" if($opt_v); - } +if($version_old >= $version_new and !opt_f){ + print STDERR "Nothing to do.\n"; + exit 0; } -# legacy check: -if(length $vtemp == 0){ - if(`git config --get merge.NHsubst.name` =~ m/^Net/){ - $version_old = 1; - print STDERR "Migrating to setup version 1\n" if($opt_v); + +if($version_old > 0){ + if($version_old != $version_new){ + print STDERR "Migrating from setup version $version_old to $version_new\n"; + if(length $message_new){ + print STDERR "Additional information:\n$message_new\n"; } + } +} + + +# legacy check: +if(length $version_old == 0){ + if(`git config --get merge.NHsubst.name` =~ m/^Net/){ + $version_old = 1; + print STDERR "Migrating to setup version 1\n" if($opt_v); + } } my $gitadddir = `git config --get nethack.gitadddir`; chomp($gitadddir); if(length $gitadddir){ - if(! -d $gitadddir){ - die "nethack.gitadddir has invalid value '$gitadddir'\n"; - } + if(! -d $gitadddir){ + die "nethack.gitadddir has invalid value '$gitadddir'\n"; + } } print STDERR "nethack.gitadddir=$gitadddir\n" if($opt_v); # This is (relatively) safe because we know we're at R in R/DEVEL/nhgitset.pl my $srcdir = ($0 =~ m!^(.*)$DS!)[0]; +#XXX do I really want a full path for srcdir? how badly? + if(! -f catfile($srcdir, 'nhgitset.pl')){ - die "I can't find myself in '$srcdir'\n"; + die "I can't find myself in '$srcdir'\n"; } print STDERR "Copying from: $srcdir\n" if($opt_v); if($opt_f || $version_old==0){ - print STDERR "Configuring line endings\n" if($opt_v); - unlink catfile('.git','index') unless($opt_n); - system("git reset") unless($opt_n); - system("git config --local core.safecrlf true") unless($opt_n); - system("git config --local core.autocrlf false") unless($opt_n); + print STDERR "Configuring line endings\n" if($opt_v); + system("git reset") unless($opt_n); + &add_config('core.safecrlf', 'true') unless($opt_n); + &add_config('core.autocrlf', 'false') unless($opt_n); } elsif($version_old <2){ - my $xx = `git config --get --local core.safecrlf`; - if($xx !~ m/true/){ - print STDERR "\nNeed to 'rm .git${DSP}index;git reset'.\n"; - print STDERR " When ready to proceed, re-run with -f flag.\n"; - exit 2; - } + my $xx = `git config --get --local core.safecrlf`; + if($xx !~ m/true/){ + print STDERR "\nNeed to 'rm .git${PDS}index;git reset'.\n"; + print STDERR " When ready to proceed, re-run with -f flag.\n"; + exit 2; + } } - - print STDERR "Installing aliases\n" if($opt_v); $addpath = catfile(curdir(),'.git','hooks','NHadd'); &add_alias('nhadd', "!$addpath add"); + &add_help('nhadd', 'NHadd'); &add_alias('nhcommit', "!$addpath commit"); + &add_help('nhcommit', 'NHadd'); my $nhsub = catfile(curdir(),'.git','hooks','nhsub'); &add_alias('nhsub', "!$nhsub"); + &add_help('nhsub', 'nhsub'); +&add_alias('nhhelp', '!'.catfile(curdir(),'.git','hooks','nhhelp')); + &add_help('nhhelp', 'nhhelp'); + +&add_help('NHsubst', 'NHsubst'); +&add_help('NHgithook', 'NHgithook.pm'); -print STDERR "Installing filter/merge\n" if($opt_v); -# XXXX need it in NHadd to find nhsub??? # removed at version 3 +#print STDERR "Installing filter/merge\n" if($opt_v); #if($^O eq "MSWin32"){ # $cmd = '.git\\\\hooks\\\\NHtext'; #} else { @@ -117,170 +165,183 @@ print STDERR "Installing filter/merge\n" if($opt_v); #&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 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); + print STDERR "Removing NHtext\n" if($opt_v); + unlink catfile(curdir(),'.git','hooks','NHtext') unless($opt_n); } +&add_config('nethack.setuppath',$srcdir); +&add_config('nethack.is-sourcerepo',0+$is_sourcerepo); + $cmd = catfile(curdir(),'.git','hooks','NHsubst'); &add_config('merge.NHsubst.name', 'NetHack Keyword Substitution'); &add_config('merge.NHsubst.driver', "$cmd %O %A %B %L"); print STDERR "Running directories\n" if($opt_v); -foreach my $dir ( glob("$srcdir$DS*") ){ - next unless(-d $dir); +# copy directories into .git (right now that's just hooks +my @gitadd = length($gitadddir)?glob("$gitadddir$DS*"):undef; +foreach my $dir ( (glob("$srcdir$DS*"), @gitadd) ){ + next unless(-d $dir); - my $target = catfile($dir, 'TARGET'); - next unless(-f $target); + my $target = catfile($dir, 'TARGET'); + next unless(-f $target); - open TARGET, '<', $target or die "$target: $!"; - my $targetpath = ; - # still have to eat all these line endings under msys, so instead of chomp use this: - $targetpath =~ s![\r\n]!!g; - close TARGET; - print STDERR "Directory $dir -> $targetpath\n" if($opt_v); + open TARGET, '<', $target or die "$target: $!"; + my $targetpath = ; + # still have to eat all these line endings under msys, so instead of chomp use this: + $targetpath =~ s![\r\n]!!g; + close TARGET; + print STDERR "Directory $dir -> $targetpath\n" if($opt_v); - my $enddir = $dir; - $enddir =~ s!.*$DS!!; - if(! &process_override($enddir, "INSTEAD")){ - &process_override($enddir, "PRE"); - my $fnname = "do_dir_$enddir"; - if(defined &$fnname){ - &$fnname($dir, $targetpath); - } - &process_override($enddir, "POST"); + my $enddir = $dir; + $enddir =~ s!.*$DS!!; + if(! &process_override($enddir, "INSTEAD")){ + &process_override($enddir, "PRE"); + my $fnname = "do_dir_$enddir"; + if(defined &$fnname){ + &$fnname($dir, $targetpath); } + &process_override($enddir, "POST"); + } } -&check_prefix; # for variable substitution +&check_gitvars; # for variable substitution -if($version_old != $version_new){ - print STDERR "Setting version to $version_new\n" if($opt_v); - if(! $opt_n){ - system("git config nethack.setupversion $version_new"); - if($?){ - die "Can't set nethack.setupversion $version_new: $?,$!\n"; - } - } +if($version_old != $version_new or $opt_f){ + print STDERR "Setting version to $version_new\n" if($opt_v); + NHgithook::version_set_git($version_new) if(! $opt_n); } exit 0; -sub process_override { - my($srcdir, $plname) = @_; - return 0 unless(length $gitadddir); +sub add_help { + my($cmd, $file) = @_; - my $plpath = catfile($gitadddir, $srcdir, $plname); -#print STDERR " ",catfile($srcdir, $plname),"\n"; # save this for updating docs - list of overrides - return 0 unless(-x $plpath); - - print STDERR "Running $plpath\n" if($opt_v); - # current directory is top of target repo - - unless($opt_n){ - system("$plpath $opt_v") and die "Callout $plpath failed: $?\n"; + &add_config("nethack.aliashelp.$cmd", $file); + # pull out =for nhgitset CMD description... + my $desc = ''; + open my $fh, "<", "$DEVhooksdir/$file"; + if($fh){ + while(<$fh>){ + m/^=for\s+nhgitset\s+\Q$cmd\E\s+(.*)/ && do { + $desc = $1; + last; + } } - return 1; + close $fh; + } else { + warn "Can't open: '$DEVhooksdir/$file' ($!)\n"; + } + + if(length $desc){ + &add_config("nethack.aliasdesc.$cmd", $desc); + } else { + &add_config("nethack.aliasdesc.$cmd", "(no description available)"); + } +} + +sub process_override { + my($srcdir, $plname) = @_; + return 0 unless(length $gitadddir); + + my $plpath = catfile($gitadddir, $srcdir, $plname); + return 0 unless(-x $plpath); + + print STDERR "RunningOverride $plpath\n" if($opt_v); + + # current directory is top of target repo + unless($opt_n){ + system("$plpath $opt_v") and die "Callout $plpath failed: $?\n"; + } + return 1; } sub add_alias { - my($name, $def) = @_; - &add_config("alias.$name",$def); + my($name, $def) = @_; + &add_config("alias.$name",$def); } sub add_config { - my($name, $val) = @_; - system('git', 'config', '--local', $name, $val) unless($opt_n); + my($name, $val) = @_; + system('git', 'config', '--local', $name, $val) unless($opt_n); +} + +sub check_gitvars { + &check_prefix("substprefix"); + &check_prefix("projectname"); } sub check_prefix { - my $lcl = `git config --local --get nethack.substprefix`; - chomp($lcl); - if(0==length $lcl){ - my $other = `git config --get nethack.substprefix`; - chomp($other); - if(0==length $other){ - print STDERR "ERROR: nethack.substprefix is not set anywhere. Set it and re-run.\n"; - exit 2; - } else { - &add_config('nethack.substprefix', $other); - print STDERR "Copying prefix '$other' to local repository.\n" if($opt_v); - } - $lcl = $other; # for display below + my $which = $_[0]; + my $lcl = `git config --local --get nethack.$which`; + chomp($lcl); + if(0==length $lcl){ + my $other = `git config --get nethack.$which`; + chomp($other); + if(0==length $other){ + print STDERR "ERROR: nethack.$which is not set anywhere. Set it and re-run.\n"; + exit 2; + } else { + &add_config('nethack.$which', $other); + print STDERR "Copying prefix '$other' to local repository.\n" if($opt_v); } - print "\n\nUsing prefix '$lcl' - PLEASE MAKE SURE THIS IS CORRECT\n\n"; + $lcl = $other; # for display below + } + print "Using $which '$lcl' - PLEASE MAKE SURE THIS IS CORRECT\n"; } sub do_dir_DOTGIT { -if(1){ - # We are NOT going to mess with config now. - return; -} else { - my($srcdir, $targetdir) = @_; -#warn "do_dir_DOTGIT($srcdir, $targetdir)\n"; - my $cname = "$srcdir/config"; - if(-e $cname){ - print STDERR "Appending to .git/config\n" if($opt_v); - open CONFIG, ">>.git/config" or die "open .git/config: $!"; - open IN, "<", $cname or die "open $cname: $!"; - my @data = ; - print CONFIG @data; - close IN; - close CONFIG; - } else { - print STDERR " Nothing to add to .git/config\n" if($opt_v); - } -# XXX are there other files in .git that we might want to handle? -# So just in case: - for my $file ( glob("$srcdir/*") ){ - next if( $file =~ m!.*/TARGET$! ); - next if( $file =~ m!.*/config$! ); - die "ERROR: no handler for $file\n"; - } -} + my($srcdir, $targetdir) = @_; + # not currently in use so just bail + return; + # are there other files in .git that we might want to handle? + # So just in case: + for my $file ( glob("$srcdir/*") ){ + next if( $file =~ m!.*/TARGET$! ); + next if( $file =~ m!.*/config$! ); + die "ERROR: no handler for $file\n"; + } } sub do_dir_hooksdir { - my($srcdir, $targetdir) = @_; + my($srcdir, $targetdir) = @_; - unless (-d $targetdir){ + unless (-d $targetdir){ # Older versions of git, when cloning a repo and # the expected source templates directory does not # exist, does not create .git/hooks. So do it here. - mkdir $targetdir; - print STDERR "WARNING: .git/hooks had to be created.\n"; - print STDERR " You may want to update git.\n"; + mkdir $targetdir; + print STDERR "WARNING: .git/hooks had to be created.\n"; + print STDERR " You may want to update git.\n"; + } + + for my $path ( glob("$srcdir$DS*") ){ + next if( $path =~ m!.*${DS}TARGET$! ); + + my $file = $path; + + $file =~ s!.*$DS!!; + $file = catfile($targetdir, $file); + + next if($opt_n); + + open IN, "<", $path or die "Can't open $path: $!"; + open OUT, ">", "$file" or die "Can't open $file: $!"; + while(){ + print OUT; } + close OUT; + close IN; - for my $path ( glob("$srcdir$DS*") ){ - - next if( $path =~ m!.*${DS}TARGET$! ); - - my $file = $path; - - $file =~ s!.*$DS!!; - - $file = catfile($targetdir, $file); - - next if($opt_n); - - open IN, "<", $path or die "Can't open $path: $!"; - open OUT, ">", "$file" or die "Can't open $file: $!"; - while(){ - print OUT; - } - close OUT; - close IN; - - if(! -x $file){ - chmod 0755 ,$file; - } + if(! -x $file){ + chmod 0755 ,$file; } + } } __END__ @@ -308,11 +369,29 @@ nhgitset.pl). The following options are available: -B<-f> Force. Do not use this unless the program requests it. +=over -B<-n> Make no changes. +=item B<-f> -B<-v> Verbose output. +Force. Do not use this unless the program requests it or the hooks are broken. + +=back + +=over + +=item B<-n> + +Dry-run - make no changes. + +=back + +=over + +=item B<-v> + +Verbose output. + +=back =head1 CONFIG @@ -329,8 +408,35 @@ nethack.gitadddir nethack.setupversion + The version for nhgitset.pl and friends; has no relationship + to NetHack version numbers. + nethack.substprefix + The prefix this repo uses for variable substitution. + +nethack.projectname + + The name of the game being built - see C. + +nethack.is-sourcerepo + + Does this repo contain NetHack source code? (1 = yes, 0 = no) + +nethack.setuppath + + Path to (and including) the DEVEL directory used including the + copy of nhgitset.pl used to set up this repo. + +nethack.aliashelp.* + + The last element of the variable is the name used with C + and the value is the name of a file to display with C. + +nethack.aliasdesc.* + + The last element of the variable is the name used with C + and the value is short help displayed with C. =head1 EXIT STATUS diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 549f9c0b7..e850311e9 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.574 $ $NHDT-Date: 1711040379 2024/03/21 16:59:39 $ +.\" $NHDT-Branch: keni-gitset $:$NHDT-Revision: 1.593 $ $NHDT-Date: 1730681007 2024/11/04 00:43:27 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\"+-- @@ -46,8 +46,8 @@ .ds vr NetHack 3.7.0 .ds f0 \*(vr .ds f1 \" empty -.\"DO NOT REMOVE NH_DATESUB .ds f2 DATE(%B %-d, %Y) -.ds f2 September 13, 2024 +.\"DO NOT REMOVE NH_DATESUB .ds f2 Date(%B %-d, %Y) +.ds f2 November 4, 2024 . .\" A note on some special characters: .\" \(lq = left double quote @@ -6671,3 +6671,4 @@ Izchak Miller Mike Stephenson .sm "Brand and product names are trademarks or registered trademarks \ of their respective holders." .\"EOF +changes diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index d71cbd330..d9e2ebeb9 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -47,7 +47,7 @@ %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7.0 by Mike Stephenson and others)} -%DO NOT REMOVE NH_DATESUB \date{DATE(%B %-d, %Y)} +%DO NOT REMOVE NH_DATESUB \date{Date(%B %-d, %Y)} \date{September 13, 2024} \maketitle diff --git a/doc/dlb.6 b/doc/dlb.6 index 785120aa2..058c6b42f 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -1,16 +1,16 @@ -.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ $NHDT-Date: 1693253316 2023/08/28 20:08:36 $ -.\"DO NOT REMOVE NH_DATESUB .TH DLB 6 "DATE(%-d %B %Y)" NETHACK -.TH DLB 6 "8 February 2022" NETHACK +.\" $NHDT-Branch: keni-gitset $:$NHDT-Revision: 1.13 $ $NHDT-Date: 1730949315 2024/11/06 22:15:15 $ +.\"DO NOT REMOVE NH_DATESUB .TH DLB 6 "DATE(%-d %B %Y)" Project(uc) +.TH DLB 6 "DATE(%-d %B %Y)" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) -.ds Nd 2022 +.ds Nd DATE(%Y) .de NB .ds Nb \\$2 .. .de NR .ds Nr \\$2 .. -.NB $NHDT-Branch: NetHack-3.7 $ -.NR $NHDT-Revision: 1.12 $ +.NB $NHDT-Branch: keni-gitset $ +.NR $NHDT-Revision: 1.13 $ .ds Na Kenneth Lorber .SH NAME dlb \- NetHack data librarian diff --git a/doc/makedefs.6 b/doc/makedefs.6 index 1c2129f7d..4c4a65dd6 100644 --- a/doc/makedefs.6 +++ b/doc/makedefs.6 @@ -1,4 +1,4 @@ -.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "DATE(%-d %B %Y)" NETHACK +.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "DATE(%-d %B %Y)" Project(uc) .TH MAKEDEFS 6 "8 February 2022" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) .ds Nd 2022 diff --git a/doc/nethack.6 b/doc/nethack.6 index 478f99f5d..735ffa46e 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -1,4 +1,4 @@ -.\"DO NOT REMOVE NH_DATESUB .TH NETHACK 6 "DATE(%-d %B %Y)" NETHACK +.\"DO NOT REMOVE NH_DATESUB .TH NETHACK 6 "DATE(%-d %B %Y)" Project(uc) .TH NETHACK 6 "21 February 2022" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) .ds Nd 2022 diff --git a/doc/recover.6 b/doc/recover.6 index b94efda65..9972ff6d6 100644 --- a/doc/recover.6 +++ b/doc/recover.6 @@ -1,4 +1,4 @@ -.\"DO NOT REMOVE NH_DATESUB .TH RECOVER 6 "DATE(%-d %B %Y)" NETHACK +.\"DO NOT REMOVE NH_DATESUB .TH RECOVER 6 "DATE(%-d %B %Y)" Project(uc) .TH RECOVER 6 "8 February 2022" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) .ds Nd 2022 diff --git a/sys/windows/build-msys2.txt b/sys/windows/build-msys2.txt index c9efc6859..4ce421f2e 100644 --- a/sys/windows/build-msys2.txt +++ b/sys/windows/build-msys2.txt @@ -11,6 +11,8 @@ Prerequisite Requirements: pacman -S make pacman -S vim (or your editor of choice) pacman -S man (otherwise "git help foo" will not work) + pacman -S perl-doc (otherwise "git nhhelp foo" will not work, + so only needed if you use nhgitset.pl) o Lua o pdcursesmod (Only required if curses interface support is desired) Instructions for obtaining these are later in this file.