# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Repositorio::Repository::Yum; use Moose; use Try::Tiny; use File::Basename qw'basename'; use Data::Dumper; use Carp; use Params::Validate qw(:all); use File::Spec; use File::Path; use IO::All; use JSON::XS; # VERSION extends "Rex::Repositorio::Repository::Base"; sub mirror { my ( $self, %option ) = @_; $self->repo->{url} =~ s/\/$//; $self->repo->{local} =~ s/\/$//; my $name = $self->repo->{name}; my $pr = $self->app->progress_bar( title => "Downloading metadata...", length => 3, ); my ( $packages_ref, $repomd_ref ); ( $packages_ref, $repomd_ref ) = $self->_get_repomd_xml( $self->repo->{url} ); my @packages = @{$packages_ref}; try { $self->download_metadata( url => $self->repo->{url} . "/repodata/repomd.xml", dest => $self->repo->{local} . "/repodata/repomd.xml", force => $option{update_metadata}, ); $pr->update(2); $self->download_metadata( url => $self->repo->{url} . "/repodata/repomd.xml.asc", dest => $self->repo->{local} . "/repodata/repomd.xml.asc", force => $option{update_metadata}, ); $pr->update(3); } catch { $pr->update(3); $self->app->logger->error($_); }; $self->_download_packages( \%option, @packages ); print "\n"; print "\n"; $pr = $self->app->progress_bar( title => "Downloading rest of metadata...", length => scalar( @{ $repomd_ref->{data} } ), ); my $mi = 0; for my $file_data ( @{ $repomd_ref->{data} } ) { $mi++; $pr->update($mi); my $file_url = $self->{repo}->{url} . "/" . $file_data->{location}->[0]->{href}; my $file = basename $file_data->{location}->[0]->{href}; $self->download_metadata( url => $file_url, dest => $self->repo->{local} . "/repodata/$file", cb => sub { $self->_checksum( @_, $file_data->{checksum}->[0]->{type}, $file_data->{checksum}->[0]->{content} ); }, force => $option{update_metadata}, ); } if ( exists $self->repo->{images} && $self->repo->{images} eq "true" ) { print "\n"; print "\n"; $pr = $self->app->progress_bar( title => "Downloading images...", length => 7, ); my $ii = 0; for my $file ( ( "images/boot.iso", "images/efiboot.img", "images/efidisk.img", "images/install.img", "images/pxeboot/initrd.img", "images/pxeboot/vmlinuz", "images/upgrade.img", "LiveOS/squashfs.img", ) ) { $ii++; $pr->update($ii); my $file_url = $self->repo->{url} . "/" . $file; my $local_file = $self->repo->{local} . "/" . $file; try { $self->download_package( url => $file_url, name => $file, dest => $local_file, ); 1; } catch { $self->app->logger->error("Error downloading $file_url."); }; } } } sub _download_packages { my ( $self, $_option, @packages ) = @_; if ( !$_option->{update_files} && !$_option->{force} ) { return; } my %option = %{$_option}; my $i = 0; print "\n"; print "\n"; my $pr = $self->app->progress_bar( title => "Downloading packages...", length => scalar(@packages), ); for my $package (@packages) { $i++; $pr->update($i); my $package_url = $self->repo->{url} . "/" . $package->{location}; my $package_name = $package->{name}; my $local_file = $self->repo->{local} . "/" . $package->{location}; $self->download_package( url => $package_url, name => $package_name, dest => $local_file, cb => sub { $self->_checksum( @_, $package->{checksum}->{type}, $package->{checksum}->{data} ); }, update_file => $option{update_files}, force => $option{force}, ); } } sub _get_repomd_xml { my ( $self, $url ) = @_; my $repomd_ref = $self->decode_xml( $self->download("$url/repodata/repomd.xml") ); my ($primary_file) = grep { $_->{type} eq "primary" } @{ $repomd_ref->{data} }; $primary_file = $primary_file->{location}->[0]->{href}; $url = $url . "/" . $primary_file; $self->app->logger->debug("Downloading $url."); my $xml = $self->get_xml( $self->download_gzip($url) ); my @packages; my @xml_packages = $xml->getElementsByTagName('package'); for my $xml_package (@xml_packages) { my ($name_node) = $xml_package->getChildrenByTagName("name"); my ($checksum_node) = $xml_package->getChildrenByTagName("checksum"); my ($size_node) = $xml_package->getChildrenByTagName("size"); my ($location_node) = $xml_package->getChildrenByTagName("location"); push @packages, { location => $location_node->getAttribute("href"), name => $name_node->textContent, checksum => { type => $checksum_node->getAttribute("type"), data => $checksum_node->textContent, }, size => $size_node->getAttribute("archive"), }; } return ( \@packages, $repomd_ref ); } sub init { my $self = shift; my $repo_dir = $self->app->get_repo_dir( repo => $self->repo->{name} ); mkpath "$repo_dir/repodata"; $self->_run_createrepo(); } sub add_file { my $self = shift; my %option = validate( @_, { file => { type => SCALAR }, } ); my $dest = $self->app->get_repo_dir( repo => $self->repo->{name} ) . "/" . basename( $option{file} ); $self->add_file_to_repo( source => $option{file}, dest => $dest ); $self->_run_createrepo(); } sub remove_file { my $self = shift; my %option = validate( @_, { file => { type => SCALAR }, } ); my $file = $self->app->get_repo_dir( repo => $self->repo->{name} ) . "/" . basename( $option{file} ); $self->remove_file_from_repo( file => $file ); $self->_run_createrepo(); } sub _run_createrepo { my $self = shift; my $repo_dir = $self->app->get_repo_dir( repo => $self->repo->{name} ); if ( exists $self->repo->{gpg} && $self->repo->{gpg}->{key} ) { unlink "$repo_dir/repodata/repomd.xml.asc"; } system "cd $repo_dir ; createrepo ."; if ( $? != 0 ) { confess "Error running createrepo."; } if ( exists $self->repo->{gpg} && $self->repo->{gpg}->{key} ) { my $key = $self->repo->{gpg}->{key}; my $pass = $self->repo->{gpg}->{password}; if ( !$pass ) { $pass = $self->read_password("GPG key passphrase: "); } my $cmd = "cd $repo_dir ; gpg --default-key $key -a --batch --passphrase '" . $pass . "' --detach-sign repodata/repomd.xml"; system $cmd; if ( $? != 0 ) { $cmd =~ s/\Q$pass\E/\*\*\*\*\*\*\*/; confess "Error running: $cmd"; } # export pub key as asc file my $pub_file = $self->repo->{name} . ".asc"; $cmd = "cd $repo_dir ; gpg -a --output $pub_file --export $key"; system $cmd; if ( $? != 0 ) { confess "Error running gpg export: $cmd"; } } } # test if all necessary parameters are available override verify_options => sub { my $self = shift; super(); if ( !exists $self->repo->{local} ) { confess "No local path (local) given for: " . $self->repo->{name}; } }; 1;