#!/usr/bin/perl use strict; use warnings; =pod =head1 NAME survey-repositories - Show any uncommitted changes and pending publications of my source repositories =cut use lib '/home/mike/sys/lib'; use Cwd (); use File::Find (); use File::stat (); use Mike::File (); my @repos; # Paths of basic projects, those on which other projects depend. Paths are listed in order # from least to most basic, with the upshot that my process of change review and commital # proceeds from dependencies to dependants. my @bases = ( # '/home/mike/code/WP3/wayic/refractory/', ## Alone [it was] non-basic and dependent on all others, whose terms it may index: '/home/mike/code/WP3/wayic/Waybrec/Emacs', '/home/mike/code/WP3/wayic/Web/imager', '/home/mike/code/WP3/wayic/Waybrec/parser', '/home/mike/code/WP3/wayic/model', '/home/mike/code/WP3/wayic/intercast', '/home/mike/code/WP3/wayic/cast', '/home/mike/code/WP3/wayic/Waybrec', '/home/mike/code/WP3/way', '/home/mike/work/ethic', '/home/mike/work/Breccia/Emacs', '/home/mike/work/Java/Emacs', '/home/mike/work/email/TMDA', '/home/mike/work/Web/autoindex', '/home/mike/work/Breccia/Web/imager', '/home/mike/work/Breccia/parser/plain', '/home/mike/work/Breccia/XML/translator', '/home/mike/work/Breccia/parser', '/home/mike/work/Breccia/XML', '/home/mike/work/Breccia', '/home/mike/work/Java', '/home/mike/work/building/Makeshift' ); my @privateBranches = ( # `reluk.ca` '/home/mike/project/Breccia', '/home/mike/project/building', '/home/mike/project/email', '/home/mike/project/Java', '/home/mike/project/wayic', '/home/mike/project/Web' ); for my $dir ( '/home/mike/work', '/home/mike/code/WP3', @privateBranches ){ -d $dir or die "not a dir: $dir\n"; Mike::File::is_working__set_dir( $dir ); # File::Find::find( {wanted=>\&wanted}, $dir ); # Follows no symbolic links. File::Find::find( {wanted=>\&wanted, follow=>1, follow_skip=>2}, $dir ); } # Follows symbolic links, yet avoids cycles and returns no file twice. @repos = sort basicComparator @repos; for my $repo( @repos ) { my $git = 'git -C ' . $repo; system "$git status --short"; system "$git --no-pager log --oneline master --not --remotes=*/master"; # ‘Shows all commits # that are in local master but not in any remote repository master branches.’ [man git-log] my $prettyPath = $repo; $prettyPath =~ s'/home/mike'~'; print " $prettyPath/\n"; } sub basicComparator { # Comparing path globals `$a` and `$b` and returning the result as -1, 0 or 1. my $aOrdinal; my $bOrdinal; my $oN; # Private branches, the highest priority # ──────────────── $oN = scalar @privateBranches; for( my $o = 0; $o < $oN; ++$o ) { my $dir = $privateBranches[$o]; if( !defined $aOrdinal && rindex($a,$dir,0) == 0 ) { $aOrdinal = $o; } if( !defined $bOrdinal && rindex($b,$dir,0) == 0 ) { $bOrdinal = $o; } if( defined $aOrdinal && defined $bOrdinal ) { # Then both are in private branches, return $a cmp $b; }} # wherefore compare them lexicographically. if( defined $aOrdinal ) { return 1; } # Because `$a` alone is in a private branches. if( defined $bOrdinal ) { return -1; } # Because `$b` alone is in a private branches. # Basic projects, the next highest and with fine degrees of # ────────────── $oN = scalar @bases; for( my $o = 0; $o < $oN; ++$o ) { my $base = $bases[$o]; if( !defined $aOrdinal && $a eq $base ) { $aOrdinal = $o; } if( !defined $bOrdinal && $b eq $base ) { $bOrdinal = $o; } if( defined $aOrdinal && defined $bOrdinal ) { # Then both are proper to base projects, return $aOrdinal <=> $bOrdinal; }} # wherefore compare them ordinally. if( defined $aOrdinal ) { return 1; } # Because `$a` alone is proper to a base project. if( defined $bOrdinal ) { return -1; } # Because `$b` alone is proper to a base project. return $a cmp $b; } # Neither a private branch nor base project, compare them lexicographically. sub wanted { -d or return; my $path = $File::Find::name; $path =~ m'/\._(?:/|$)' and return; # A boneyard directory, or within one. -l "$path" and return; # A linked directory, e.g. under `~/work/wayic/`, and so a duplicate. -d "$path/.git" or return; push @repos, $path; } __END__