diff options
Diffstat (limited to 'usr/src/libpiny/lib/Piny/Repo.pm')
-rw-r--r-- | usr/src/libpiny/lib/Piny/Repo.pm | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/usr/src/libpiny/lib/Piny/Repo.pm b/usr/src/libpiny/lib/Piny/Repo.pm new file mode 100644 index 0000000..4783960 --- /dev/null +++ b/usr/src/libpiny/lib/Piny/Repo.pm @@ -0,0 +1,169 @@ +# Copyright © 2010 Julian Blake Kongslie <jblake@omgwallhack.org> +# Licensed under the BSD 3-clause license. + +package Piny::Repo; + +use Moose; + +use File::Find qw( find ); + +use Piny::User; + +# Attributes + +has 'name' => + ( is => 'rw' + , isa => 'Str' + , trigger => \&_rename_repo + , required => 1 + ); + +has 'path' => + ( is => 'ro' + , isa => 'Str' + , lazy_build => 1 + , init_arg => undef + ); + +has 'description' => + ( is => 'rw' + , isa => 'Str' + , trigger => \&_set_description + , lazy_build => 1 + , init_arg => undef + ); + +has 'repostat' => + ( is => 'ro' + , isa => 'ArrayRef' + , lazy_build => 1 + , init_arg => undef + ); + +has 'owner' => + ( is => 'rw' + , isa => 'Piny::User' + , trigger => \&_change_owner + , lazy_build => 1 + , init_arg => undef + ); + +has 'globally_readable' => + ( is => 'ro' + , isa => 'Bool' + , lazy_build => 1 + , init_arg => undef + ); + +has 'globally_writable' => + ( is => 'ro' + , isa => 'Bool' + , lazy_build => 1 + , init_arg => undef + ); + +# Triggers + +sub _rename_repo { + my ( $s, $new_name, $old_name ) = @_; + + return unless defined $old_name; + + my $olddir = "/srv/git/$old_name.git"; + my $newdir = "/srv/git/$new_name.git"; + + rename( $olddir, $newdir ) or die "Couldn't rename $olddir to $newdir: $!"; + + $s->clear_path( ); +}; + +sub _set_description { + my ( $s, $new_description, $old_description ) = @_; + + return unless defined $old_description; + + open( my $fd, ">", $s->path( ) . "/description" ) or die "Unable to open " . $s->path( ) . "/description for writing: $!"; + print $fd $new_description; + close( $fd ) or die "Error when closing " . $s->path( ) . "/description: $!"; +}; + +sub _change_owner { + my ( $s, $new_owner, $old_owner ) = @_; + + return unless defined $old_owner; + + find( { wanted => sub { chown( $new_owner->uid( ), -1, $_ ) or die "Couldn't chown $_: $!"; }, no_chdir => 1 }, $s->path( ) ); +}; + +# Builder methods + +# If constructed with just one argument, then treat it as a repo name. +around BUILDARGS => sub { + my ( $orig, $class ) = ( shift, shift ); + + if ( @_ == 1 && ! ref $_[0] ) { + return $class->$orig( name => $_[0] ); + } else { + return $class->$orig( @_ ); + }; +}; + +sub _build_path { + my ( $s ) = @_; + + my $dir = "/srv/git/" . $s->name( ) . ".git"; + + if ( -d $dir ) { + return $dir; + } else { + die "Expected repo $dir does not exist!"; + }; +}; + +sub _build_description { + my ( $s ) = @_; + + open( my $d, "<", $s->path( ) . "/description" ) or die "Unable to open " . $s->path( ) . "/description: $!"; + my $desc; + { + local $/ = undef; + $desc = <$d>; + }; + close( $d ); + + return $desc; +}; + +sub _build_repostat { + my ( $s ) = @_; + + my @res = stat( $s->path( ) ); + die "stat( " . $s->path( ) . " ) failed: $!" unless @res; + return \@res; +}; + +sub _build_owner { + my ( $s ) = @_; + + my ( $uid ) = $s->repostat( )->[4]; + + return Piny::User->new( uid => $uid ); +}; + +sub _build_globally_readable { + my ( $s ) = @_; + + return ( $s->repostat( )->[2] & 0444 ) == 0444; +}; + +sub _build_globally_writable { + my ( $s ) = @_; + + return ( $s->repostat( )->[2] & 0111 ) == 0111; +}; + +# Moose boilerplate + +__PACKAGE__->meta->make_immutable; + +1; |