initial git setup

This commit is contained in:
keni
2015-02-11 19:42:57 -05:00
parent 5cc7f32044
commit 34221670bc
24 changed files with 1612 additions and 0 deletions

5
.gitattributes vendored Normal file
View File

@@ -0,0 +1,5 @@
*.[ch] filter=NHtext merge=NHsubst
* text=auto
*.hqx -text
*.sln -text
*.vcxproj -text

BIN
DEVEL/.gitattributes.swp Normal file

Binary file not shown.

1
DEVEL/DOTGIT/TARGET Normal file
View File

@@ -0,0 +1 @@
.git

164
DEVEL/Developer.txt Normal file
View File

@@ -0,0 +1,164 @@
___ _
| \ _____ _____| |___ _ __ ___ _ _
| |) / -_) V / -_) / _ \ '_ \/ -_) '_|
|___/\___|\_/\___|_\___/ .__/\___|_|
|_|
$NHDT-Date$
Welcome to the NetHack Infrastructure Developer's Guide.
This is the info you need if you are developing code for NetHack.
(This information is from DevTeam. If you are working with a variant please
check for additional documentation for that variant.)
For information on building NetHack, see README in the top level directory.
For information on playing NetHack, see the Guidebook in the doc directory.
DANGER! WORK IN PROGRESS! Known issues marked XXX.
CONTENTS
1. email
2. git repositories
3. bug reporting
4. git configuration
5. variable expansion
6. reserved names
------------------------------------------------------------------------------
1. email
Email to devteam@nethack.org will usually get a response, but it may take a
while. Please do not send save files, binary screen grabs, or other large
things.
------------------------------------------------------------------------------
2. git repositories
The public NetHack git repository is available (read-only) on SourceForge at:
git://git.code.sf.net/p/nethack/NHsource
------------------------------------------------------------------------------
3. bug reporting
Please use the form at http://www.nethack.org/common/contact.html (or send
us an email if that's more appropriate).
------------------------------------------------------------------------------
4. git configuration
A. If you have never set up git on this machine before:
(This assumes you will only be using git for NetHack. If you are going to
use it for other projects as well, think before you type.)
Tell git what name (or nicname) and email address to use for you:
git config --global user.name "MY NAME"
git config --global user.email USER@EXAMPLE.COM
You probably want to set up a credential cache.
Mac OS X:
git config --global credential.helper osxkeychain
XXX windows
XXX linux
B. Specify the prefix for variable substitution:
(This assumes you are not a member of DevTeam or any variant's development
team. If you are, this may be wrong. Look for more specific documentation.)
Decide where you want to put this info; it should NOT be inside the
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):
#!/bin/sh
git config nethack.substprefix MINE
C. Configure the repository:
- cd to the top level of the repository
- tell the repository about the directory you created above:
git config nethack.gitadddir FULL_PATH_TO_GITADDDIR
so for the example above:
git config nethack.gitadddir ~/nethack/GITADDDIR
- do the automated setup:
perl DEVEL/nhgitset.pl
If it complains, fix what it complains about. nhgitset.pl accepts
the following options:
-v verbose
-n dry run
You can re-run nhgitset.pl as often as needed; occasionally we will
update it and ask you to run it again.
D. aliases
Two aliases are installed by nhgitset.pl:
nhadd
nhcommit
These two commands take the same options as the normal git add and commit
commands but perform RCS/CVS-style variable substitution. Note that the
substitutions do not show up in the working directory.
Note that nothing terrible will happen if you do not use the nh* versions
of the commands.
Supported substitutions:
MINE-Date the commit time and date
Experimental substitutions:
MINE-Revision CVS style revision number
MINE-Branch the current git branch
That's it. If you need to do something more when setting up your repository,
keep reading. Otherwise, you are done with this section.
1) to run your own hooks in addition to ours:
name your hook
WHEN-HOOKNAME
where WHEN is
PRE (run your code before the NetHack hook)
POST (run your code after the NetHack hook)
and HOOKNAME is the normal git name of the hook.
Be sure to test carefully since the composition of two bits of code may or
may not do what you want.
2) to install other bits on setup:
Put additional files in the GITADDDIR tree. Use "DOTGIT" instead of
".git". If a file called PRE, POST, or INSTEAD exists in a
subdirectory of GITADDDIR, it is run before the copy, after the copy,
or instead of the copy. No copy operation is attempted in the DOTGIT
directory; use a script and standard git commands to change the
contents as needed.
3) NB: In all namespaces, anything that matches m/^nh/i or m/^nethack/i is
reserved.
------------------------------------------------------------------------------
5. variable expansion
A. Introduction
We have implemented an RCS/CVS/SVN style variable expansion mechanism.
References of either of the formats:
$PREFIX-VARNAME$
$PREFIX-VARNAME: VALUE $
will be handled (if enabled).
The PREFIX is the value in the git config variable nethack.substprefix.
VARNAME is one of:
Date
Branch (experimental)
Revision (experimental)
other names will give a warning.
B. Enabling variable expansion
Variable expansion is controlled by the .gitattributes file.
To enable variable expansion:
pattern filter=NHtext merge=NHsubst
To disable variable expansion:
pattern -filter
More information: "git help gitattributes"
C. Oddities
To trigger variable expansion, you _must_ use "git nhadd" or "git nhcommit"
instead of "git add" or "git commit." Nothing terrible will happen if you
use the wrong one, but the values will not be updated.
Due to the way this abuses git filters, the updated values are not visible
in your working tree.
D. Using your own hooks
You can use your own hooks - put them in .git/hooks as usual BUT name them
as follows:
WHEN-HOOKNAME
where WHEN is:
PRE (execute the code before the NetHack hook)
POST (execute the code after the NetHack hook)
and HOOKNAME is the normal git name for the hook.
Test carefully - interactions between hooks can be nasty.
------------------------------------------------------------------------------
6. reserved names
Anything that matches m/^nh/i or m/^nethack/i is reserved in all
namespaces (environment, file names, git config, etc).
------------------------------------------------------------------------------

Binary file not shown.

14
DEVEL/hooksdir/NHadd Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/perl
# wrapper for nhadd and nhcommit aliases
# $NHDT-Date$
%ok = map { $_ => 1 } ('add', 'commit');
die "Bad subcommand '$ARGV[0]'" unless $ok{$ARGV[0]};
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: $!";

205
DEVEL/hooksdir/NHgithook.pm Normal file
View File

@@ -0,0 +1,205 @@
#
# NHgithook.pm
# NetHack Git Hook Module
# $NHDT-Date$
package NHgithook;
use Cwd;
###
### CONFIG
###
my $trace = 0;
my $tracefile = "/tmp/nhgitt.$$";
# OS hackery
my $DS = quotemeta('/');
if ($^O eq "MSWin32")
{
$DS = quotemeta('\\');
}
our %saved_env;
our @saved_argv;
our $saved_input;
sub saveSTDIN {
@saved_input = <STDIN>;
if($trace){
print TRACE "STDIN:\n";
print TRACE $saved_input;
print TRACE "ENDSTDIN\n";
}
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 = <STDIN> )
sub resetSTDIN{
my $x = tied(*STDIN);
my %x = %$x;
my $data = @$x{DATA};
untie *STDIN;
tie *STDIN, 'NHIO::STDIN', $data;
}
# don't need this now
#sub restore {
# open STDIN, "<", \$saved_input or die "reopen STDIN: $!";
# @ARGV = @saved_argv;
# %ENV = %saved_env;
#}
sub PRE {
&do_hook("PRE");
}
sub POST {
&do_hook("POST");
}
# 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);
open TOHOOK, "|-", $hname or die "open $hname: $!";
print TOHOOK <STDIN>;
close TOHOOK or die "close $hname: $! $?";
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<scalar @ARGV;$x++){
$x1 = $x+1;
print TRACE "[$x1] $ARGV[$x]\n";
}
print TRACE "ENV:\n";
foreach my $k (sort keys %ENV){
next unless ($k =~ m/(^GIT_)|(^NH)/);
print TRACE " $k => $ENV{$k}\n";
}
}
BEGIN {
%saved_env = %ENV;
@saved_argv = @ARGV;
&trace_start;
}
###
### ugly mess so we can re-read STDIN
###
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;
}
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;
}
}
}
sub EOF {
$self = shift;
return $self->{EOF};
}
1;
__END__
=head1 NAME
NHgithook - common code for NetHack git hooks (and other git bits)
=head1 SYNOPSIS
BEGIN {
my $DS = quotemeta('/');
my $PDS = '/';
if ($^O eq "MSWin32")
{
$DS = quotemeta('\\');
$PDS = '\\';
}
push(@INC, $ENV{GIT_DIR}.$PDS."hooks"); # for most hooks
push(@INC, ($0 =~ m!^(.*)$DS!)[0]); # when the above doesn't work
$gitdir = `git rev-parse --git-dir`; # and when the above really doesn't work
$gitdir =~ s/[\r\n]*$/;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
&NHgithook::saveSTDIN;
&NHgithook::PRE;
(core hook code)
&NHgithook::POST;
=head1 DESCRIPTION
Buffers call information so multiple independent actions may be coded for
Git hooks and similar Git callouts.
=head1 SETUP
Changing the C<$trace> and C<$tracefile> variables requires editing the
module source. Setting C<$trace> enables tracing, logs basic information,
and leaves the C<TRACE> filehandle open for additional output; output to this
filehandle must be guarded by C<$NHgithook::trace>. Setting
C<$tracefile> specifies the file used for trace output. Note that C<$$>
may be useful since multiple processes may be live at the same time.
=head1 FUNCTIONS
NHgithook::saveSTDIN reads STDIN until EOF and saves it
NHgithook::PRE runs the PRE hook, if it exists
NHgithook::POST runs the POST hook, if it exists
=head1 BUGS
Some features not well tested, especially under Windows.
=head1 AUTHOR
Kenneth Lorber (keni@his.com)

366
DEVEL/hooksdir/NHsubst Executable file
View File

@@ -0,0 +1,366 @@
#!/usr/bin/perl
#
# NHsubst
# $NHDT-Date$
# git merge driver for substitutions (like RCS/CVS)
# driver line: .... %O %A %B %L
use strict;
my $debug = 0;
my $rawin = 0; # feed diff to stdin for testing (do NOT set $debug=1)
# We want TRACE open so we don't need to test $debug everywhere, but we skip
# this first block because it's expensive and dumpfile() hangs with $rawin.
my $sink = ($^O eq "MSWin32") ? "NUL" : "/dev/null";
my $dbgfile = ($^O eq "MSWin32") ? "$ENV{TEMP}.$$" : "/tmp/trace.$$";
open TRACE, ">>", ($debug==0)? $sink : $dbgfile;
if($debug){
print TRACE "START CLIENT ARGV:\n";
print TRACE "[0] $0\n";
my $x1;
for(my $x=0;$x<scalar @ARGV;$x++){
$x1 = $x+1;
print TRACE "[$x1] $ARGV[$x]\n";
}
print TRACE "ENV:\n";
foreach my $k (sort keys %ENV){
next unless ($k =~ m/^GIT_/);
print TRACE " $k => $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];
$mark_len = 3 if($mark_len==0 && $rawin);
my $mark_start = '<' x $mark_len;
my $mark_middle = '=' x $mark_len;
my $mark_end = '>' x $mark_len;
my $PREFIX;
# pick up the prefix for substitutions in this repo
if($rawin){
$PREFIX = "TEST";
} else {
$PREFIX = `git config --local --get nethack.substprefix`;
chomp($PREFIX);
}
my @out;
my $cntout;
if($rawin){
@out = <STDIN>;
} 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]`;
#NB: we don't check the exit value because it's useless
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;
} 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;
print TRACE "WRITING START ($ARGV[1])\n".join("",@out)."WRITING END\n";
&dumpfile($ARGV[1], "READBACK");
}
print TRACE "COUNT: $cntout\n";
exit( ($cntout>0) ? 1 : 0);
#git merge-file [-L <current-name> [-L <base-name> [-L <other-name>]]]
# [--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=<n>]
# [--[no-]diff3] <current-file> <base-file> <other-file>
#The `merge.*.driver` variable's value is used to construct a command to run to merge ancestor's
# version (%O), current version (%A) and the other branches' version (%B). These three tokens are
# replaced with the names of temporary files that hold the contents of these versions when the
# command line is built. Additionally, %L will be replaced with the conflict marker size (see
# below).
# 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";
}
sub edit_merge {
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, $_);
}
}
print TRACE "RETURN count=$::count\n";
return($::count, @out);
}
sub edit_conflict {
my(@in) = @_;
print TRACE "EDIT START: " . scalar(@in)."\n";
if($debug){
foreach my $x (@in){ my $xx = $x; chomp($xx); print TRACE "-$xx-\n"; }
}
print TRACE "EDIT END INPUT\n";
# one-line change - use as base case to develop the code
# ours ARGV[1] top-of-diff
# theirs ARGV[2] bottom-of-diff
# simple conflict:
# [0] <<<<<<< d1
# [1] $$PREFIX-Date: 1 ...
# [2] =======
# [3] $$PREFIX-Date: 3 ...
# [4] >>>>>>> d3
if(scalar(@in) == 5 && $in[2] =~ m/^$mark_middle/){
my $back = &merge_one_line_maybe($in[1],$in[3]); # (ours, theirs)
if(!defined $back){
$::count++; # leave the conflict
return @in;
} else {
return ($back);
}
# NOTREACHED
} else {
# XXX LATER
# Start at the top of both sections and work downwards. As long as the lines can be merged,
# push them out and keep going. If there are lines left, we will still have a conflict but
# we can try to make it smaller. Push out the start-conflict marker. Start at the
# bottom of both section and work upwards. As long as the lines can be merged, reverse push out
# the merged line and keep going. (We know there will be lines left at some point.) Push out
# remaining (middle) lines from OURS. Push out mark_middle. Push out remaining middle lines
# from THEIRS. Push out end-conflict marker. $::count++; return (@a,$b,@c,$d,@e,$f,@g)
# @a
# $b = <<<
# @c
# $d = ===
# @e
# $f = >>>
# @g
}
# not matched - return the unchanged conflict
$::count++;
return @in;
}
# XXX This is expensive. Add a quick check for "anything that looks like a subst var" and just
# declare the lines unmergeable if it fails.
sub merge_one_line_maybe {
my($ours, $theirs) = @_;
my $more = 1;
my $fail = 0;
my $out = '';
# TYPES:
# 0 no match
# 1 unexpanded var
# 2 expanded var
# 3 non-var text
my($ourstype, $theirtype);
my($oursvar, $theirvar);
my($oursval, $theirval);
while($more){
($ourstype, $theirtype) = (0,0);
($oursvar, $theirvar) = (undef, undef);
($oursvar, $theirvar) = (undef, undef);
# unexpanded var
if($ours =~ m/\G\$$PREFIX-([A-Z][a-z]+)\$/gc){
$ourstype = 1;
$oursvar = $1;
}
if($theirs =~ m/\G\$$PREFIX-([A-Z][a-z]+)\$/gc){
$theirtype = 1;
$theirvar = $1;
}
# expanded var
unless($ourstype){
if($ours =~ m/\G\$$PREFIX-([A-Za-z]+):\s+(.*?)\s\$/gc){
$ourstype = 2;
$oursvar = $1;
$oursval = $2;
}
}
unless($theirtype){
if($theirs =~ m/\G\$$PREFIX-([A-Za-z]+):\s+(.*?)\s\$/gc){
$theirtype = 2;
$theirvar = $1;
$theirval = $2;
}
}
# non-var text
unless($ourstype){
if($ours =~ m/\G(\$?[^\x24]*)/gc){
$ourstype = 3;
$oursval = $1;
}
}
unless($theirtype){
if($theirs =~ m/\G(\$?[^\x24]*)/gc){
$theirtype = 3;
$theirval = $1;
}
}
# are we done?
if(pos($ours)==length $ours && pos($theirs) == length $theirs){
$more = 0;
}
if($ourstype == 0 && $theirtype == 0){
die "NHsubst MERGE FAILED - aborted infinite loop\n";
}
# now see if ours and their match or can be resolved
# text
if($ourstype == 3 && $theirtype == 3){
if($oursval eq $theirval){
$out .= $oursval;
next;
}
return undef;
}
if($ourstype == 3 || $theirtype == 3){
return undef;
}
# XXX we could do better: on failure of one field, return 2 lines with the fields we _can_ fix
# substituted into those lines, leaving only the fail-to-match bits for the user to
# deal with. Later.
# vars (all 4 cases)
if($oursvar ne $theirvar){
return undef;
}
my $m = merge_one_var_maybe($oursvar, $oursval, $theirval);
if(! defined $m){
return undef;
}
$out .= $m;
}
return $out;
}
# return undef if we can't merge the values; $NAME: VALUE $ or $NAME$ (as appropriate) if we can.
sub merge_one_var_maybe {
my($varname, $oursval, $theirval) = @_;
my $resolvedas;
{
no strict;
my $fn = "PREFIX::$varname";
if(defined &$fn){
$resolvedas = &$fn($PREFIX,$varname,$oursval, $theirval);
} else {
$resolvedas = undef; # can't resolve
}
}
if(!defined $resolvedas){
$::count++; # we have an externally visible conflict
return undef;
} else {
return $resolvedas;
}
# NOTREACHED
}
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);
return "\$$PREFIX-$varname: " . (($m>$t)?$mine:$theirs) .' $';
}
#sub Header {
#sub Author {
sub Branch {
my($PREFIX, $varname, $mine, $theirs) = @_;
return "\$$PREFIX-$varname: $mine \$";
}
sub Revision {
my($PREFIX, $varname, $mine, $theirs) = @_;
return "\$$PREFIX-$varname: $mine \$";
}
__END__
TEST 1:
<<< d1
$TEST-Date: 1 $
===
$TEST-Date: 3 $
>>> d3
TEST 2:
nothing
at all
TEST 3:
<<< d1
a line
===
one line
two lines
>>> d3
TEST 4:
<<< d1
$TEST-Date: 1 $ yes
===
$TEST-Date: 1 $ no
>>> d3
TEST 5:
<<< d1
$TEST-Date: 3 $ yes
===
$TEST-Date: 1 $ yes
>>> d3
TEST 6:
<<< d1
$TEST-Date: 3 $ yes$TEST-Date: 4 $
===
$TEST-Date: 1 $ yes$TEST-Date: 5 $
>>> d3
TEST 7:
<<< d1
$TEST-Branch: mine $
===
$TEST-Branch: theirs $
>>> d3

145
DEVEL/hooksdir/NHtext Executable file
View File

@@ -0,0 +1,145 @@
#!/usr/bin/perl
#
# NHtext
# $NHDT-Date$
# clean/smudge filter for handling substitutions
use strict;
my $debug = 0;
my $sink = ($^O eq "MSWin32")? "NUL" :"/dev/null";
my $dbgfile = ($^O eq "MSWin32") ? "$ENV{TEMP}.$$" : "/tmp/trace.$$";
open TRACE, ">>", ($debug==0)? $sink : $dbgfile;
print TRACE "START CLIENT ARGV:\n";
print TRACE "[0] $0\n";
my $x1;
for(my $x=0;$x<scalar @ARGV;$x++){
$x1 = $x+1;
print TRACE "[$x1] $ARGV[$x]\n";
}
print TRACE "ENV:\n";
foreach my $k (sort keys %ENV){
next unless ($k =~ m/^(GIT_|NH)/);
print TRACE " $k => $ENV{$k}\n";
}
print TRACE "CWD: " . `pwd`;
print TRACE "END\n";
# pick up the prefix for substitutions in this repo
my $PREFIX = `git config --local --get nethack.substprefix`;
chomp($PREFIX);
my $submode = 0; # ok to make non-cleaning changes to file
my $mode;
if($ARGV[0] eq "--clean"){
$mode = "c";
if(0 == 0+$ENV{NHMODE}){
$submode = 1; # do NOT add extra changes to the file
print TRACE "SKIPPING\n";
}
} elsif($ARGV[0] eq "--smudge"){
$mode = "s";
} else {
warn "Unknown mode '$ARGV[0]'\n";
exit 1;
}
# XXX for now, there isn't any - if we get called, we subst. No options for now.
# get relevent config info
#XXX
#git check-attr -a $ARGV[1]
# process stdin to stdout
while(<STDIN>){
print TRACE "IN: $_";
# $1 - var and value (not including trailing $)
# $2 - var
# $4 - value or undef
# s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\N{DOLLAR SIGN}]+))?)\s*\$/&handlevar($2,$4)/eg;
s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\x24]+))?)\s*\$/&handlevar($2,$4)/eg;
print;
print TRACE "OT: $_";
}
sub handlevar {
my($var, $val) = @_;
my $subname = "PREFIX::$var";
if(defined &$subname){
no strict;
$val = &$subname($val,$mode,$submode);
} 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, $mode, $submode) = @_;
if($mode eq "c"){
if($submode==0){
# 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));
}
}
if($mode eq "s"){
$val =~ s/\s*$//; # XXX why do I need this?
}
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, $mode, $submode) = @_;
if($mode eq "c"){
if($submode==0){
$val = `git branch --no-color --contains`;
chomp($val); #XXX
$val =~ s/^\*\s*//;
}
}
if($mode eq "s"){
#XXX do we need this now?
$val =~ s/\s*$//; # XXX why do I need this?
}
return $val;
}
sub Revision {
my($val, $mode, $submode) = @_;
if($mode eq "c"){
if($submode==0){
my $file = $ARGV[1];
my @val = `git log --follow --oneline $file`;
$val = sprintf("1.%d",0+$#val);
}
}
if($mode eq "s"){
#XXX do we need this here?
$val =~ s/\s*$//; # XXX why do I need this?
}
return $val;
}
__END__

1
DEVEL/hooksdir/TARGET Normal file
View File

@@ -0,0 +1 @@
.git/hooks

30
DEVEL/hooksdir/applypatch-msg Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/commit-msg Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/post-applypatch Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/post-checkout Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/post-commit Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/post-merge Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

32
DEVEL/hooksdir/post-rewrite Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::saveSTDIN;
&NHgithook::PRE;
&NHgithook::resetSTDIN;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/pre-applypatch Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/pre-auto-gc Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/pre-commit Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

32
DEVEL/hooksdir/pre-push Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::saveSTDIN;
&NHgithook::PRE;
&NHgithook::resetSTDIN;
&NHgithook::POST;
exit 0;

30
DEVEL/hooksdir/pre-rebase Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

View File

@@ -0,0 +1,30 @@
#!/usr/bin/perl
# $NHDT-Date$
#STARTUP-START
BEGIN {
# OS hackery has to be duplicated in each of the hooks :/
# first the directory separator
my $DS = quotemeta('/');
my $PDS = '/';
# msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n).
# temporarily removed because inconsistent behavior
# if ($^O eq "msys")
# {
# $/ = "\r\n";
# $\ = "\r\n";
# }
if($^O eq "MSWin32"){
$DS = quotemeta('\\');
$PDS = '\\';
}
$gitdir = `git rev-parse --git-dir`;
chomp $gitdir;
push(@INC, $gitdir.$PDS."hooks");
}
use NHgithook;
#STARTUP-END
&NHgithook::PRE;
&NHgithook::POST;
exit 0;

317
DEVEL/nhgitset.pl Executable file
View File

@@ -0,0 +1,317 @@
#!/usr/bin/perl
# $NHDT-Date$
# 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_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 <<E_O_M;
File::Spec not found. (If you are running ActiveState Perl please run:
cpan File::Spec
and re-run this program.
E_O_M
}
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
# 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"){
# $/ = "\r\n";
# $\ = "\r\n";
# # 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"){
$DS = quotemeta('\\');
$DSP = '\\';
}
# 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";
}
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);
}
}
# 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);
}
}
my $gitadddir = `git config --get nethack.gitadddir`;
chomp($gitadddir);
if(length $gitadddir){
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];
if(! -f catfile($srcdir, 'nhgitset.pl')){
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);
} 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;
}
}
print STDERR "Installing aliases\n" if($opt_v);
$addpath = catfile(curdir(),'.git','hooks','NHadd');
&add_alias('nhadd', "!$addpath add");
&add_alias('nhcommit', "!$addpath commit");
print STDERR "Installing filter/merge\n" if($opt_v);
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");
$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);
my $target = catfile($dir, 'TARGET');
next unless(-f $target);
open TARGET, '<', $target or die "$target: $!";
my $targetpath = <TARGET>;
# 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");
}
}
&check_prefix; # 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";
}
}
}
exit 0;
sub process_override {
my($srcdir, $plname) = @_;
return 0 unless(length $gitadddir);
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";
}
return 1;
}
sub add_alias {
my($name, $def) = @_;
&add_config("alias.$name",$def);
}
sub add_config {
my($name, $val) = @_;
system('git', 'config', '--local', $name, $val) unless($opt_n);
}
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
}
print "\n\nUsing prefix '$lcl' - PLEASE MAKE SURE THIS IS CORRECT\n\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 = <IN>;
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";
}
}
}
sub do_dir_hooksdir {
my($srcdir, $targetdir) = @_;
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(<IN>){
print OUT;
}
close OUT;
close IN;
if(! -x $file){
chmod 0755 ,$file;
}
}
}
__END__
(can we change the .gitattributes syntax to include a comment character?)
maybe [comment] attr.c:parse_attr_line
grr - looks like # is the comment character
=head1 NAME
nhgitset.pl - Setup program for NetHack git repositories
=head1 SYNOPSIS
cd THE_REPO
[git config nethack.gitadddir GITADDDIR]
perl SOME_PATH/DEVEL/nhgitset.pl [-v][-n][-f]
=head1 DESCRIPTION
nhgitset.pl installs NetHack-specific setup after a C<git clone> (or after
changes to the desired configuration, which are installed by re-running
nhgitset.pl).
The follwing options are available:
B<-f> Force. Do not use this unless the program requests it.
B<-n> Make no changes.
B<-v> Verbose output.
=head1 CONFIG
nhgitset.pl uses the following non-standard C<git config> variables:
nethack.gitadddir
DOTGIT/INSTEAD
DOTGIT/PRE
DOTGIT/POST
hooksdir/INSTEAD
hooksdir/PRE
hooksdir/POST
nethack.setupversion
nethack.substprefix
=head1 EXIT STATUS
0 Success.
1 Fail.
2 Intervention required.