view lib/Yours/Model/Repository.pm @ 2:f2a86753b494

implemented object model robust validation
author cin
date Tue, 22 Oct 2013 16:15:22 +0400
parents
children ae61af01bfa5
line wrap: on
line source

package Yours::Model::Repository;
use strict;

use File::Spec();
use IMPL::Exception();
use IMPL::Const qw(:prop);
use URI;
use IMPL::declare {
	require => {
		MDParser      => 'Yours::Parsers::MDParser',
		PMDParser     => 'Yours::Parsers::PMDParser',
		Uncompress    => 'IO::Uncompress::AnyUncompress',
		IOException   => '-IMPL::IOException',
		ArgException  => '-IMPL::InvalidArgumentException',
		FileValidator => 'Yours::FileValidator'
	  },
	  base  => [ 'IMPL::Object' => undef, ],
	  props => [
		name      => PROP_RW,
		localPath => PROP_RW,
		repoUrl   => PROP_RW
	  ]
};

sub CTOR {
	my ( $this, $name, $localPath, $repoUrl ) = @_;

	die ArgException->new( name => "A name is required" )
	  unless $name;
	die ArgException->new( localPath => "A localPath is required" )
	  unless $localPath;
	die ArgException->new( repoUrl => "A repoUrl is required" )
	  unless $repoUrl;

	$this->repoUrl( URI->new($repoUrl) );
	$this->localPath($localPath);
	$this->name($name);
}

sub GetMetadataFiles {
	my ($this) = @_;
	
	return {
		map {
			$this->GetLocalFile($_),
			{
				location => $this->GetRemoteLocation($_)
			}
		} (
			'repodata/repomd.xml',
			'repodata/repomd.xml.asc',
			'repodata/repomd.xml.key'
		)
	};
}

sub GetDescriptionFiles {
	my ($this) = @_;
	return {
		map {
			$this->GetLocalFile($_->{location}),
			{
				location => $this->GetRemoteLocation($_->{location}),
				checksum => $_->{checksum}
			}
		} @{$this->ReadMetadata()->{data} || []}
	};
}

sub GetLocalFile {
	my ( $this, $url ) = @_;

	my @parts = split /\//, $url;

	return File::Spec->catfile( $this->localPath, @parts );
}

sub GetRemoteLocation {
	my ( $this, $url ) = @_;

	return URI->new_abs( $url, $this->repoUrl );
}

sub ReadMetadata {
	my ($this) = @_;

	my $mdFile = $this->GetLocalFile('repodata/repomd.xml');

	die IOException->new( "File not found", $mdFile )
	  unless -f $mdFile;

	my $parser = MDParser->new();
	$parser->Parse( { location => $mdFile, no_blanks => 1 } );

	return $parser->data;
}

sub ProcessContent {
	my ( $this, $handler ) = @_;
	
	die ArgException->new(handler => 'A handler is required')
		unless $handler;

	my %index = map { $_->{type}, $_ } @{ $this->ReadMetadata()->{data} || [] };

	my $filePrimary = $this->GetLocalFile( $index{primary}{location} );

	die IOException->new( "File not found", $filePrimary )
	  unless -f $filePrimary;

	my $hdata = Uncompress->new($filePrimary)
	  or die IOException->new( "Failed to uncompress file", $filePrimary );

	PMDParser->new(sub {
		my ($meta) = shift;
		my $file = $this->GetLocalFile($meta->{location});
		$meta->{location} = $this->GetRemoteLocation($meta->{location});
		&$handler($file,$meta);
	})->Parse( { IO => $hdata, no_blanks => 1 } );
}

sub ValidateMetadata {
	my ($this) = @_;
	
	my $files = $this->GetMetadataFiles();
	
	my $validator = FileValidator->new(); 
	
	my @errors = $validator->Validate($files);
	
	return @errors if @errors;
	
	$files = $this->GetDescriptionFiles;
	
	return $validator->Validate($files);
}

sub ValidateContent {
	my ($this) = @_;
	
	my %files;
	
	$this->ProcessContent(sub {
		my ($meta) = @_;
		
		my $file = $this->GetLocalFile($meta->{location});
		
		$files{$file} = $meta;
	});
	
	return FileValidator->new()->Validate(\%files);
}

1;