4 # On Ubuntu, you'll want the following packages:
5 # - libconfig-simple-perl
6 # - libgit-repository-perl
11 use Date::Manip qw/ParseDate UnixDate/;
14 use Git::Repository::Command;
18 my ($help, $config_file, $repo_path, $all, $check_files, $hash_file, $since, $git_output, $deployed_output);
20 my $remote = 'origin';
24 'help' => \$help, # show help message and exit
25 'config=s' => \$config_file, # INI file for path mappings
26 'repo=s' => \$repo_path, # location of git repo
27 'branch=s' => \$branch, # git branch/head to check against (defaults to 'HEAD')
28 'remote=s' => \$remote, # git remote to pull from (defaults to 'origin')
29 'component=s' => \@components, # parts of EG to be checked (each component is a block in the INI file)
30 'all' => \$all, # check all components specified in config (overrides --component)
31 'check-files' => \$check_files, # check deployed files
32 'hash-file=s' => \$hash_file, # file containing git hashes (overrides --repo)
33 'since=s' => \$since, # check only files modified since this time
34 'print-git-hashes=s' => \$git_output, # output file for git hashes (optional)
35 'print-deployed-hashes=s' => \$deployed_output # output file for hashes of deployed files (optional)
41 $0 --config pathmap.ini --repo /path/to/evergreen.git [ --component perl [ --component tt2 ] | --all ] --check-files [ --since <date> ]
42 $0 --config pathmap.ini --repo /path/to/evergreen.git [ --component perl [ --component tt2 ... ] | --all ] --print-git-hashes <git-hashes.txt>
43 $0 --config pathmap.ini --repo /path/to/evergreen.git [ --component perl [ --component tt2 ... ] | --all ] --print-deployed-hashes <deployed-hashes.txt>
47 Show help message and exit.
49 Location of INI file for path mappings.
51 Location of git repo (overridden by --hash-file).
53 Git branch (head) to check against (defaults to HEAD).
55 Git remote to pull from (defaults to origin).
57 Parts of EG to be checked (each component is a block in the config file).
58 You can use this option multiple times: --component perl --component web
60 Check all components specified in config file (overrides --component).
62 Get file hashes from git, then check deployed files to see if they match.
64 File containing file hashes from git. If you use this option, you don't
65 need to specify a git repo using the --repo option.
66 Use case: pull hashes from git once, copy the resulting file to multiple
67 servers, then check the deployed code against the file instead of pulling
68 hashes from git individually on each server.
70 Only calculate hashes if file has been modified since the specified time.
72 Get file hashes from git repo and print/append to the specified file.
73 Can be used with --check-files and --print-deployed-hashes.
74 --print-deployed-hashes
75 Print git-like hashes for deployed files.
76 Can be used with --check-files and --print-git-hashes.
82 # specify all possible components (--all option);
83 @components = split('\n', `./access_pathmap.pl --config $config_file`) if ($all);
86 open (GITOUTPUT, '>>', $git_output) or die "Could not open $git_output: $!\n";
88 if ($deployed_output) {
89 open (DEPLOYEDOUTPUT, '>>', $deployed_output) or die "Could not open $deployed_output: $!\n";
94 # optionally read in git hashes from file
96 open (HASHFILE, '<', $hash_file) or die "Could not open $hash_file: $!\n";
99 my ($hash, $file) = split(/\s+/, $_, 2);
100 $git_hashes{$file} = $hash;
105 foreach my $component (@components) {
106 my @paths = split('\n', `./access_pathmap.pl --config $config_file --component $component`);
108 # if no hash file was supplied, grab git hashes from repo
112 die "No repo specified\n" unless ($repo_path);
113 $repo_path =~ s|/$||;
114 $repo_path = "$repo_path/.git" unless ($repo_path =~ /\.git$/);
115 my $repo = Git::Repository->new( git_dir => $repo_path ) or die "Could not load git repo $repo_path: $!\n";
117 # ensure git repo is up-to-date
118 if ($branch ne 'HEAD') {
119 $repo->run( 'pull' => $remote );
120 $repo->run( 'checkout' => $branch ); # TODO: is this necessary?
123 # get hashes from git
124 foreach my $srcpath (@paths) {
125 # use git-ls-tree to traverse the file tree starting at $srcpath
126 # e.g. `git ls-tree -r HEAD Open-ILS/src/perlmods/lib`
127 my @tree = $repo->run( 'ls-tree' => '-r', $branch, $srcpath );
128 foreach my $file (@tree) {
129 my ($mode, $type, $hash, $filename) = split(/\s+/, $file, 4);
130 $git_hashes{$filename} = $hash;
131 print GITOUTPUT $hash, "\t", $filename, "\n" if ($git_output);
136 # check deployed files
137 if ($check_files || $deployed_output) {
138 foreach my $srcpath (@paths) {
139 my $destpath = `./access_pathmap.pl --config $config_file --component $component --srcpath $srcpath`;
141 # for each file in the destination path, push the file's absolute path to @files;
142 # output will include symlinked files, but will not include directories
143 # clear @files for each time through loop
145 find( { wanted => sub { push @files, $_ if -f }, follow => 1, no_chdir => 1 }, $destpath );
147 foreach my $file (@files) {
149 # convert $since to seconds since epoch
150 my $since_ts = UnixDate($since, '%s');
151 # get $file modification time as seconds since epoch
152 my $file_ts = ctime(stat($file)->mtime);
154 next unless $file_ts > $since_ts;
157 # you can calculate what the git hash would be
158 # for any file using `git hash-object <file>`;
159 # you don't even need to be in a git repo to run it!
160 my $hash = Git::Repository->run( 'hash-object', $file );
164 $srcfile =~ s|^$destpath|$srcpath|;
166 if (!$git_hashes{$srcfile}) {
167 print "untracked\t$file\n";
168 } elsif ($git_hashes{$srcfile} ne $hash) {
169 print "modified\t$file\n";
172 print DEPLOYEDOUTPUT $hash, "\t", $file, "\n" if ($deployed_output);
179 close (GITOUTPUT) if ($git_output);
180 close (DEPLOYEDOUTPUT) if ($deployed_output);