#!/usr/bin/env perl # hg-working-stat -- collect stat information about mercurial working files # Author: Noah Friedman # Created: 2010-03-22 # Public domain # $Id: hg-working-stat,v 1.1 2010/03/23 05:35:34 friedman Exp $ # Commentary: # Mercurial doesn't preserve file modes, timestamps, security contexts, and # other errata when updating a workspace. This command can be used to # generate a checkpoint of this data in a workspace, and then restore it # after doing an update. # The format of the output is: user group perm mtime selinux_context filename # Code: $^W = 1; # enable warnings use Symbol; use strict; use File::ExtAttr qw(:all); #use POSIX qw(strftime); sub max { my $elt = $_[0]; map { $elt = $_ if $_ > $elt } @_; return $elt; } sub timestamps { my $fh = gensym; # Print entries in ascending order, so that later timestamps override # earlier ones. open ($fh, "hg log -r0:. --template \"{date|hgdate} {files}\\n\" @_ |") || die; my %ts; map { chomp; my ($t, $o, @files) = split (/\s+/, $_); my $ts = $t + $o; map { $ts{$_} = $ts } @files; } <$fh>; return \%ts; } sub main { my @files = `hg manifest -r.`; chomp @files; my $ts = timestamps (@files); my %data; map { my %f; my @st = lstat ($_); $f{owner} = getpwuid ($st[4]); $f{group} = getgrgid ($st[5]); $f{mode} = $st[2] & 07777; $f{mtime} = $ts->{$_}; $f{context} = getfattr ($_, 'selinux', { namespace => 'security' }); $f{context} =~ s/\0//g; #$f{mtimestr} = strftime ("%Y-%m-%d:%H:%M:%S", gmtime ($f{mtime})); $data{$_} = \%f; } @files; my $ctxlen = max (map { length $data{$_}->{context} } keys %data); my $fmtctx = sprintf ("%%-%ds", $ctxlen); my $fmt = "%s %s %4.4o %s $fmtctx %s\n"; map { local *d = $data{$_}; printf ($fmt, @::d{qw(owner group mode mtime context)}, $_); } @files; } main (@ARGV); # eof