chiark / gitweb /
Dgit.pm: in_workarea: Use changedir
[dgit.git] / Debian / Dgit.pm
index dcecbd1a840e7f0c7718b398d585e2e4d4e3fe77..399aaad4d029e3a2d4ce28b04cefad02c335d5e5 100644 (file)
@@ -29,6 +29,8 @@ use Config;
 use Digest::SHA;
 use Data::Dumper;
 use IPC::Open2;
+use File::Path;
+use File::Basename;
 
 BEGIN {
     use Exporter   ();
@@ -45,7 +47,7 @@ BEGIN {
                       fail ensuredir executable_on_path
                       waitstatusmsg failedcmd_waitstatus
                      failedcmd_report_cmd failedcmd
-                      cmdoutput cmdoutput_errok
+                      runcmd cmdoutput cmdoutput_errok
                       git_rev_parse git_cat_file
                      git_get_ref git_for_each_ref
                       git_for_each_tag_referring is_fast_fwd
@@ -55,10 +57,14 @@ BEGIN {
                       initdebug enabledebug enabledebuglevel
                       printdebug debugcmd
                       $debugprefix *debuglevel *DEBUG
-                      shellquote printcmd messagequote);
+                      shellquote printcmd messagequote
+                      $negate_harmful_gitattrs
+                     changedir git_slurp_config_src
+                     workarea_setup
+                     fresh_workarea in_workarea);
     # implicitly uses $main::us
     %EXPORT_TAGS = ( policyflags => [qw(NOFFCHECK FRESHREPO NOCOMMITCHECK)] );
-    @EXPORT_OK   = @{ $EXPORT_TAGS{policyflags} };
+    @EXPORT_OK   = ( qw($wa), @{ $EXPORT_TAGS{policyflags} } );
 }
 
 our @EXPORT_OK;
@@ -82,6 +88,8 @@ sub NOCOMMITCHECK () { return 0x8; }
 our $debugprefix;
 our $debuglevel = 0;
 
+our $negate_harmful_gitattrs = "-text -eol -crlf -ident -filter";
+
 our $forkcheck_mainprocess;
 
 sub forkcheck_setup () {
@@ -276,6 +284,12 @@ sub failedcmd {
     fail failedcmd_waitstatus();
 }
 
+sub runcmd {
+    debugcmd "+",@_;
+    $!=0; $?=-1;
+    failedcmd @_ if system @_;
+}
+
 sub cmdoutput_errok {
     confess Dumper(\@_)." ?" if grep { !defined } @_;
     debugcmd "|",@_;
@@ -406,4 +420,83 @@ sub is_fast_fwd ($$) {
     }
 }
 
+sub changedir ($) {
+    my ($newdir) = @_;
+    printdebug "CD $newdir\n";
+    chdir $newdir or confess "chdir: $newdir: $!";
+}
+
+sub git_slurp_config_src ($) {
+    my ($src) = @_;
+    # returns $r such that $r->{KEY}[] = VALUE
+    my @cmd = (qw(git config -z --get-regexp), "--$src", qw(.*));
+    debugcmd "|",@cmd;
+
+    local ($debuglevel) = $debuglevel-2;
+    local $/="\0";
+
+    my $r = { };
+    open GITS, "-|", @cmd or die $!;
+    while (<GITS>) {
+       chomp or die;
+       printdebug "=> ", (messagequote $_), "\n";
+       m/\n/ or die "$_ ?";
+       push @{ $r->{$`} }, $'; #';
+    }
+    $!=0; $?=0;
+    close GITS
+       or ($!==0 && $?==256)
+       or failedcmd @cmd;
+    return $r;
+}
+
+sub workarea_setup ($) {
+    # for use in the workarea
+    my ($t_local_git_cfg) = @_;
+    # should be run in a directory .git/FOO/BAR of a working tree
+    runcmd qw(git init -q);
+    runcmd qw(git config gc.auto 0);
+    foreach my $copy (qw(user.email user.name user.useConfigOnly
+                         core.sharedRepository
+                         core.compression core.looseCompression
+                         core.bigFileThreshold core.fsyncObjectFiles)) {
+       my $v = $t_local_git_cfg->{$copy};
+       next unless $v;
+       runcmd qw(git config), $copy, $_ foreach @$v;
+    }
+    rmtree('.git/objects');
+    symlink '../../../../objects','.git/objects' or die $!;
+    ensuredir '.git/info';
+    open GA, "> .git/info/attributes" or die $!;
+    print GA "* $negate_harmful_gitattrs\n" or die $!;
+    close GA or die $!;
+}
+
+our $wa;
+our $local_git_cfg;
+
+sub in_workarea ($;$) {
+    my $sub = pop @_; # in_workarea [$twa, sub { ... };]
+    # default $twa is global $wa (which caller must, in that case, set)
+    # $twa should be relative paths of the form .git/FOO/BAR
+    my ($twa) = @_;
+    $twa //= $wa;
+    changedir $twa or die "$twa $!";
+    my $r = eval { $sub->($twa); };
+    changedir '../../..' or die "$@; $!";
+    die $@ if length $@;
+    return $r;
+}
+
+sub fresh_workarea (;$) {
+    my ($twa) = @_;
+    $twa //= $wa;
+    $local_git_cfg //= git_slurp_config_src 'local';
+    my $parent = dirname $twa;
+    mkdir $parent or $!==EEXIST or fail "failed to mkdir $parent: $!";
+    rmtree $twa;
+    mkdir $twa or die "$twa $!";
+    in_workarea sub { workarea_setup $local_git_cfg; };
+}
+
 1;