view lib/Yours/SyncRepository.pm @ 4:8001dc056331

fixed problems with sax parser fixed handling of empty repos added log autoflush
author sergey
date Wed, 23 Oct 2013 11:49:16 +0400
parents ae61af01bfa5
children
line wrap: on
line source

package Yours::SyncRepository;
use strict;

use File::Path qw(make_path);
use File::Spec();
use IMPL::Const qw(:prop);
use IMPL::declare {
	require => {
		UserAgent => 'LWP::UserAgent',
		Exception => 'IMPL::Exception',
		Validator => 'Yours::FileValidator'
	},
	base => [
		'IMPL::Object' => undef,
		'IMPL::Object::Autofill' => '@_'
	],
	props => [
		agent => PROP_RO,
		log => PROP_RO,
		skipSrc => PROP_RO,
		skipDebug => PROP_RO,
		_dirs => PROP_RW,
		_files => PROP_RW
	]
};

sub CTOR {
	my ($this, $opts) = @_;
	
	$opts ||= {};
	
	$this->log($opts->{log});
	$this->skipSrc($opts->{skipSrc});
	$this->skipDebug($opts->{skipDebug});
	$this->_dirs({});
	$this->_files({});
	
	my $agent = UserAgent->new();
	$agent->env_proxy;
	
	$this->agent($agent);
}

sub _RegisterFile {
	my ($this,$file,$md) = @_;
	
	my ($vol,$dir) = File::Spec->splitpath($file);
	
	make_path($dir);
		
	$this->_dirs->{$dir} = 1;
	$this->_files->{$file} = $md;
}

sub _FetchFile {
	my ($this,$file,$md,$dieOnError) = @_;
	
	if ($md->{size}) {
		$this->Log("    fetch %s  [%.2fM]", $md->{location}, $md->{size}/(1024*1024));
	} else {
		$this->Log("    fetch %s", $md->{location});
	}
			
	my $resp = $this->agent->get(
		$md->{location},
		':content_file' => $file
	);
	
	unless($resp->is_success) {
		$this->Log("      %s %s", $resp->code, $resp->message);
		die Exception->new($resp->code,$resp->message)
			if $dieOnError; 
	}
}

sub Update {
	my ($this,$repo) = @_;
	
	$this->Log("Updating %s [%s]", $repo->name, $repo->repoUrl);
	
	$this->Log("  loading metadata");
	my $files = $repo->GetMetadataFiles;
	while( my ($file,$md) = each %$files ) {
		$this->_RegisterFile($file,$md);
		
		$this->_FetchFile($file,$md,'die')
	}
	
	$this->Log("  loading description");
	$files = $repo->GetDescriptionFiles;
	while( my ($file,$md) = each %$files ) {
		$this->_RegisterFile($file,$md);
		
		$this->_FetchFile($file,$md,'die')
			unless -f $file;
	}
	
	my $retry = 3;
	$this->Log("  validating metadata");
	while(my @errors = $repo->ValidateMetadata()) {
		die Exception->new("Unable to complete due errors")
			unless $retry;
		$retry--;
		
		foreach my $err (@errors) {
			$this->Log("    %s: %s", $err->{file},$err->{message});
			$this->_FetchFile($err->{file},$err->{metadata});
		}
	}
	
	$this->Log("  downloading content");
	$repo->ProcessContent(sub {
		my ($file,$md) = @_;
		
		return if $this->skipSrc and $md->{arch} eq 'src';
		return if $this->skipDebug and $md->{name} =~ /debuginfo|debugsource/;
		
		$this->_RegisterFile($file,$md);
		
		$this->_FetchFile($file,$md)
			unless -f $file;
	});
	
	$this->Log("  clenup");
	$this->_Cleanup;
	
	$this->Log("  validate");
	
	$retry = 3;
	my $validateFiles = $this->_files;
	
	while(my @errors = Validator->new()->Validate($validateFiles)) {
		die Exception->new("Unable to complete due errors")
			unless $retry;
		$this->Log("  attempt to fix problems");
		$retry--;
		
		$validateFiles = {};		
		
		foreach my $err (@errors) {
			$this->Log("    %s: %s", $err->{file},$err->{message});
			
			$this->_FetchFile($err->{file},$err->{metadata});
			
			$validateFiles->{$err->{file}} = $err->{metadata};
		}
	}
	
	return;
}

sub _Cleanup {
	my ($this) = @_;
	
	my $dirs = $this->_dirs;
	my $files = $this->_files; 
	
	foreach my $dir (keys %$dirs) {
		if (opendir(my $hdir, $dir)) {
			while(my $file = readdir $hdir) {
				next if $file eq '.' || $file eq '..';
				my $fullPath = File::Spec->catfile($dir,$file);
				next unless -f $fullPath;
				
				unless( $files->{$fullPath} ){
					$this->Log("    - %s",$file);
					unlink $fullPath;
				}
			}
		}
	}
}

sub Repair {
	my ($this) = @_;
}

sub Log {
	my ($this,$format,@args) = @_;
	
	if (my $h = $this->log) {
		printf $h ($format,@args);
		print $h "\n";
		$h->flush;
	}
}

1;