[dw-free] move vcv to local repo. Header is updated to note where it came from
[commit: http://hg.dwscoalition.org/dw-free/rev/08ee07f4ef06]
move vcv to local repo. Header is updated to note where it came from
Files modified:
move vcv to local repo. Header is updated to note where it came from
Files modified:
- bin/vcv
- cvs/multicvs.conf
--------------------------------------------------------------------------------
diff -r 523e5dd6e9b6 -r 08ee07f4ef06 bin/vcv
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/vcv Tue May 01 16:00:07 2012 +0800
@@ -0,0 +1,858 @@
+#!/usr/bin/perl
+#
+# This code was originally imported from:
+#
+# http://code.sixapart.com/svn/vcv/trunk
+#
+# We have copied this module locally to modify it for use in the Dreamwidth project.
+# Original copyright is presumably owned by Six Apart, Ltd. Modifications are
+# copyright (C) 2008-2012 by Dreamwidth Studios, LLC.
+#
+
+use strict;
+use Getopt::Long;
+use Cwd;
+
+$| = 1;
+
+my $help = 0;
+my $sync = 0;
+my $diff = 0;
+my $cvsonly = 0;
+my $liveonly = 0;
+my $newonly = 0;
+my $init = 0;
+my $conf;
+my $opt_update;
+my $opt_stable;
+my $opt_justfiles;
+my $opt_checkout;
+my $opt_print_branches;
+my $opt_print_current_branches;
+my $opt_print_vars;
+my $opt_print_repos;
+my $opt_ignore_space;
+my $these_flag;
+my $opt_livelist;
+my $opt_which;
+my $opt_all;
+my $opt_map;
+my $opt_headserver; # blank or "host:port", connect and returns lines of "repo\s+HEADREVNUM\n";
+
+my $opt_svk = 0;
+
+exit 1 unless GetOptions('conf=s' => \$conf,
+ 'help|h' => \$help,
+ 's|sync' => \$sync,
+ 'diff' => \$diff,
+ 'cvsonly|c' => \$cvsonly,
+ 'liveonly|l' => \$liveonly,
+ 'newonly|n' => \$newonly,
+ 'init' => \$init,
+ 'update' => \$opt_update,
+ 'justfiles|1' => \$opt_justfiles,
+ 'print-branches|pb' => \$opt_print_branches,
+ 'print-current-branches|pcb' => \$opt_print_current_branches,
+ 'print-vars|pv' => \$opt_print_vars,
+ 'print-repos|pr' => \$opt_print_repos,
+ 'no-space-changes|b|w' => \$opt_ignore_space,
+ 'these|t' => \$these_flag,
+ 'all' => \$opt_all, # cancels --these
+ 'livelist|ll' => \$opt_livelist,
+ 'checkout|co' => \$opt_checkout,
+ 'which' => \$opt_which,
+ 'map' => \$opt_map,
+ 'headserver|hs=s' => \$opt_headserver,
+ 'svk=s' => \$opt_svk,
+ 'stable' => \$opt_stable,
+ );
+
+
+
+if ($help or not defined $conf) {
+ die "Usage: vcv --conf=/path/to/vcv.conf [opts] [files]\n" .
+ " --help Get this help\n" .
+ " --sync Put files where they need to go.\n" .
+ " All files, unless you specify which ones.\n".
+ " --diff Show diffs of changed files.\n".
+ " --cvsonly Don't consider files changed in live dirs.\n".
+ " --liveonly Don't consider files changed in the CVS dirs.\n".
+ " --newonly Only show files that seem to be new.\n".
+ " --init Copy all files from cvs to main, unconditionally.\n" .
+ " --update Updates files in the CVS dirs from the cvs repositories.\n".
+ " --stable Restrict --update to the most recent stable DW release.\n".
+ " --justfiles -1 Only output files, not the old -> new arrow. (good for xargs)\n".
+ " --livelist -ll Output the list of all accounted-for files.\n".
+ " --which Output the source of the given file\n".
+ " --these -t Refuse to --sync if no files are specified.\n".
+ " --map Like --livelist and --which combined.\n".
+ " --all Overrides --these, allowing --sync to run with no args.\n".
+ " --print-current-branches -pcb Print repositories and their current branches\n".
+ " --print-branches -pb Print repositories and their branches.\n".
+ " --print-repos -pr Print repositories and their resource URLs.\n".
+ " --print-vars -pv Print configuration variables specified in .conf files.\n".
+ " --no-space-changes -b Do not display whitespace differences.\n";
+}
+
+if ($init) {
+ $sync = 1;
+ die "Can't set --liveonly or --cvsonly with --init\n"
+ if $cvsonly or $liveonly;
+ $diff = 0;
+}
+
+unless (-e $conf) {
+ die "Specified conf file doesn't exist: $conf\n";
+}
+
+my %REPO_URLS = (); # repo => url
+my %REPO_BRANCHES = (); # repo => [ branch1, branch2, ... ]
+my %REPO_REV = (); # repo => revnum
+
+my %CACHE = (); # dom => { key => val }
+
+our $SVK;
+
+if($opt_svk || $ENV{VCV_SVK}) {
+ $SVK = VCV::SVK->new;
+ $SVK->set_depot($ENV{VCV_SVK} || $opt_svk);
+}
+
+my ($DIR_LIVE, $DIR_CVS);
+
+my @paths;
+my $headcache; # undef or hashref of { repo => latest rev }
+
+my $read_conf = sub
+{
+ my $file = shift;
+ my $main = shift;
+
+ my $repopattern = '\(([\w\-]+)\)\s*=\s*(\S+)\s*(?:@([a-z0-9]+))?';
+ open (C, $file) or die "Error opening conf file.\n";
+ while (<C>)
+ {
+ s/\#.*//;
+ next unless /\S/;
+ s/^\s+//;
+ s/\s+$//;
+ s/\$(\w+)/$ENV{$1} or die "Environment variable \$$1 not set.\n"/ge;
+
+ if (/(\w+)\s*=\s*(.+)/) {
+ my ($k, $v) = ($1, $2);
+ unless ($main) {
+ die "Included config files can't set variables such as $k.\n";
+ }
+ if ($k eq "LIVEDIR") { $DIR_LIVE = $v; }
+ elsif ($k eq "CVSDIR") { $DIR_CVS = $v; }
+ else { die "Unknown option $k = $v\n"; }
+ next;
+ }
+
+ if (/^SVN$repopattern/) {
+ die "SVN declaration without CVSDIR declared\n" unless $DIR_CVS;
+ my ($ldir, $src, $rev) = ($1, $2, $3);
+
+ my @urlparts = split(/\//, $src);
+ my $url = join("/", @urlparts[0..$#urlparts-1]);
+ $REPO_URLS{$ldir} = $url;
+ $REPO_REV{$ldir} = $rev;
+
+ my $full_ldir = "$DIR_CVS/$ldir";
+ my $full_ldir_svn = "$DIR_CVS/$ldir/.svn";
+ if ($SVK) {
+ $SVK->add_repo($ldir, $src);
+ unless (-d $full_ldir) {
+ unless ($SVK->check_repo($ldir)) {
+ unless ($opt_checkout) {
+ die "SVK directory '$ldir' doesn't exist under $DIR_CVS. Re-run vcv with --checkout for me to automaticall sync it and check it out.\n";
+ }
+ $SVK->checkout_repo($ldir);
+ }
+ }
+ next;
+ }
+
+ unless (-d $full_ldir && -d $full_ldir_svn) {
+ unless ($opt_checkout) {
+ die "Subversion directory '$ldir' doesn't exist under $DIR_CVS. " .
+ "Re-run vcv with --checkout for me to automatically get it for you.\n";
+ }
+ if (-d $full_ldir) {
+ if (-d "$full_ldir/CVS") {
+ rename $full_ldir, "$full_ldir-oldcvs"
+ or die "Failed renaming $full_ldir to oldcvs-$full_ldir: $!";
+ } else {
+ die "You have a $full_ldir directory but it's not CVS or Subversion; confused.";
+ }
+ }
+ my @opts;
+ if ($rev) { push @opts, "-r", $rev; }
+ system("svn", "co", @opts, $src, $full_ldir) and
+ die "Failed to run svn: is it installed?";
+ }
+
+ } elsif (/^HG$repopattern/) {
+ die "HG declaration without CVSDIR declared\n" unless $DIR_CVS;
+ my ($ldir, $src, $rev) = ($1, $2, $3);
+
+ # stable check
+ if ( defined $rev && $rev eq 'stable' ) {
+ undef $rev unless $opt_stable;
+ }
+
+ my @urlparts = split(/\//, $src);
+ my $url = join("/", @urlparts[0..$#urlparts-1]);
+ $REPO_URLS{$ldir} = $url;
+ $REPO_REV{$ldir} = $rev;
+
+ my $full_ldir = "$DIR_CVS/$ldir";
+ my $full_ldir_svn = "$DIR_CVS/$ldir/.hg";
+
+ unless (-d $full_ldir && -d $full_ldir_svn) {
+ unless ($opt_checkout) {
+ die "Mercurial directory '$ldir' doesn't exist under $DIR_CVS. " .
+ "Re-run vcv with --checkout for me to automatically get it for you.\n";
+ }
+ my @opts;
+ if ($rev) { push @opts, "-r", $rev; }
+ system("hg", "clone", @opts, $src, $full_ldir) and
+ die "Failed to run hg: is it installed?";
+ }
+ } elsif(/^GIT$repopattern/) {
+ die "GIT declaration without CVSDIR declared\n" unless $DIR_CVS;
+ my ( $ldir, $src, $rev ) = ( $1, $2, $3 );
+
+ my @urlparts = split(/\//, $src);
+ my $url = join("/", @urlparts[0..$#urlparts-1]);
+ $REPO_URLS{$ldir} = $url;
+ $REPO_REV{$ldir} = $rev;
+
+ my $full_ldir = "$DIR_CVS/$ldir";
+ my $full_ldir_svn = "$DIR_CVS/$ldir/.git";
+
+ unless (-d $full_ldir && -d $full_ldir_svn) {
+ unless ($opt_checkout) {
+ die "Git directory '$ldir' doesn't exist under $DIR_CVS. " .
+ "Re-run vcv with --checkout for me to automatically get it for you.\n";
+ }
+ my @opts;
+ if ($rev) { push @opts, "-r", $rev; }
+ system("git", "clone", @opts, $src, $full_ldir) and
+ die "Failed to run git: is it installed?";
+ }
+ } elsif (/(\S+)\s+(.+)/) {
+ my ($from, $to) = ($1, $2);
+ my $maybe = 0;
+ if ($from =~ s/\?$//) { $maybe = 1; }
+ push @paths, {
+ 'from' => $from,
+ 'to' => $to,
+ 'maybe' => $maybe,
+ };
+
+ } else {
+ die "Bogus line: $_\n";
+ }
+ }
+ close C;
+};
+$read_conf->($conf, 1);
+
+my $origcwd = getcwd;
+chdir( $DIR_LIVE ) or die "Could not change directory to $DIR_LIVE";
+
+if ($conf =~ /^(.+)(multicvs\.conf)$/) {
+ my $localconf = "$1multicvs-local.conf";
+ $read_conf->($localconf) if -e $localconf;
+
+ my $privconf = "$1multicvs-private.conf";
+ $read_conf->($privconf) if -e $privconf;
+}
+
+# after reading config, but before iterating over file paths, perform
+# any requested branch management, which is generally exclusive of
+# file operations
+
+if ($opt_print_vars) {
+ print_vars();
+ exit 0;
+}
+
+if ($opt_print_repos) {
+ print_repos();
+ exit 0;
+}
+
+
+# did the user ask for a list of branches to be printed?
+if ($opt_print_branches) {
+ print_branches();
+ exit 0;
+}
+
+if ($opt_print_current_branches) {
+ print_current_branches();
+ exit 0;
+}
+
+# now config has been read, need to iterate over files in registered
+# paths and do any copying
+
+my %cvspath; # live path -> cvs path
+my %have_updated;
+my %newfile_dirs; # directories to scan for new files
+
+foreach my $p (@paths)
+{
+ unless (-e "$DIR_CVS/$p->{'from'}") {
+ warn "WARNING: $p->{'from'} doesn't exist under $DIR_CVS\n"
+ unless $p->{'maybe'};
+ next;
+ }
+
+ if ($opt_update) {
+ my $root = $p->{'from'};
+ $root =~ s!/.*!!;
+ my $dir = "$DIR_CVS/$root";
+
+ if (-l $dir) {
+ my $to = readlink $dir;
+ if ($to && $to =~ /^[\w\-]+$/) {
+ $root = $to;
+ $dir = "$DIR_CVS/$root";
+ }
+ }
+
+ if (-d $dir && ! $have_updated{$dir}) {
+ chdir $dir or die "Can't cd to $dir\n";
+ my $extra = $REPO_REV{$root} ? "(to r$REPO_REV{$root}) " : "";
+ print "Updating CVS dir $dir '$root' $extra...\n";
+ if (-d ".svn") {
+ my $svninfo = `svn info`;
+ $svninfo =~ /^Revision: (\d+)/m;
+ my $ourrev = $1 || undef;
+ unless (at_wanted_rev($root, $ourrev)) {
+ my @opts;
+ if ($REPO_REV{$root}) { push @opts, "-r", $REPO_REV{$root}; }
+ system("svn", "update", @opts)
+ and die "Failed to update svn for: $dir\n";
+ }
+ } elsif (-d "CVSA") {
+ system("cvs", "-q", "update", "-dP")
+ and die "Failed to update cvs for: $dir\n";
+ } elsif (-d ".hg" ) {
+ my @opts;
+ push @opts, "-r", $REPO_REV{$root} if $REPO_REV{$root};
+ system("hg", "pull");
+ system("hg", "update", @opts);
+ } elsif (-d ".git" ) {
+ system("git", "pull");
+ }elsif ($SVK) {
+ my $info = `svk info $dir`;
+ $info =~ /Mirrored From(.*)Rev. (\d+)/;
+ my $ourrev = $2 || undef;
+ unless (svn_rev_is_latest($root, $ourrev)) {
+ system("svk", "pull", $dir);
+ $SVK->update_repo($dir);
+ };
+ }
+
+ $have_updated{$dir} = 1;
+ }
+ }
+
+ if (-f "$DIR_CVS/$p->{'from'}") {
+ $cvspath{$p->{'to'}} = $p->{'from'};
+ next;
+ }
+
+ $p->{'to'} =~ s!/$!!;
+ my $to_prefix = "$p->{'to'}/";
+ $to_prefix =~ s!^\./!!;
+
+ my @dirs = ($p->{'from'});
+ while (@dirs)
+ {
+ my $dir = shift @dirs;
+ my $fulldir = "$DIR_CVS/$dir";
+
+ opendir (MD, $fulldir) or die "Can't open $fulldir.";
+ while (my $file = readdir(MD)) {
+ next if $file =~ /~$/; # ignore emacs files
+ next if $file =~ /^\.\#/; # ignore CVS archived versions
+ next if $file =~ /\bCVS\b/;
+ next if $file eq ".svn";
+ next if $file eq ".hg";
+ next if $file eq ".git";
+ next if $file eq 'var';
+ next if $file eq "." or $file eq "..";
+ if (-d "$fulldir/$file") {
+ next if $file eq "blib";
+ unshift @dirs, "$dir/$file";
+ } elsif (-f "$fulldir/$file") {
+ my $to = "$dir/$file";
+ $to =~ s!^$p->{'from'}/!!;
+
+ my $fn = "$to_prefix$to";
+ $cvspath{$fn} = "$dir/$file";
+
+ $fn =~ s#/[^/]+$##;
+ $newfile_dirs{$fn} = 1;
+ }
+ }
+ close MD;
+ }
+}
+
+# If the user has specified that there must be arguments, require @ARGV to
+# contain something.
+die "These what?\n\nWith --these specified, you must provide at least one file to sync.\n"
+ if ($these_flag && ! $opt_all) && $sync && !@ARGV;
+
+if ($opt_which && @ARGV != 1) {
+ die "--which requires exactly one argument";
+}
+
+my @files = scalar(@ARGV) ? @ARGV : sort keys %cvspath;
+foreach my $relfile (@files)
+{
+ my $status;
+ next unless exists $cvspath{$relfile};
+ my $root = $cvspath{$relfile};
+ $root =~ s!/.*!!;
+
+ my ($from, $to); # if set, do action (diff and/or sync)
+
+ my $lfile = "$DIR_LIVE/$relfile";
+ my $cfile = "$DIR_CVS/$cvspath{$relfile}";
+
+ if ($opt_map) {
+ print "$relfile\t$cvspath{$relfile}\n";
+ next;
+ }
+
+ if ($opt_which) {
+ print "$cvspath{$relfile}\n";
+ next;
+ }
+
+ if ($opt_livelist) {
+ print "$relfile\n";
+ next;
+ }
+
+ if ($init) {
+ $status = "main <- $root";
+ ($from, $to) = ($cfile, $lfile);
+ } else {
+ my $ltime = mtime($lfile);
+ my $ctime = mtime($cfile);
+ next if $ltime == $ctime;
+ if ($ltime > $ctime && ! $cvsonly && ! $newonly) {
+ $status = "main -> $root";
+ ($from, $to) = ($lfile, $cfile);
+ }
+ if ($ctime > $ltime && ! $liveonly && ! $newonly) {
+ $status = "main <- $root";
+ ($from, $to) = ($cfile, $lfile);
+ }
+ }
+
+ next unless $status;
+
+ my $the_diff;
+ if ($diff && -e $from && -e $to) {
+ my $opt = "";
+ $opt = '-b' if $opt_ignore_space;
+ $the_diff = `diff -u $opt $to $from`; # getting from destination to source
+ if ($the_diff) {
+ # fix the -p level to be -p0
+ my $slashes = ($DIR_LIVE =~ tr!/!/!);
+ $the_diff =~ s/((^|\n)[\-\+]{3,3} )\/([^\/]+?\/){$slashes,$slashes}/$1/g;
+ } else {
+ # don't touch the files that don't have a diff if we're ignoring spaces
+ # as there might really be one and we just don't see it
+ next if $opt_ignore_space;
+
+ # no real change (just touched/copied?), so copy
+ # cvs one on top to fix times up.
+ copy($from, $to);
+ next;
+ }
+ }
+ if ($sync) {
+ make_dirs($relfile);
+ copy($from, $to);
+ }
+
+ if ($opt_justfiles) {
+ print "$relfile\n";
+ } else {
+ printf "%-25s %s\n", $status, $relfile;
+ print $the_diff;
+ }
+}
+
+# now print out new files that don't seem to exist in CVS anywhere
+my %checked;
+my @dirs = sort keys %newfile_dirs;
+@dirs = () if $cvsonly || $liveonly || $sync;
+while ( @dirs ) {
+ my $path = shift @dirs;
+
+ next if $path eq 'cvs' || $path eq 'etc' || $path eq 'logs';
+ next if $checked{$path}++ > 0;
+ next unless -d $path;
+
+ opendir (MD, $path) or die "Can't open $path.";
+ while (my $file = readdir(MD)) {
+ next if $file =~ /~$/; # ignore emacs files
+ next if $file =~ /^\.\#/; # ignore CVS archived versions
+ next if $file =~ /\bCVS\b/;
+ next if $file eq ".svn";
+ next if $file eq ".hg";
+ next if $file eq ".git";
+ next if $file eq "." or $file eq "..";
+ next if $file =~ /\.(?:rej|orig|swp)$/;
+
+ next if $cvspath{"$path/$file"};
+
+ if (-d "$path/$file") {
+ next if $file eq "blib";
+ unshift @dirs, "$path/$file";
+ } elsif (-f "$path/$file") {
+
+ next if @ARGV && ! grep { "$path/$file" eq $_ } @ARGV;
+
+ if ( $opt_justfiles ) {
+ print "$path/$file\n";
+ } else {
+ printf "%-25s %s\n", "main -> new-file", "$path/$file";
+ }
+
+ if ( $diff ) {
+ my $opt = $opt_ignore_space ? '-b' : '';
+ my $the_diff = `diff -u $opt /dev/null $path/$file`;
+ print $the_diff;
+ }
+ }
+ }
+}
+
+chdir( $origcwd );
+
+sub read_cache {
+ return 1 if %CACHE;
+
+ my $file = "$DIR_CVS/.vcv_cache";
+ unless (-e $file) {
+ system("touch", $file);
+ }
+
+ open my $fh, "<$file"
+ or die "unable to open $file";
+
+ while (my $line = <$fh>) {
+ next if $line =~ /^\#/;
+
+ my ($dom_key, $val) = split /\s+/, $line;
+ $CACHE{"$dom_key"} = $val;
+ }
+
+ # set a key in %CACHE even if the file had no data
+ # to indicate that we've already tried to read
+ $CACHE{_read_time} = time();
+
+ return close $fh ? 1 : 0;
+}
+
+sub write_cache {
+ open my $fh, ">$DIR_CVS/.vcv_cache"
+ or die "unable to open $DIR_CVS/.vcv_cache";
+
+ foreach my $key (sort keys %CACHE) {
+ next if $key =~ /^_/;
+ print $fh "$key $CACHE{$key}\n";
+ }
+
+ return close $fh ? 1 : 0;
+}
+
+sub get_cache {
+ my ($dom, @keys) = @_;
+
+ read_cache();
+
+ # only one key requested?
+ return $CACHE{"$dom-$keys[0]"} if @keys == 1;
+
+ # otherwise, return a hashref of k => v
+ my %ret = ();
+ foreach (@keys) {
+ $ret{$_} = $CACHE{"$dom-$_"} if exists $CACHE{"$dom-$_"};
+ }
+
+ return \%ret;
+}
+
+sub set_cache {
+ my $dom = shift;
+
+ while (my ($key, $val) = splice(@_, 0, 2)) {
+ $CACHE{"$dom-$key"} = $val;
+ }
+
+ write_cache();
+ return 1;
+}
+
+sub at_wanted_rev {
+ my ($repo, $have) = @_;
+ return 0 unless $opt_headserver;
+
+ my $wanted = $REPO_REV{$repo} || svn_latest_rev($repo);
+ return $wanted == $have;
+}
+
+sub svn_rev_is_latest {
+ my ($repo, $have) = @_;
+ return 0 unless $opt_headserver;
+
+ return svn_latest_rev($repo) == $have;
+}
+
+sub svn_latest_rev {
+ my $repo = shift;
+ return 0 unless $opt_headserver;
+
+ unless ($headcache) {
+ require IO::Socket::INET;
+ $headcache = {};
+ my $sock = IO::Socket::INET->new(PeerAddr => $opt_headserver)
+ or return 0;
+ while (<$sock>) {
+ /^(\S+)\s+(\d+)/ or next;
+ $headcache->{$1} = $2;
+ }
+ }
+
+ return $headcache->{$repo};
+}
+
+# returns { repo => [ branch1, branch2, ... ] }
+sub get_branches {
+ my %repo_cache_rev = (); # repo => rev num
+
+ # make sure %REPO_BRANCHES is populated from cache
+ my $cache = get_cache("repo_branches", keys %REPO_URLS);
+ while (my ($repo, $branch_info) = each %$cache) {
+ $REPO_BRANCHES{$repo} ||= [];
+ next unless $branch_info;
+
+ my ($rev, @branches) = split(/\s*,\s*/, $branch_info);
+ $repo_cache_rev{$repo} = $rev;
+
+ push @{$REPO_BRANCHES{$repo}}, @branches;
+ }
+
+ # now loop and verify each branch according to revision time
+ my $dirty;
+ foreach my $repo (sort keys %REPO_URLS) {
+
+ my $dir = "$DIR_CVS/$repo";
+ chdir $dir or die "Can't cd to $dir\n";
+
+ die "Branching functionality requires SVN.\n"
+ unless -d ".svn";
+
+ # when was this cache made? is it still the latest revision?
+ my $ourrev = $repo_cache_rev{$repo};
+ unless (svn_rev_is_latest($repo, $ourrev)) {
+ my $rv = `svn ls $REPO_URLS{$repo} $REPO_URLS{$repo}/branches 2>&1`;
+ $rv =~ s/^\s*svn:.+\n//g;
+
+ @{$REPO_BRANCHES{$repo}} =
+ (grep { ! /^(branches|tags)$/ }
+ grep { s/\/$// }
+ split /\s+/, $rv);
+
+ $dirty = 1;
+ }
+
+ # this repo's branch information is already up to date
+ }
+
+ # if anything was updated, update the file cache
+ if ($dirty) {
+ set_cache("repo_branches",
+ map { $_ => join(",", svn_latest_rev($_), @{$REPO_BRANCHES{$_}}) }
+ keys %REPO_BRANCHES);
+ }
+
+ return \%REPO_BRANCHES;
+}
+
+sub print_current_branches {
+ foreach my $repo (sort keys %REPO_URLS) {
+ my $dir = "$DIR_CVS/$repo";
+ chdir $dir or die "Can't cd to $dir\n";
+ die "Branching functionality requires SVN.\n"
+ unless -d ".svn";
+
+ my @lines = `svn info`;
+ chomp @lines;
+
+ foreach my $line (@lines) {
+ next unless $line =~ /^URL:\s+(\S+)\s*$/;
+ my $url = $1;
+ my $branch = (split("/", $url))[-1];
+ printf "%-25s %2s\n", $repo, $branch;
+ }
+ }
+}
+
+sub print_branches {
+ my $branches = get_branches() || {};
+ foreach my $repo (sort keys %$branches) {
+ foreach my $branch (@{$branches->{$repo}}) {
+ printf "%-25s %2s\n", $repo, $branch;
+ }
+ }
+}
+
+sub print_vars {
+
+ # to be extended later as new vars are added
+ my %conf = (
+ DIR_LIVE => \$DIR_LIVE,
+ DIR_CVS => \$DIR_CVS,
+ );
+
+ foreach my $k (@_ ? @_ : sort keys %conf) {
+ my $v = $conf{$k};
+
+ printf "%-25s %s\n", $k, ref $v eq 'ARRAY' ? join(", ", @$v) : $$v;
+ }
+}
+
+sub print_repos {
+ my @repos = shift || sort keys %REPO_URLS;
+
+ foreach my $repo (@repos) {
+ printf "%-25s %s\n", $repo, $REPO_URLS{$repo};
+ }
+}
+
+sub mtime
+{
+ my $file = shift;
+ return (stat($file))[9];
+}
+
+my %MADE_DIR;
+sub make_dirs
+{
+ my $file = shift;
+ return 1 unless $file =~ s!/[^/]*$!!;
+ return 1 if $MADE_DIR{$file};
+ my @dirs = split(m!/!, $file);
+ for (my $i=0; $i<scalar(@dirs); $i++) {
+ my $sd = join("/", @dirs[0..$i]);
+ my $makedir = "$DIR_LIVE/$sd";
+ unless (-d $makedir) {
+ mkdir $makedir, 0755
+ or die "Couldn't make directory $makedir\n";
+ }
+ }
+ $MADE_DIR{$file} = 1;
+}
+
+# was using perl's File::Copy, but I want to preserve the file time.
+sub copy
+{
+ my ($src, $dest) = @_;
+ my $ret = system("cp", "-p", $src, $dest);
+ return ($ret == 0);
+}
+
+package VCV::SVK;
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = bless {}, $class;
+
+ return $self;
+}
+
+sub add_repo {
+ my $self = shift;
+ my $local_dir = shift;
+ my $repo_src = shift;
+ $self->{repo}->{$local_dir} = {
+ remote => $repo_src,
+ svk => "/$self->{depot}/mirror/$local_dir/trunk",
+ co => "$DIR_CVS/$local_dir",
+ };
+}
+
+sub check_repo {
+ my $self = shift;
+ my $local_dir = shift;
+ my $foo = `svk st $self->{repo}->{$local_dir}->{co}`;
+ return unless $foo;
+}
+
+sub checkout_repo {
+ my $self = shift;
+ my $local_dir = shift;
+
+
+
+ my $svk_path = "$self->{repo}->{$local_dir}->{svk}";
+ $svk_path =~ s!/trunk!!;
+
+ my $is_mirror = `svk ls $svk_path`;
+ if ($?) {
+ my $remote = "$self->{repo}->{$local_dir}->{remote}";
+ $remote =~ s!/trunk!!;
+ warn ("svk mirror $remote $svk_path");
+ system("svk","mirror", $remote, $svk_path) and die;
+ }
+ warn "sync $svk_path";
+ my $sync = system("svk sync $svk_path");
+ die $sync if $?;
+ if (! -e $self->{repo}->{$local_dir}->{co}) {
+ warn "svk co $self->{repo}->{$local_dir}->{svk} $self->{repo}->{$local_dir}->{co}\n";
+ my $checkout = `svk co $self->{repo}->{$local_dir}->{svk} $self->{repo}->{$local_dir}->{co}`;
+ die $checkout if $?;
+ } else {
+ warn "svk update $self->{repo}->{$local_dir}->{co}";
+ my $update = `svk update $self->{repo}->{$local_dir}->{co}`;
+ die $update if $?;
+ }
+}
+
+sub update_repo {
+
+}
+
+sub set_depot {
+ my $self = shift;
+ my $depot = shift;
+ die "Alread have depot set to '$self->{depot}'" if $self->{depot};
+
+ my $found_depot = 0;
+ foreach my $line (split "\n", `svk depotmap --list`) {
+ $found_depot = 1 if($line =~ m!^/$depot/!);
+ }
+ if ($found_depot) {
+ $self->{depot} = $depot;
+ } else {
+ die "Cannot find specified depot '$depot'";
+ }
+}
+
+
+__END__
diff -r 523e5dd6e9b6 -r 08ee07f4ef06 cvs/multicvs.conf
--- a/cvs/multicvs.conf Tue May 01 15:54:48 2012 +0800
+++ b/cvs/multicvs.conf Tue May 01 16:00:07 2012 +0800
@@ -12,7 +12,6 @@
# DreamWidth repositories
HG(dw-free) = http://hg.dwscoalition.org/dw-free @stable
-HG(vcv) = http://hg.dwscoalition.org/vcv
HG(bml) = http://hg.dwscoalition.org/bml
HG(js) = http://hg.dwscoalition.org/js
HG(s2) = http://hg.dwscoalition.org/s2
@@ -39,7 +38,6 @@
#openid/perl/Net-OpenID-Consumer/lib cgi-bin
#openid/perl/Net-OpenID-Server/lib cgi-bin
#openid/perl/Net-OpenID-Common/lib cgi-bin
-vcv/bin/vcv bin/vcv
TheSchwartz/bin/schwartzmon bin/schwartzmon
js/ htdocs/js
--------------------------------------------------------------------------------
