lib/ES/TargetRepo.pm (100 lines of code) (raw):

package ES::TargetRepo; use strict; use warnings; use v5.10; use Cwd; use Path::Class(); use Encode qw(decode_utf8); use ES::Util qw(run); use parent qw( ES::BaseRepo ); my %Repos; #=================================== # Create a repo for tracking *built* docs. This creation doesn't do anything # on disk and the repo should be prepared by calling `update_from_remote` and # `checkout_minimal`. The first call interacts with the network and can take # a long time, especially if the repo doesn't exist locally. The second call # is generally much quicker. #=================================== sub new { #=================================== my ( $class, %args ) = @_; $args{name} = 'target_repo'; my $self = $class->SUPER::new(%args); $self->{destination} = $args{destination} or die "No <destination> specified for repo <target_repo>"; $self->{branch} = $args{branch} or die "No <branch> specified for repo <target_repo>"; $self; } #=================================== # Checks out the parts of this repo that are not built docs. This will make # sure that we have the tracker file that we need to check out other repos. #=================================== sub checkout_minimal { #=================================== my ( $self ) = @_; # Whether or not we'll need to force push the target branch. $self->{rebuilding_target_branch} = 0; my $original_pwd = Cwd::cwd(); eval { my $out = run qw(git clone --no-checkout), $self->git_dir, $self->{destination}; # This if statement handles empty repositories in a way that works with # different target branches. It always checks out the master # branch. If the target branch is `master` then it will return early. # If the target branch isn't master it'll delete the existing copy # of the branch. if ( $out =~ /You appear to have cloned an empty repository./) { $self->{started_empty} = 1; printf(" - %20s: Initializing empty master for empty repo\n", 'target_repo'); return 1 if $self->{branch} eq 'master'; chdir $self->{destination}; $self->{initialized_empty_master} = 1; run qw(git commit --allow-empty -m init); } else { $self->{started_empty} = 0; chdir $self->{destination}; run qw(git config core.sparseCheckout true); $self->_write_sparse_config( $self->{destination}, "/*\n!html/*/\n!raw/*/" ); run qw(git checkout master); return 1 if $self->{branch} eq 'master'; if ( $self->_branch_exists( 'origin/' . $self->{branch} ) ) { $self->{rebuilding_target_branch} = 1; } } printf(" - %20s: Forking <%s> from master\n", 'target_repo', $self->{branch}); run qw(git checkout -b), $self->{branch}; 1; } or die "Error checking out repo <target_repo>: $@"; chdir $original_pwd; } #=================================== # Checks out the rest of the repo. This must be finished before we can build # docs into the repo. #=================================== sub checkout_all { #=================================== my ( $self ) = @_; my $original_pwd = Cwd::cwd(); chdir $self->{destination}; eval { $self->_write_sparse_config( $self->{destination}, "*\n" ); run qw(git read-tree -mu HEAD) unless $self->{started_empty}; 1; } or die "Error checking out repo <target_repo>: $@"; chdir $original_pwd; } #=================================== # Returns truthy if there outstanding changes to the repo, falsy otherwise. #=================================== sub outstanding_changes { #=================================== my ( $self ) = @_; local $ENV{GIT_WORK_TREE} = $self->{destination}; local $ENV{GIT_DIR} = $ENV{GIT_WORK_TREE} . '/.git'; # This command will list all modified files, including deleted files. # Unlike `git status` it won't group new directories. return run qw(git ls-files -zomd --); } #=================================== # Commits all changes to the repo. #=================================== sub commit { #=================================== my ( $self ) = @_; local $ENV{GIT_WORK_TREE} = $self->{destination}; local $ENV{GIT_DIR} = $ENV{GIT_WORK_TREE} . '/.git'; run qw(git add -A); my $commit_msg = 'Updated docs'; if ( $ENV{NODE_NAME} ) { $commit_msg .= "\n\nBuilt on $ENV{NODE_NAME}"; } run qw(git commit -m), $commit_msg; } #=================================== # Push to the remote repo. #=================================== sub push_changes { #=================================== my ( $self ) = @_; local $ENV{GIT_WORK_TREE} = $self->{destination}; local $ENV{GIT_DIR} = $ENV{GIT_WORK_TREE} . '/.git'; my @push_branch = qw(git push origin); push @push_branch, '--force' if $self->{rebuilding_target_branch}; push @push_branch, $self->{branch}; run qw(git push origin master) if $self->{initialized_empty_master}; run @push_branch; local $ENV{GIT_DIR} = $self->{git_dir}; run qw(git push origin master) if $self->{initialized_empty_master}; run @push_branch; } #=================================== # Does a branch exist? #=================================== sub _branch_exists { #=================================== my ( $self, $branch ) = @_; return eval { run qw(git rev-parse --verify), $branch }; } #=================================== sub destination { shift->{destination} } #=================================== 1