#!/usr/bin/perl # $Id$ =head1 NAME youri-upload - package upload agent =head1 VERSION Version 2.0 =head1 SYNOPSIS youri-upload [options] Options: --config use file as config file --skip-check skip check --skip-action skip action --define = pass additional values --list-targets list available targets --list-checks list configured checks for for --list-actions list configured actions for for --verbose verbose run --test test run --help print this help message =head1 DESCRIPTION B allows to upload packages in a repository. All packages given on command lines are passed to a list of check plugins, depending on given upload target. If none of them fails, all packages are passed to a list of action plugins, depending also on given upload target. =head1 OPTIONS =over =item B<--config> I Use given file as configuration, instead of normal one. =item B<--skip-check> I Skip check plugin with given identity. =item B<--skip-action> I Skip action plugin with given identity. =item B<--define> = Define additional parameters, to be used by plugins. =item B<--verbose> Produce more verbose output (can be used more than once) =item B<--test> Don't perform any modification. =item B<--list-targets> List available targets =item B<--list-checks> I List configured checks for given target =item B<--list-actions> I List configured actions for given target =item B<--help> Print a brief help message and exits. =back =head1 CONFIGURATION Configuration is read from the first file found among: =over =item * the one specified by B<--config> option on command-line =item * $HOME/.youri/upload.conf =item * /usr/local/etc/youri/upload.conf =back All additional configuration files specified by B directive are then processed. Then command line options. Any directive overrides prior definition. =over =item B I Uses space-separated list I as a list of additional configuration files. =item B I Declares a repository object with identity I. =item B I Declares a list of upload target objects with identity taken in space-separated list I. =back Each object declared in configuration must be fully defined later, using a configuration section, starting with bracketed object identity, followed by at least a class directive, then any number of additional object-specific directives. Example: objects = foo [foo] class = Foo::Bar key1 = value1 key2 = value2 =head1 SEE ALSO Youri::Config, for configuration file format. Each used plugin man page, for available options. =head1 COPYRIGHT AND LICENSE Copyright (C) 2002-2006, YOURI project This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut use strict; use warnings; use Youri::Config; use Youri::Utils; use Pod::Usage; my $config = Youri::Config->new( command_spec => [ 'config=s', 'skip-check=s@', 'skip-action=s@', 'list-targets!', 'list-checks=s', 'list-actions=s', 'define=s%', 'help|h!', 'test|t!', 'verbose|v!' ], file_spec => [ 'includes=s', 'targets=s', 'repository=s', ], directories => [ '@sysconfigdir', "$ENV{HOME}/.youri" ], file_name => 'upload.conf', caller => $0, ); # compute available targets first my %targets = map { $_ => 1 } split(/\s+/, $config->get('targets')); if ($config->get('list-targets')) { print join(' ', keys %targets) . "\n"; exit 0; } elsif ($config->get('list-checks')) { my %target = get_target_config($config->get('list-checks')); print join(' ', @{$target{checks}}) . "\n"; exit 0; } elsif ($config->get('list-actions')) { my %target = get_target_config($config->get('list-actions')); print join(' ', @{$target{actions}}) . "\n"; exit 0; } pod2usage(-verbose => 0, -message => "No target specified, aborting\n") unless @ARGV > 0; pod2usage(-verbose => 0, -message => "No packages specified, aborting\n") unless @ARGV > 1; # convenient global flags my $test = $config->get('test'); my $verbose = $config->get('verbose'); # check target my $target = shift @ARGV; my %target = get_target_config($target); # create repository my $repository; my $repository_id = $config->get('repository'); die "No repository declared" unless $repository_id; print "Creating repository $repository_id\n" if $verbose; eval { $repository = create_instance( 'Youri::Repository', test => $test, user => $config->get('define')->{user}, verbose => $verbose > 0 ? $verbose - 1 : 0, targets => [ keys %targets ], $config->get_section($repository_id) ); }; die "Failed to create repository $repository_id: $@\n" if $@; # create packages my @packages; foreach my $file (@ARGV) { push( @packages, create_instance( 'Youri::Package', class => $repository->get_package_class(), file => $file ) ); } # check all packages pass all tests my %skip_checks = map { $_ => 1 } @{$config->get('skip-check')}; foreach my $id (@{$target{checks}}) { next if $skip_checks{$id}; print "Creating check $id\n" if $verbose; my $check; eval { $check = create_instance( 'Youri::Upload::Check', id => $id, test => $test, user => $config->get('define')->{user}, verbose => $verbose > 0 ? $verbose - 1 : 0, $config->get_section($id) ); }; if ($@) { print STDERR "Failed to create check $id: $@\n"; } else { foreach my $package (@packages) { print "running check $id on package $package\n" if $verbose; unless ($check->run($package, $repository, $target, $config->get('define'))) { print STDERR "Error: " . $check->get_error() . ", aborting\n"; exit(1); } } } } # proceed further my %skip_actions = map { $_ => 1 } @{$config->get('skip-action')}; foreach my $id (@{$target{actions}}) { next if $skip_actions{$id}; print "Creating action $id\n" if $verbose; my $action; eval { $action = create_instance( 'Youri::Upload::Action', id => $id, test => $test, verbose => $verbose > 0 ? $verbose - 1 : 0, $config->get_section($id) ); }; if ($@) { print STDERR "Failed to create action $id: $@\n"; } else { foreach my $package (@packages) { print "running action $id on package $package\n" if $verbose; eval { $action->run($package, $repository, $target, $config->get('define')); }; if ($@) { print STDERR "Failed to run action $id on package $package: $@\n"; } } } } sub get_target_config { my ($id) = @_; die "Unavailable target $target" unless $targets{$id}; my %target = $config->get_section($id); die "Undefined target $id" unless %target; return %target; }