chiark / gitweb /
gitattributes: Suppress transformations in our cloned trees
[dgit.git] / dgit
diff --git a/dgit b/dgit
index afdf2c58ec8d13c7dc54e2444f6abd1b5412b147..db8d1f72bbbc8ed4aedab90868cc03d21970d6bc 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -34,7 +34,6 @@ use POSIX;
 use IPC::Open2;
 use Digest::SHA;
 use Digest::MD5;
-use List::Util qw(any);
 use List::MoreUtils qw(pairwise);
 use Text::Glob qw(match_glob);
 use Fcntl qw(:DEFAULT :flock);
@@ -70,7 +69,6 @@ our $overwrite_version; # undef: not specified; '': check changelog
 our $quilt_mode;
 our $quilt_modes_re = 'linear|smash|auto|nofix|nocheck|gbp|dpm|unapplied';
 our $dodep14tag;
-our $dodep14tag_re = 'want|no|always';
 our $split_brain_save;
 our $we_are_responder;
 our $we_are_initiator;
@@ -145,6 +143,7 @@ our %opts_cfg_insertpos = map {
 } keys %opts_opt_map;
 
 sub parseopts_late_defaults();
+sub setup_gitattrs(;$);
 
 our $keyid;
 
@@ -1699,6 +1698,7 @@ sub mktree_in_ud_here () {
     runcmd qw(git config gc.auto 0);
     rmtree('.git/objects');
     symlink '../../../../objects','.git/objects' or die $!;
+    setup_gitattrs();
 }
 
 sub git_write_tree () {
@@ -2557,7 +2557,7 @@ sub lrfetchref () { return lrfetchrefs.'/'.server_branch($csuite); }
 # (If we deleted them unconditionally, then we might end up
 # re-fetching the same git objects each time dgit fetch was run.)
 #
-# So, leach use of lrfetchrefs needs to be accompanied by arrangements
+# So, each use of lrfetchrefs needs to be accompanied by arrangements
 # in git_fetch_us to fetch the refs in question, and possibly a call
 # to lrfetchref_used.
 
@@ -2764,8 +2764,8 @@ sub git_fetch_us () {
        } elsif ($here{$lref} eq $objid) {
            lrfetchref_used $fullrefname;
        } else {
-           print STDERR \
-               "Not updateting $lref from $here{$lref} to $objid.\n";
+           print STDERR
+               "Not updating $lref from $here{$lref} to $objid.\n";
        }
     });
 }
@@ -2800,6 +2800,11 @@ sub fetch_from_archive_record_2 ($) {
     }
 }
 
+sub parse_dsc_field_def_dsc_distro () {
+    $dsc_distro //= cfg qw(dgit.default.old-dsc-distro
+                          dgit.default.distro);
+}
+
 sub parse_dsc_field ($$) {
     my ($dsc, $what) = @_;
     my $f;
@@ -2807,16 +2812,17 @@ sub parse_dsc_field ($$) {
        $f = $dsc->{$field};
        last if defined $f;
     }
+
     if (!defined $f) {
        progress "$what: NO git hash";
+       parse_dsc_field_def_dsc_distro();
     } elsif (($dsc_hash, $dsc_distro, $dsc_hint_tag, $dsc_hint_url)
             = $f =~ m/^(\w+)\s+($distro_re)\s+($versiontag_re)\s+(\S+)(?:\s|$)/) {
        progress "$what: specified git info ($dsc_distro)";
        $dsc_hint_tag = [ $dsc_hint_tag ];
     } elsif ($f =~ m/^\w+\s*$/) {
        $dsc_hash = $&;
-       $dsc_distro //= cfg qw(dgit.default.old-dsc-distro
-                              dgit.default.distro);
+       parse_dsc_field_def_dsc_distro();
        $dsc_hint_tag = [ debiantags +(getfield $dsc, 'Version'),
                          $dsc_distro ];
        progress "$what: specified git hash";
@@ -2912,7 +2918,7 @@ but we could not obtain that object anywhere.
 END
        foreach my $t (@tags) {
            my $fullrefname = $lrf.'/'.$t;
-           print STDERR "CHK $t $fullrefname ".Dumper(\%lrfetchrefs_f);
+#          print STDERR "CHK $t $fullrefname ".Dumper(\%lrfetchrefs_f);
            next unless $lrfetchrefs_f{$fullrefname};
            next unless is_fast_fwd "$fullrefname~0", $dsc_hash;
            lrfetchref_used $fullrefname;
@@ -3311,9 +3317,57 @@ sub ensure_setup_existing_tree () {
     set_local_git_config $k, 'true';
 }
 
+sub open_gitattrs () {
+    my $gai = new IO::File ".git/info/attributes"
+       or $!==ENOENT
+       or die "open .git/info/attributes: $!";
+    return $gai;
+}
+
+sub is_gitattrs_setup () {
+    my $gai = open_gitattrs();
+    return 0 unless $gai;
+    while (<$gai>) {
+       return 1 if m{^\[attr\]dgit-defuse-attrs\s};
+    }
+    $gai->error and die $!;
+    return 0;
+}    
+
+sub setup_gitattrs (;$) {
+    my ($always) = @_;
+    return unless $always || access_cfg_bool(1, 'setup-gitattributes');
+
+    if (is_gitattrs_setup()) {
+       progress <<END;
+[attr]dgit-defuse-attrs already found in .git/info/attributes
+ not doing further gitattributes setup
+END
+       return;
+    }
+    my $af = ".git/info/attributes";
+    open GAO, "> $af.new" or die $!;
+    print GAO <<END or die $!;
+*      dgit-defuse-attrs
+[attr]dgit-defuse-attrs        -text -eol -crlf -ident -filter
+# ^ see dgit(7).  To undo, leave a definition of [attr]dgit-defuse-attrs
+END
+    my $gai = open_gitattrs();
+    if ($gai) {
+       while (<$gai>) {
+           chomp;
+           print GAO $_, "\n" or die $!;
+       }
+       $gai->error and die $!;
+    }
+    close GAO or die $!;
+    rename "$af.new", "$af" or die "install $af: $!";
+}
+
 sub setup_new_tree () {
     setup_mergechangelogs();
     setup_useremail();
+    setup_gitattrs();
 }
 
 sub multisuite_suite_child ($$$) {
@@ -6045,6 +6099,13 @@ sub cmd_quilt_fixup {
     build_maybe_quilt_fixup();
 }
 
+sub import_dsc_result {
+    my ($dstref, $newhash, $what_log, $what_msg) = @_;
+    my @cmd = (@git, qw(update-ref -m), $what_log, $dstref, $newhash);
+    runcmd @cmd;
+    progress "dgit: import-dsc: $what_msg";
+}
+
 sub cmd_import_dsc {
     my $needsig = 0;
 
@@ -6112,6 +6173,12 @@ sub cmd_import_dsc {
 
     parse_dsc_field($dsc, "Dgit metadata in .dsc")
        unless forceing [qw(import-dsc-with-dgit-field)];
+    parse_dsc_field_def_dsc_distro();
+
+    $isuite = 'DGIT-IMPORT-DSC';
+    $idistro //= $dsc_distro;
+
+    notpushing();
 
     if (defined $dsc_hash) {
        progress "dgit: import-dsc of .dsc with Dgit field, using git hash";
@@ -6135,10 +6202,9 @@ END
                fail "Not fast forward to $dsc_hash";
            }
        }
-       @cmd = (@git, qw(update-ref -m), "dgit import-dsc (Dgit): $info",
-               $dstbranch, $dsc_hash);
-       runcmd @cmd;
-       progress "dgit: import-dsc updated git ref $dstbranch";
+       import_dsc_result $dstbranch, $dsc_hash,
+           "dgit import-dsc (Dgit): $info",
+           "updated git ref $dstbranch";
        return 0;
     }
 
@@ -6149,8 +6215,6 @@ Specify  +$specbranch to overwrite, discarding existing history
 END
        if $oldhash && !$force;
 
-    notpushing();
-
     my @dfi = dsc_files_info();
     foreach my $fi (@dfi) {
        my $f = $fi->{Filename};
@@ -6200,10 +6264,9 @@ END
        }
     }
 
-    my @cmd = (@git, qw(update-ref -m), "dgit import-dsc: $info",
-              $dstbranch, $newhash);
-    runcmd @cmd;
-    progress "dgit: import-dsc results are in in git ref $dstbranch";
+    import_dsc_result $dstbranch, $newhash,
+       "dgit import-dsc: $info",
+       "results are in in git ref $dstbranch";
 }
 
 sub cmd_archive_api_query {
@@ -6257,7 +6320,9 @@ sub cmd_version {
 }
 
 our (%valopts_long, %valopts_short);
+our (%funcopts_long);
 our @rvalopts;
+our (@modeopt_cfgs);
 
 sub defvalopt ($$$$) {
     my ($long,$short,$val_re,$how) = @_;
@@ -6293,6 +6358,26 @@ defvalopt '--initiator-tempdir','','.*', sub {
        " absolute, not relative, directory."
 };
 
+sub defoptmodes ($@) {
+    my ($varref, $cfgkey, $default, %optmap) = @_;
+    my %permit;
+    while (my ($opt,$val) = each %optmap) {
+       $funcopts_long{$opt} = sub { $$varref = $val; };
+       $permit{$val} = $val;
+    }
+    push @modeopt_cfgs, {
+        Var => $varref,
+        Key => $cfgkey,
+        Default => $default,
+        Vals => \%permit
+    };
+}
+
+defoptmodes \$dodep14tag, qw( dep14tag          want
+                             --dep14tag        want
+                             --no-dep14tag     no
+                             --always-dep14tag always );
+
 sub parseopts () {
     my $om;
 
@@ -6375,15 +6460,6 @@ sub parseopts () {
            } elsif (m/^--overwrite=(.+)$/s) {
                push @ropts, $_;
                $overwrite_version = $1;
-           } elsif (m/^--dep14tag$/s) {
-               push @ropts, $_;
-               $dodep14tag= 'want';
-           } elsif (m/^--no-dep14tag$/s) {
-               push @ropts, $_;
-               $dodep14tag= 'no';
-           } elsif (m/^--always-dep14tag$/s) {
-               push @ropts, $_;
-               $dodep14tag= 'always';
            } elsif (m/^--delayed=(\d+)$/s) {
                push @ropts, $_;
                push @dput, $_;
@@ -6422,6 +6498,9 @@ sub parseopts () {
            } elsif (m/^(--[-0-9a-z]+)(=|$)/ && ($oi = $valopts_long{$1})) {
                $val = $2 ? $' : undef; #';
                $valopt->($oi->{Long});
+           } elsif ($funcopts_long{$_}) {
+               push @ropts, $_;
+               $funcopts_long{$_}();
            } else {
                badusage "unknown long option \`$_'";
            }
@@ -6554,12 +6633,14 @@ sub parseopts_late_defaults () {
        $quilt_mode = $1;
     }
 
-    if (!defined $dodep14tag) {
+    foreach my $moc (@modeopt_cfgs) {
        local $access_forpush;
-       $dodep14tag = access_cfg('dep14tag', 'RETURN-UNDEF') // 'want';
-       $dodep14tag =~ m/^($dodep14tag_re)$/ 
-           or badcfg "unknown dep14tag setting \`$dodep14tag'";
-       $dodep14tag = $1;
+       my $vr = $moc->{Var};
+       next if defined $$vr;
+       $$vr = access_cfg($moc->{Key}, 'RETURN-UNDEF') // $moc->{Default};
+       my $v = $moc->{Vals}{$$vr};
+       badcfg "unknown $moc->{Key} setting \`$$vr'" unless defined $v;
+       $$vr = $v;
     }
 
     $need_split_build_invocation ||= quiltmode_splitbrain();