+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; };
+}
+