package Shipwright::Backend::FS; use warnings; use strict; use Carp; use File::Spec::Functions qw/catfile splitdir catdir rel2abs/; use Shipwright::Util; use File::Copy::Recursive qw/rcopy rmove/; use File::Path qw/remove_tree make_path/; our %REQUIRE_OPTIONS = ( import => [qw/source/] ); use base qw/Shipwright::Backend::Base/; =head1 NAME Shipwright::Backend::FS - File System backend =head1 SYNOPSIS shipwright create -r fs:/home/me/shipwright/my_project =head1 DESCRIPTION This module implements file system based backend with version control for Shipwright L. =head1 METHODS =cut =over 4 =item build =cut sub build { my $self = shift; $self->strip_repository; my $repo = $self->repository; $repo =~ s/^~/Shipwright::Util->user_home/e; my $abs_path = rel2abs($repo); $repo = $abs_path if $abs_path; $self->repository($repo); $self->SUPER::build(@_); } =item initialize Initialize a project. =cut sub initialize { my $self = shift; my $dir = $self->SUPER::initialize(@_); $self->delete; # clean repository in case it exists rcopy( $dir, $self->repository ) or confess "can't copy $dir to " . $self->repository . ": $!"; } # a cmd generating factory sub _cmd { my $self = shift; my $type = shift; my %args = @_; $args{path} ||= ''; for ( @{ $REQUIRE_OPTIONS{$type} } ) { croak "$type need option $_" unless $args{$_}; } my @cmd; if ( $type eq 'checkout' || $type eq 'export' ) { @cmd = sub { rcopy( $self->repository . $args{path}, $args{target} ); }; } elsif ( $type eq 'import' ) { if ( $args{_extra_tests} ) { @cmd = sub { rcopy( $args{source}, catdir( $self->repository, 't', 'extra' ) ); }; } else { if ( my $script_dir = $args{build_script} ) { push @cmd, sub { rcopy( catdir($script_dir), catdir( $self->repository, 'scripts', $args{name} ) ); }; } else { if ( $self->has_branch_support ) { my @dirs = splitdir( $args{as} ); unless ( -e catdir( $self->repository, 'sources', $args{name}, @dirs[ 0 .. $#dirs - 1 ] ) ) { push @cmd, sub { make_path( catdir( $self->repository, 'sources', $args{name}, @dirs[ 0 .. $#dirs - 1 ] ) ); }; } push @cmd, sub { rcopy( catdir( $args{source} ), catdir( $self->repository, 'sources', $args{name}, $args{as} ) ); }; } else { push @cmd, sub { rcopy( catdir( $args{source} ), catdir( $self->repository, 'dists', $args{name} ) ); }; } } } } elsif ( $type eq 'delete' ) { @cmd = sub { remove_tree( $self->repository . $args{path} ) }; } elsif ( $type eq 'move' ) { @cmd = sub { rmove( $self->repository . $args{path}, $self->repository . $args{new_path} ); }; } elsif ( $type eq 'info' ) { @cmd = sub { -e $self->repository . $args{path} }; } elsif ( $type eq 'list' ) { @cmd = sub { my $path = $self->repository . $args{path}; return 'No such file or directory' unless -e $path; if ( -d $path ) { my $dh; opendir $dh, $path or die $!; my $dirs = join "\t", grep { /^[^.]/ } readdir $dh; return $dirs; } else { return $path; } }; } elsif ( $type eq 'cat' ) { @cmd = sub { my $path = $self->repository . $args{path}; return ( 'No such file or directory' ) unless -e $path; return ( '', 'Is a directory' ) unless -f $path; local $/; open my $fh, '<', $path or die $!; my $c = <$fh>; return $c; }; } else { croak "invalid command: $type"; } return @cmd; } =item _yml =cut sub _yml { my $self = shift; my $path = shift; my $yml = shift; my $file = catfile( $self->repository, $path ); if ($yml) { Shipwright::Util::DumpFile( $file, $yml ); } else { Shipwright::Util::LoadFile($file); } } =item info =cut sub info { my $self = shift; my %args = @_; my $path = $args{path} || ''; my ( $info, $err ) = $self->SUPER::info( path => $path ); if (wantarray) { return $info, $err; } else { return $info; } } =item check_repository Check if the given repository is valid. =cut sub check_repository { my $self = shift; my %args = @_; if ( $args{action} eq 'create' ) { my $repo = $self->repository; if ( $args{force} || !-e $repo ) { return 1; } $self->log->fatal("$repo exists already"); return; } else { return $self->SUPER::check_repository(@_); } } sub _update_file { my $self = shift; my $path = shift; my $latest = shift; my $file = catfile( $self->repository, $path ); unlink $file; rcopy( $latest, $file ) or confess "can't copy $latest to $file: $!"; } sub _update_dir { my $self = shift; my $path = shift; my $latest = shift; my $dir = catfile( $self->repository, $path ); rcopy( $latest, $dir ) or confess "can't copy $latest to $dir: $!"; } =item import =cut sub import { my $self = shift; return unless ref $self; # get rid of class->import return $self->SUPER::import( @_, delete => 1 ); } =back =cut 1; __END__ =head1 AUTHORS sunnavy C<< >> =head1 LICENCE AND COPYRIGHT Shipwright is Copyright 2007-2009 Best Practical Solutions, LLC. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.