2 # usage: tb-update [options]
10 Getopt::Long::Configure(qw(bundling));
12 die "bad usage\n" if @ARGV;
21 check_baseref_metadata("$baserefs/$patch");
23 my $head = git_run_1line(qw(rev-parse),"$baserefs/$patch");
25 # 2.i. Compute set of desired included deps
27 my $add_desired = sub {
29 my ($obk,$deps) = git_get_object("$baserefs/$sub:.topbloke/deps");
30 die "$sub $obk ??" unless $obk eq 'blob';
31 foreach my $depline (split /\n/, $deps) {
32 next if exists $desired{$depline};
33 $desired{$depline} = 1;
34 if ($depline =~ m/^- /) {
35 } elsif ($depline =~ m/^-/) {
38 check_baseref_metadata("$baserefs/$depline");
39 $add_desired->($depline);
43 $add_desired->($patch);
46 # first, find the list of sources
49 my ($obk,$deps) = git_get_object("$baserefs/$patch:.topbloke/deps");
50 die "$patch $obk ??" unless $obk eq 'blob';
51 foreach my $depline (split /\n/, $deps) {
52 if ($depline =~ m/^- /) {
53 push @sources, { Ref => "$'", Kind => 'foreign' };
54 } elsif ($depline =~ m/^-/) {
55 die "$depline ?"; # should have failed earlier
57 push @sources, { Ref => "$tiprefs/$depline", Kind => 'tb' };
61 my ($obk,$tg) = git_get_object("$baserefs/$patch:.topbloke/topgit-");
62 if ($obk ne 'missing') {
63 $obj eq 'blob' or die "$patch $obk ??";
64 chomp $tg or die "$patch ??";
65 push @sources, { Ref => "refs/top-bases/$tg", Kind => 'topgit' };
68 # This bit involves rather too much history walking
69 # and could perhaps be optimised.
71 # Find the merge base for each source
72 foreach my $source (@sources) {
73 $source->{Head} = run_git_1line(qw(rev-parse), $source->{Ref});
74 $source->{MergeBase} =
75 run_git_1line(qw(merge-base), $head, "$baserefs/$patch");
77 # The merge base is contained in $head, so if it is equal
78 # to the source's head, the source is contained in $head -
79 # ie we are ahead of the source. Skip those sources.
80 @sources = grep { $source->{MergeBase} ne $source->{Head} } @sources;
82 # Now we run git-rev-list to walk the graph back to those
83 # sources so we can tell which is the most recent.
84 foreach my $source (@sources) {
88 $source->{MergeBase} = $mergebase;
90 bad_metadata("$patch base topgit $obj") unless $obj eq 'blob';
98 return 1 if $done{$_[0]}++;
103 my ($key,$code) = @_;
105 return $memo{$key} if exists $memo{$key};
107 $memo{$key} = $code->();
112 sub tip_sources ($) {
115 push @sources, { How => 'base', Ref => "$baserefs/$patch" };
116 foreach my $remote (get_configured_remotes()) {
117 push @sources, { How => 'remote',
118 Ref => "refs/remotes/$remote/topbloke-tips/$patch" };
121 sub compute_desired_deps ($) {
123 return memo("compute_desired_deps $patch", {
124 foreach my $sourceref (tip_source_refs($patch)) {
129 sub update_base ($) {
131 return if done("update_base $patch");
132 my @desired_deps = compute_desired_deps($patch);
135 sub update_deps ($) {
137 return if done("update_deps $patch");
138 my $deps = git_get_object("$baserefs/$patch:.topbloke/deps");
139 foreach my $dep (split /\n/, $deps) {
140 if ($dep =~ m/^tb /) {
141 my $dep_patch = $'; #';
142 update_patch($dep_patch);
147 sub update_patch ($) {
154 our $current = current_branch();
155 if ($current->{Kind} eq 'tip') {
156 update_patch($current);
157 } elsif ($current->{Kind} eq 'base') {
158 update_deps($current);
159 update_base($current);
161 die "Not a topbloke branch ($current->{Kind})\n";