Commit c22b7b06 authored by Michael Pyne's avatar Michael Pyne
Browse files

Implement tag and revision options for git modules.

This makes the 'tag' option allow for checking out a given git tag for a
module (which is enforced by using refs/tags/$foo when passing to git).

Additionally, the 'revision' option has been adopted for git modules as
well, to allow for checking out any other git "tree-ish" that git
supports (i.e. anything supported by 'git checkout $foo').

Both options should leave the source directory in a detached HEAD state,
although kdesrc-build will adapt as necessary with each source update.

The auto-stashing is still attempted for both types, and a failure to
apply an auto-stashed change will cause the module to fail to build.
Ensure you're in a clean working directory if you want to avoid issues
due to this.

The test suite continues to pass (not that it's very extensive).

BUG:308493
FIXED-IN:1.16
parent e3c41daf
......@@ -2168,12 +2168,18 @@ specify the &git; repository to download the source code for the module.
<row id="conf-revision">
<entry>revision</entry>
<entry>Module setting overrides global</entry>
<entry>If this option is set to a value other than 0 (zero), &kdesrc-build;
will force the &subversion; update to bring the module to the exact revision
<entry><para>If this option is set to a value other than 0 (zero), &kdesrc-build;
will force the source update to bring the module to the exact revision
given, even if options like <link linkend="conf-branch">branch</link> are in
effect. If the module is already at the given revision then it will not be
updated further unless this option is changed or removed from the
configuration.</entry>
configuration.</para>
<note><para>This option did not work for git-based modules (including <link
linkend="kde-projects-module-sets">kde-projects</link> modules) until
&kdesrc-build; version 1.16.</para></note>
</entry>
</row>
<row id="conf-run-tests">
......
......@@ -2475,6 +2475,7 @@ EOM
use File::Basename; # basename
use File::Spec; # tmpdir
use POSIX qw(strftime);
use List::Util qw(first);
use constant {
DEFAULT_GIT_REMOTE => 'origin',
......@@ -2552,7 +2553,12 @@ EOM
p_chdir($srcdir);
# Switch immediately to user-requested tag or branch now.
if (my $tag = $module->getOption('tag')) {
if (my $rev = $module->getOption('revision')) {
info ("\tSwitching to specific revision g[$rev]");
$result = (log_command($module, 'git-checkout-rev',
['git', 'checkout', $rev]) == 0);
}
elsif (my $tag = $module->getOption('tag')) {
info ("\tSwitching to specific tagged-commit g[$tag]");
$result = (log_command($module, 'git-checkout-tag',
['git', 'checkout', "refs/tags/$tag"]) == 0);
......@@ -2688,32 +2694,25 @@ EOF
return $remoteNames[0];
}
# Updates an already existing git checkout by running git pull.
# Completes the steps needed to update a git checkout to be checked-out to
# a given remote-tracking branch. Any existing local branch with the given
# branch set as upstream will be used if one exists, otherwise one will be
# created. The given branch will be rebased into the local branch.
#
# Return parameter is the number of affected *commits*. Errors are
# returned only via exceptions because of this.
sub updateExistingClone
# No checkout is done, this should be performed first.
# Assumes we're already in the needed source dir.
# Assumes we're in a clean working directory (use git-stash to achieve
# if necessary).
#
# First parameter is the remote to use.
# Second parameter is the branch to update to.
# Returns boolean success flag.
# Exception may be thrown if unable to create a local branch.
sub _updateToRemoteHead
{
my $self = assert_isa(shift, 'GitUpdate');
my $module = $self->module();
my $srcdir = $module->fullpath('source');
my $cur_repo = $module->getOption('repository');
my $branch = $self->getBranch();
my $result;
p_chdir($srcdir);
note ("Updating g[$module] (to branch b[$branch])");
my $start_commit = $self->commit_id('HEAD');
my $remoteName = $self->_setupBestRemote();
# Download updated objects. This also updates remote heads so do this
# before we start comparing branches and such, even though we will
# later use git pull.
if (0 != log_command($module, 'git-fetch', ['git', 'fetch', $remoteName])) {
die "Unable to perform git fetch for $remoteName, which should be $cur_repo";
}
my $self = shift;
my ($remoteName, $branch) = @_;
my $module = $self->module();
# The 'branch' option requests a given head in the user's selected
# repository. Normally the remote head is mapped to a local branch,
......@@ -2741,11 +2740,86 @@ EOF
{
die "Unable to perform a git checkout to existing branch $branchName";
}
# On the right branch, merge in changes.
return 0 == log_command($module, 'git-rebase',
['git', 'rebase', "$remoteName/$branch"]);
}
# With all remote branches fetched, and the checkout of our desired branch
# completed, we can now use git pull to complete the changes.
if ($self->stashAndUpdate()) {
return 1;
}
# Completes the steps needed to update a git checkout to be checked-out to
# a given commit. The local checkout is left in a detached HEAD state,
# even if there is a local branch which happens to be pointed to the
# desired commit. Based the given commit is used directly, no rebase/merge
# is performed.
#
# No checkout is done, this should be performed first.
# Assumes we're already in the needed source dir.
# Assumes we're in a clean working directory (use git-stash to achieve
# if necessary).
#
# First parameter is the commit to update to. This can be in pretty
# much any format that git itself will respect (e.g. tag, sha1, etc.).
# It is recommended to use refs/$foo/$bar syntax for specificity.
# Returns boolean success flag.
sub _updateToDetachedHead
{
my ($self, $commit) = @_;
my $module = $self->module();
info ("\tDetaching head to b[$commit]");
return 0 == log_command($module, 'git-checkout-commit',
['git', 'checkout', $commit]);
}
# Updates an already existing git checkout by running git pull.
#
# Return parameter is the number of affected *commits*. Errors are
# returned only via exceptions because of this.
sub updateExistingClone
{
my $self = assert_isa(shift, 'GitUpdate');
my $module = $self->module();
my $cur_repo = $module->getOption('repository');
my $result;
p_chdir($module->fullpath('source'));
my $remoteName = $self->_setupBestRemote();
# Download updated objects. This also updates remote heads so do this
# before we start comparing branches and such.
info ("Downloading updates for g[$module]");
if (0 != log_command($module, 'git-fetch', ['git', 'fetch', '-t', $remoteName])) {
die "Unable to perform git fetch for $remoteName, which should be $cur_repo";
}
# Now we need to figure out if we should update a branch, or simply
# checkout a specific tag/SHA1/etc.
# We need to be wordy here to placate the Perl warning generator.
my @gitRefTypes = (
[qw/revision commit/], [qw/tag tag/], [qw/branch branch/],
);
my $gitRefType = first { $module->getOption($_->[0]) } @gitRefTypes;
my ($branch, $type) = @$gitRefType;
$branch = $module->getOption($branch);
note ("Updating g[$module] (to $type b[$branch])");
my $start_commit = $self->commit_id('HEAD');
my $updateSub = sub { $self->_updateToRemoteHead($remoteName, $branch) };
if ($type ne 'branch') {
$branch = "refs/tags/$branch" if $type eq 'tag';
$updateSub = sub { $self->_updateToDetachedHead($branch); }
}
# With all remote branches fetched, and the checkout of our desired
# branch completed, we can now use our update sub to complete the
# changes.
if ($self->stashAndUpdate($updateSub)) {
return count_command_output('git', 'rev-list', "$start_commit..HEAD");
}
else {
......@@ -2861,8 +2935,8 @@ EOF
return ($result == 0);
}
# This stashes existing changes if necessary, and then runs git pull
# --rebase in order to advance the given module to the latest head.
# This stashes existing changes if necessary, and then runs a provided
# update routine in order to advance the given module to the desired head.
# Finally, if changes were stashed, they are applied and the stash stack is
# popped.
#
......@@ -2870,11 +2944,16 @@ EOF
# are on the right branch, and that we are already in the correct
# directory.
#
# First parameter is a reference to the subroutine to run. This subroutine
# should need no parameters and return a boolean success indicator. It may
# throw exceptions.
#
# Returns true on success, false otherwise. Some egregious errors result in
# exceptions being thrown however.
sub stashAndUpdate
{
my $self = assert_isa(shift, 'GitUpdate');
my $updateSub = shift;
my $module = $self->module();
my $date = strftime ("%F-%R", gmtime()); # ISO Date, hh:mm time
......@@ -2912,11 +2991,7 @@ EOF
}
}
$status = log_command($module, 'git-pull-rebase', [
qw(git pull --rebase --quiet)
]);
if ($status != 0) {
if (!$updateSub->()) {
error ("Unable to update the source code for r[b[$module]");
return 0;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment