Bivio::Util::VC
# Copyright (c) 2014 Bivio Software, Inc. All Rights Reserved. # $Id$ package Bivio::Util::VC; use strict; use Bivio::Base 'Bivio.ShellUtil'; b_use('IO.ClassLoaderAUTOLOAD'); b_use('IO.Config')->register(my $_CFG = { git_root_list => [ 'https://github.com/biviosoftware', ], svn_root_list => [], }); sub CONTROL_DIR_FIND_PREDICATE { return q{'(' -name CVS -o -name .git -o -name .svn ')'}; } sub CONTROL_DIR_RE { return qr{(?:^|/)(?:CVS|\.git|\.svn)(?:/|$)}; } sub USAGE { return <<'EOF'; usage: bivio vc [options] command [args..] commands checkout [version] module -- get copy from repo [version=HEAD] EOF } sub handle_config { my(undef, $cfg) = @_; $_CFG = $cfg; return; } sub u_checkout { my($self) = shift; my($version) = @_ > 1 ? shift(@_) : undef; my($module) = @_; _checkout_rsync($self, $module, $version) || _checkout_svn($self, $module, $version) || _checkout_git($self, $module, $version) || _checkout_cvs($self, $module, $version); return; } sub _checkout_cvs { my($self, $module, $version) = @_; return _update_or_fresh( $self, $module, $version, sub { $self->piped_exec([qw(cvs -Q update -d), $module]); return; }, sub { my($v) = @_; $self->piped_exec([qw(cvs -Q checkout -f -r), $v, $module]); return; }, ); } sub _checkout_git { my($self, $module, $version) = @_; my($git_dir) = $module; #TODO: Share with Dev $git_dir =~ s{/}{-}g; my($repo); foreach my $r (@{$_CFG->{git_root_list} || []}) { my($res) = "$r/$git_dir"; if (!Bivio_Die()->catch_quietly( sub {$self->piped_exec("git ls-remote $res 2>&1")}, )) { $repo = $res; last; } } return 0 unless $repo; _update_or_fresh( $self, $module, $version, sub { IO_File()->do_in_dir( $module, sub {$self->piped_exec([qw(git pull)])}, ); return; }, sub { my($v) = @_; $self->piped_exec([qw(git clone), $v eq 'HEAD' ? () : (-b => $v), $repo]); if ($git_dir ne $module) { IO_File()->mkdir_parent_only($module); IO_File()->rename($git_dir, $module); } return; }, ); return 1; } sub _checkout_rsync { my($self, $module, $version) = @_; return 0 unless ($ENV{BIVIO_UTIL_VC_ROOT} || '') =~ m{^/} && -d $ENV{BIVIO_UTIL_VC_ROOT}; my($repo) = "$ENV{BIVIO_UTIL_VC_ROOT}/$module"; IO_Config()->assert_dev; b_info("copying files from $repo, not checking out"); my($md) = IO_File()->absolute_path($module); if (-d $md) { system('chmod', '-R', 'u+w', $md); IO_File()->rm_rf($md); } my($p) = IO_File()->mkdir_parent_only($md); system('rsync', '-aq', '--exclude=.git', '-filter=:- .gitignore', $repo, $p); IO_File()->rename("$p/" . File::Basename::basename($repo), $md); system('chmod', '-R', 'u+w', $md); return 1; } sub _checkout_svn { my($self, $module, $version) = @_; my($repo); foreach my $r (@{$_CFG->{svn_root_list} || []}) { my($res) = "$r/$module"; if (!Bivio_Die()->catch_quietly( sub {$self->piped_exec("svn log '$res' 2>&1")}, )) { $repo = $res; last; } } return 0 unless $repo; _update_or_fresh( $self, $module, $version, sub { IO_File()->do_in_dir( $module, sub {$self->piped_exec([qw(svn update), $repo])}, ); return; }, sub { my($v) = @_; IO_File()->do_in_dir( IO_File()->mkdir_parent_only($module), sub {$self->piped_exec([qw(svn checkout -r), $v, $repo])}, ); return; }, ); return 1; } sub _update_or_fresh { my($self, $module, $version, $update, $fresh) = @_; if (-d $module) { if ($version) { $self->usage_error($module,': module exists and version supplied'); } $update->(); return; } $fresh->($version || 'HEAD'); return; } 1;