aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--MANIFEST.SKIP11
-rw-r--r--Makefile.PL97
-rw-r--r--README45
-rw-r--r--TODO6
-rwxr-xr-xbin/youri-submit-proxy.in77
-rwxr-xr-xbin/youri-submit-restricted.in64
-rwxr-xr-xbin/youri-submit.in404
-rw-r--r--etc/bash_completion.d/youri-submit60
-rw-r--r--etc/submit.conf134
-rw-r--r--lib/Youri/Submit/Plugin.pm93
-rwxr-xr-xt/00distribution.t15
12 files changed, 853 insertions, 155 deletions
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..01e42c4
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2 @@
+2006-04-23 Guillaume Rousse <guillomovitch@zarb.org> 0.9
+ * initial release
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
new file mode 100644
index 0000000..f2568cb
--- /dev/null
+++ b/MANIFEST.SKIP
@@ -0,0 +1,11 @@
+\.tar\.gz$
+\.SKIP$
+~$
+^pm_to_blib$
+^Makefile$
+^Makefile\.old$
+^bin/youri-submit$
+^bin/youri-submit-restricted$
+^bin/youri-submit-proxy$
+.svn
+blib
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..e246de1
--- /dev/null
+++ b/Makefile.PL
@@ -0,0 +1,97 @@
+# $Id$
+use ExtUtils::MakeMaker;
+use Config;
+
+WriteMakefile(
+ NAME => 'youri-submit',
+ VERSION => 0.9,
+ AUTHOR => 'Youri project <youri@zarb.org>',
+ EXE_FILES => [
+ 'bin/youri-submit',
+ 'bin/youri-submit-restricted',
+ 'bin/youri-submit-proxy'
+ ],
+ PREREQ_PM => {
+ 'Youri::Config' => 0,
+ 'Youri::Utils' => 0,
+ 'Pod::Simple::HTMLBatch' => 0
+ },
+ PREFIX => '/usr/local',
+ INSTALLPRIVLIB => $Config{installprivlib},
+ INSTALLSITELIB => $Config{installsitelib},
+ INSTALLVENDORLIB => $Config{installvendorlib},
+ INSTALLMAN3DIR => $Config{installman3dir},
+ INSTALLSITEMAN3DIR => $Config{installsiteman3dir},
+ INSTALLVENDORMAN3DIR => $Config{installvendorman3dir},
+ INSTALLSCRIPT => '$(PREFIX)/bin',
+ INSTALLSITESCRIPT => '$(PREFIX)/bin',
+ INSTALLVENDORSCRIPT => '$(PREFIX)/bin',
+ INSTALLMAN1DIR => '$(PREFIX)/share/man/man1',
+ INSTALLSITEMAN1DIR => '$(PREFIX)/share/man/man1',
+ INSTALLVENDORMAN1DIR => '$(PREFIX)/share/man/man1',
+);
+
+package MY;
+
+sub post_constants {
+ my ($self) = @_;
+ my $sysconfdir = $self->{ARGS}->{SYSCONFDIR} || '$(PREFIX)/etc';
+ return <<EOF;
+SYSCONFDIR = $sysconfdir
+EOF
+}
+
+sub top_targets {
+ my ($self) = @_;
+ my $top_targets = $self->SUPER::top_targets(@_);
+ $top_targets =~ s/all :: pure_all manifypods/all :: pure_all manifypods htmlifypods/;
+ $top_targets .= <<'EOF';
+htmlifypods : $(TO_INST_PM)
+ if [ ! -d blib/html ]; then mkdir blib/html; fi
+ perl -MPod::Simple::HTMLBatch -e Pod::Simple::HTMLBatch::go lib blib/html
+ pod2html < bin/youri-submit > blib/html/youri-submit.html
+ pod2html < bin/youri-submit-restricted > blib/html/youri-submit-restricted.html
+ pod2html < bin/youri-submit-proxy > blib/html/youri-submit-proxy.html
+EOF
+ return $top_targets;
+}
+
+sub install {
+ my ($self) = @_;
+ my $install = $self->SUPER::install(@_);
+ $install =~ s/install :: all pure_install doc_install/install :: all pure_install doc_install config_install completion_install/;
+ $install .= <<'EOF';
+config_install :
+ install -d -m 755 $(DESTDIR)$(SYSCONFDIR)/youri
+ install -m 644 etc/submit.conf $(DESTDIR)$(SYSCONFDIR)/youri
+
+completion_install :
+ install -d -m 755 $(DESTDIR)$(SYSCONFDIR)/bash_completion.d
+ install -m 644 etc/bash_completion.d/youri-submit $(DESTDIR)$(SYSCONFDIR)/bash_completion.d
+EOF
+ return $install;
+}
+
+sub installbin {
+ my ($self) = @_;
+ my $installbin = $self->SUPER::installbin(@_);
+ $installbin .= <<'EOF';
+bin/youri-submit : bin/youri-submit.in Makefile
+ perl -p \
+ -e 's|\@sysconfdir\@|$(SYSCONFDIR)|;' \
+ < $< > $@
+
+bin/youri-submit-restricted : bin/youri-submit-restricted.in Makefile
+ perl -p \
+ -e 's|\@sysconfdir\@|$(SYSCONFDIR)|;' \
+ -e 's|\@bindir\@|$(PREFIX)/bin|;' \
+ < $< > $@
+
+bin/youri-submit-proxy : bin/youri-submit-proxy.in Makefile
+ perl -p \
+ -e 's|\@sysconfdir\@|$(SYSCONFDIR)|;' \
+ -e 's|\@bindir\@|$(PREFIX)/bin|;' \
+ < $< > $@
+EOF
+ return $installbin;
+}
diff --git a/README b/README
new file mode 100644
index 0000000..0b7a53f
--- /dev/null
+++ b/README
@@ -0,0 +1,45 @@
+YOURI project
+-------------
+
+YOURI stands for "Youri Offers an Upload & Repository Infrastucture". It aims
+to build tools making management of a coherent set of packages easier.
+
+Description
+-----------
+Managing a package repository involves many tasks, such as keeping packages
+tree tidy, generating packages indexes, synchronising bug report system,
+running coherency checks, checking for available updates, etc...
+
+Instead of a gazillion project-specific scripts, we aim to provide a generic package-format independant framework, so as to build coherent and robust tools.
+
+Components
+----------
+Available software in this release
+- youri-check allows to check packages
+- youri-upload allows to upload packages
+
+Installation
+------------
+To install, just use:
+perl Makefile.PL
+make
+make test
+
+All standard MakeMaker variables are usable, with the addition of SYSCONFDIR to
+specify configuration files destination.
+
+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.
+
+Authors
+-------
+Guillaume Rousse <guillomovitch@zarb.org>,
+Pascal Terjan <pterjan@zarb.org>
+Damien Krotkine <dams@zarb.org>
+Olivier Thauvin <nanardon@zarb.org>
+Ville Skyttä <ville.skytta@iki.fi>
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..b798b8a
--- /dev/null
+++ b/TODO
@@ -0,0 +1,6 @@
+1.0 Goals
+=========
+
+- svn support
+- automatic bugzilla ticket closing on upload
+- more customizable (template based ?) mail notification
diff --git a/bin/youri-submit-proxy.in b/bin/youri-submit-proxy.in
new file mode 100755
index 0000000..67fed6e
--- /dev/null
+++ b/bin/youri-submit-proxy.in
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+
+=head1 NAME
+
+youri-submit-proxy - proxy wrapper over youri-submit-restricted
+
+=head1 VERSION
+
+Version 1.0
+
+=head1 SYNOPSIS
+
+youri-submit-proxy [options] <target> <files>
+
+=head1 DESCRIPTION
+
+youri-submit-proxy is a proxy wrapper over youri-submit-restricted, intended to
+be used in collaborative work to change uid before calling it through sudo.
+
+=head1 SEE ALSO
+
+youri-submit-restricted(1), youri-submit(1)
+
+=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 Fcntl ':mode';
+use File::Basename;
+
+my ($uid, $gid);
+if (-l $0) {
+ # this is a symlink, get uid and gid from it
+ ($uid, $gid) = (lstat($0))[4, 5];
+} else {
+ ($uid, $gid) = (stat($0))[4, 5];
+}
+my $user = getpwuid($uid) or die "unknown uid $uid";
+my $prog = '@bindir@/youri-submit-restricted';
+
+my %dirs;
+my @options;
+foreach my $arg (@ARGV) {
+ if (-f $arg) {
+ # push parent dir in list
+ my $parent = dirname($arg);
+ $dirs{$parent}++;
+ }
+ push(@options, $arg);
+}
+
+foreach my $dir (keys %dirs) {
+ # save original perms and gid
+ my ($orig_mode, $orig_gid) = (stat($dir))[2,5];
+ $dirs{$dir} = {
+ mode => $orig_mode,
+ gid => $orig_gid
+ };
+ # ensure correct perms and gid
+ chown -1, $gid, $dir;
+ chmod $orig_mode|S_IRGRP|S_IWGRP, $dir;
+}
+
+# call wrapped program
+system('sudo', '-H', '-u', $user, $prog, @options);
+
+foreach my $dir (keys %dirs) {
+ # restore original perms and gid
+ chown -1, $dirs{$dir}->{gid}, $dir;
+ chmod $dirs{$dir}->{mode}, $dir;
+}
diff --git a/bin/youri-submit-restricted.in b/bin/youri-submit-restricted.in
new file mode 100755
index 0000000..d28ba84
--- /dev/null
+++ b/bin/youri-submit-restricted.in
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -T
+
+=head1 NAME
+
+youri-submit-restricted - filtering wrapper over youri-submit
+
+=head1 VERSION
+
+Version 1.0
+
+=head1 SYNOPSIS
+
+youri-submit-restricted [options] <target> <files>
+
+=head1 DESCRIPTION
+
+youri-submit-restricted is just a filtering wrapper over youri-submit, intended
+to be used in collaborative work to sanitize environment and options before
+calling it.
+
+=head1 SEE ALSO
+
+youri-submit(1)
+
+=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;
+
+my $prog = '@bindir@/youri-submit';
+my @prohibited_options = qw/--config --skip-check --skip-action/;
+my %prohibited_options = map { $_ => 1 } @prohibited_options;
+my @prohibited_envvars = qw/
+ ENV BASH_ENV IFS CDPATH
+ PERLLIB PERL5LIB PERL5OPT PERLIO
+ PERLIO_DEBUG PERL5DB PERL_ENCODING
+ PERL_HASH_SEED PERL_SIGNALS PERL_UNICODE
+/;
+
+my @options;
+while (my $arg = shift @ARGV) {
+ if ($prohibited_options{$arg}) {
+ # drop prohibited options
+ print STDERR "prohibited option $arg, skipping\n";
+ shift @ARGV;
+ } else {
+ # untaint everything else
+ $arg =~ /(.*)/;
+ push(@options, $1);
+ }
+}
+
+# secure ENV
+$ENV{PATH} = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin";
+delete $ENV{$_} foreach @prohibited_envvars;
+
+# call wrapped program
+system($prog, @options);
diff --git a/bin/youri-submit.in b/bin/youri-submit.in
index c232cfb..07118f1 100755
--- a/bin/youri-submit.in
+++ b/bin/youri-submit.in
@@ -3,7 +3,7 @@
=head1 NAME
-youri-upload - package upload agent
+youri-submit - package submission tool
=head1 VERSION
@@ -11,27 +11,30 @@ Version 2.0
=head1 SYNOPSIS
-youri-upload [options] <target> <files>
+youri-submit [options] <target> <files>
+youri-submit --list <category> [target]
+
+youri-submit --help [category] [item]
+
Options:
--config <file> use file <file> as config file
--skip-pre <pre> skip pre <pre>
- --skip-action <action> skip action <action>
--skip-check <check> skip check <check>
+ --skip-action <action> skip action <action>
--skip-post <post> skip post <post>
--skip-reject <reject> skip reject <reject>
--define <key>=<value> pass additional values
- --list-targets list available targets
- --list-checks <target> list configured checks for for <target>
- --list-actions <target> list configured actions for for <target>
+ --clean delete package after success
--verbose verbose run
--test test run
- --help print this help message
+ --list <category> list items from given category
+ --help [category] display contextual help
=head1 DESCRIPTION
-B<youri-upload> allows to upload packages in a repository.
+B<youri-submit> allows to submit packages to 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
@@ -69,6 +72,10 @@ Skip reject action plugin with given identity.
Define additional parameters, to be used by plugins.
+=item B<--clean>
+
+Delete submited packages upon successfull submission.
+
=item B<--verbose>
Produce more verbose output (can be used more than once)
@@ -77,21 +84,16 @@ Produce more verbose output (can be used more than once)
Don't perform any modification.
-=item B<--list-targets>
-
-List available targets
-
-=item B<--list-checks> I<target>
-
-List configured checks for given target
-
-=item B<--list-actions> I<target>
-
-List configured actions for given target
-
-=item B<--help>
-
-Print a brief help message and exits.
+=item B<--list> I<category>
+
+List available items from given category and exits. Category must be either
+B<targets>, B<actions> or B<checks>. A target is needed for the two last ones.
+
+=item B<--help> I<category>
+
+Display help for given category and exits. Category must be either
+B<repository>, B<action> or B<check>. An item is needed for the two last ones.
+If no category given, display standard help.
=back
@@ -103,48 +105,51 @@ Configuration is read from the first file found among:
=item * the one specified by B<--config> option on command-line
-=item * $HOME/.youri/upload.conf
-
-=item * @sysconfdir@/youri/upload.conf
+=item * $HOME/.youri/submit.conf
+
+=item * @sysconfdir@/youri/submit.conf
=back
-All additional configuration files specified by B<includes> directive are then
-processed. Then command line options. Any directive overrides prior definition.
+The configuration file should be a YAML-format files, with the following
+mandatory top-level directives:
=over
-=item B<includes> I<files>
+=item B<repository>
-Uses space-separated list I<files> as a list of additional configuration files.
+The definition of repository plugin to be used.
-=item B<repository> I<id>
+=item B<targets>
-Declares a repository object with identity I<id>.
+The list of available submission targets, each one being composed from the
+following keys:
-=item B<targets> I<ids>
+=over
-Declares a list of upload target objects with identity taken in space-separated list I<ids>.
+=item B<checks>
+
+The list of check plugins to use for this target.
+
+=item B<actions>
+
+The list of action plugins to use for this target.
=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.
+=item B<checks>
+
+The list of check plugin definitions, indexed by their identity.
-Example:
+=item B<actions>
+
+The list of action plugin definitions, indexed by their identity.
- objects = foo
-
- [foo]
- class = Foo::Bar
- key1 = value1
- key2 = value2
+=back
=head1 SEE ALSO
-Youri::Config, for configuration file format.
+Youri::Config, for additional details about configuration file format.
Each used plugin man page, for available options.
@@ -164,90 +169,136 @@ use Youri::Utils;
use Pod::Usage;
my $config = Youri::Config->new(
- command_spec => [
- 'config=s',
- 'skip-pre=s@',
- 'skip-check=s@',
- 'skip-action=s@',
- 'skip-post=s@',
- 'skip-reject=s@',
- 'list-targets!',
- 'list-checks=s',
- 'list-actions=s',
- 'define=s%',
- 'help|h!',
- 'test|t!',
- 'server|s',
- 'verbose|v!'
- ],
- file_spec => [
- 'includes=s',
- 'targets=s',
- 'repository=s',
- ],
- directories => [ '@sysconfdir@', "$ENV{HOME}/.youri" ],
- file_name => 'upload.conf',
- caller => $0,
+ args => {
+ 'skip-check' => '=s@',
+ 'skip-action' => '=s@',
+ 'define' => '=s%',
+ 'verbose' => '|v!',
+ 'clean' => '!',
+ 'test' => '|t!',
+ 'list' => '|l!'
+ 'config' => '=s',
+ 'skip-prei' => '=s@',
+ 'skip-post' => '=s@',
+ 'skip-reject' => '=s@',
+ },
+ directories => [ "$ENV{HOME}/.youri", '@sysconfdir@/youri' ],
+ file => 'submit.conf',
);
-# 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";
+if ($config->get_arg('list')) {
+ my $category = $ARGV[0];
+ pod2usage(-verbose => 0, -message => "No category specified, aborting\n")
+ unless $category;
+ if ($category eq 'targets') {
+ print join(' ', keys %{$config->get_param('targets')});
+ } elsif ($category eq 'checks' || $category eq 'actions') {
+ my $target = $ARGV[1];
+ pod2usage(-verbose => 0, -message => "No target specified, aborting\n")
+ unless $target;
+ if ($category eq 'checks') {
+ my $checks = $config->get_param('targets')->{$target}->{checks};
+ print join(' ', @{$checks}) if $checks;
+ } else {
+ my $actions = $config->get_param('targets')->{$target}->{actions};
+ print join(' ', @{$actions}) if $actions;
+ }
+ } else {
+ pod2usage(-verbose => 0, -message => "Invalid category $category, aborting\n")
+ }
+ print "\n";
exit 0;
}
+if ($config->get_arg('help')) {
+ my $category = $ARGV[0];
+ my ($item, $section);
+ if ($category eq 'repository') {
+ $section = $config->get_param('repository');
+ pod2usage(
+ -verbose => 0,
+ -message => "No repository defined, aborting\n"
+ ) unless $section;
+ } elsif ($category eq 'check' || $category eq 'action') {
+ $item = $ARGV[1];
+ pod2usage(
+ -verbose => 0,
+ -message => "No item specified, aborting\n"
+ ) unless $item;
+ if ($category eq 'check') {
+ $section = $config->get_param('checks')->{$item};
+ pod2usage(
+ -verbose => 0,
+ -message => "No such check $item defined, aborting\n"
+ ) unless $section;
+ } else {
+ $section = $config->get_param('actions')->{$item};
+ pod2usage(
+ -verbose => 0,
+ -message => "No such action $item defined, aborting\n"
+ ) unless $section;
+ }
+ } else {
+ pod2usage(-verbose => 0, -message => "Invalid category $category, aborting\n")
+ }
+ my $file = $section->{class} . '.pm';
+ $file =~ s/::/\//g;
+ pod2usage(
+ -verbose => 99,
+ -sections => 'NAME|DESCRIPTION',
+ -input => $file,
+ -pathlist => \@INC
+ );
+}
+
+
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');
+my $test = $config->get_arg('test');
+my $verbose = $config->get_arg('verbose');
# check target
my $target = shift @ARGV;
-my %target = get_target_config($target);
+my $target_conf = $config->get_param('targets')->{$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;
+my $repository_conf = $config->get_param('repository');
+die "No repository declared" unless $repository_conf;
+print "Creating repository\n" if $verbose;
eval {
$repository = create_instance(
'Youri::Repository',
- test => $test,
- verbose => $verbose > 0 ? $verbose - 1 : 0,
- targets => [ keys %targets ],
- $config->get_section($repository_id)
+ $repository_conf,
+ {
+ test => $test,
+ verbose => $verbose > 0 ? $verbose - 1 : 0,
+ targets => [ keys %{$config->get_param('targets')} ],
+ }
);
};
-die "Failed to create repository $repository_id: $@\n" if $@;
+die "Failed to create repository: $@\n" if $@;
# perfrom pre action
my %skip_pres = map { $_ => 1 } @{$config->get('skip-pre')};
my $pre_packages = [];
my $ok = 1;
-foreach my $id (@{$target{pre}}) {
+foreach my $id (@{$target_conf->{pre}}) {
next if $skip_pres{$id};
print "Creating pre $id\n" if $verbose;
my $pre;
eval {
$pre = create_instance(
'Youri::Upload::Pre',
- id => $id,
- test => $test,
- verbose => $verbose > 0 ? $verbose - 1 : 0,
- $config->get_section($id)
+ {
+ id => $id,
+ test => $test,
+ verbose => $verbose > 0 ? $verbose - 1 : 0,
+ }
);
};
if ($@) {
@@ -272,29 +323,42 @@ foreach my $group ((map { [ { section => "", file => $_ } ] } @ARGV), @$pre_pac
@packages,
create_instance(
'Youri::Package',
- class => $repository->get_package_class(),
- file => $opt->{file},
- %$opt
+ {
+ class => $repository->get_package_class(),
+ },
+ {
+ file => $opt->{file},
+ %$opt
+ },
)
);
}
@packages or next;
# check all packages pass all tests
- my %skip_checks = map { $_ => 1 } @{$config->get('skip-check')};
- my $ok = 1;
+ my %errors;
+ my $skip_check = $config->get_arg('skip-check');
+ my %skip_check = $skip_check ? map { $_ => 1 } @{$skip_check} : ();
my @error;
- foreach my $id (@{$target{checks}}) {
+ foreach my $id (@{$target_conf->{checks}}) {
next if $skip_checks{$id};
print "Creating check $id\n" if $verbose;
my $check;
+ my $check_conf = $config->get_param('checks')->{$id};
+
+ if (!$check_conf) {
+ print STDERR "No such check $id, skipping\n";
+ next;
+ }
eval {
$check = create_instance(
'Youri::Upload::Check',
- id => $id,
- test => $test,
- verbose => $verbose > 0 ? $verbose - 1 : 0,
- $config->get_section($id)
+ $check_conf,
+ {
+ id => $id,
+ test => $test,
+ verbose => $verbose > 0 ? $verbose - 1 : 0,
+ }
);
};
if ($@) {
@@ -302,30 +366,40 @@ foreach my $group ((map { [ { section => "", file => $_ } ] } @ARGV), @$pre_pac
} else {
foreach my $package (@packages) {
print "running check $id on package $package\n" if $verbose;
- unless ($check->run($package, $repository, $target, $config->get('define'))) {
- my $err = $check->get_error();
- print STDERR "Error: $err\n";
- push @error, $err;
- $ok = 0
- }
+ my @errors = $check->run(
+ $package,
+ $repository,
+ $target,
+ $config->get_arg('define')
+ );
+ push(@{$errors{$package}}, @errors) if @errors;
+ }
+ }
+ if (%errors) {
+ print "Submission errors, aborting:\n";
+ foreach my $package (keys %errors) {
+ print "- $package:\n";
+ foreach my $error (@{$errors{$package}}) {
+ print " - $error\n";
}
-
}
- }
- if (!$ok) {
# reject the packages
- my %skip_rejects = map { $_ => 1 } @{$config->get('skip-reject')};
- foreach my $id (@{$target{rejects}}) {
+ my $skip_rejects = $config->get_arg('skip-reject');
+ my %skip_rejects = $skip_rejects ? map { $_ => 1 } @{$skip_rejects} : ();
+ foreach my $id (@{$target_conf{rejects}}) {
next if $skip_rejects{$id};
print "Creating reject $id\n" if $verbose;
my $reject;
+ my $reject_conf = $config->get_param('rejects')->{$id};
eval {
$reject = create_instance(
'Youri::Upload::Reject',
- id => $id,
- test => $test,
- verbose => $verbose > 0 ? $verbose - 1 : 0,
- $config->get_section($id)
+ $reject_conf,
+ {
+ id => $id,
+ test => $test,
+ verbose => $verbose > 0 ? $verbose - 1 : 0,
+ }
);
};
if ($@) {
@@ -334,7 +408,7 @@ foreach my $group ((map { [ { section => "", file => $_ } ] } @ARGV), @$pre_pac
foreach my $package (@packages) {
print "running reject $id on package $package\n" if $verbose;
eval {
- $reject->run($package, \@error, $repository, $target, $config->get('define'));
+ $reject->run($package, \%errors, $repository, $target, $config->get('define'));
};
if ($@) {
print STDERR "Failed to run action $id on package $package: $@\n";
@@ -346,48 +420,70 @@ foreach my $group ((map { [ { section => "", file => $_ } ] } @ARGV), @$pre_pac
}
# proceed further
- my %skip_actions = map { $_ => 1 } @{$config->get('skip-action')};
- foreach my $id (@{$target{actions}}) {
+ my $skip_action = $config->get_arg('skip-action');
+ my %skip_action = $skip_action ? map { $_ => 1 } @{$skip_action} : ();
+ foreach my $id (@{$target_conf->{actions}}) {
next if $skip_actions{$id};
print "Creating action $id\n" if $verbose;
my $action;
+ my $action_conf = $config->get_param('actions')->{$id};
+
+ if (!$action_conf) {
+ print STDERR "No such action $id, skipping\n";
+ next;
+ }
eval {
$action = create_instance(
'Youri::Upload::Action',
- id => $id,
- test => $test,
- verbose => $verbose > 0 ? $verbose - 1 : 0,
- $config->get_section($id)
+ $action_conf,
+ {
+ id => $id,
+ test => $test,
+ verbose => $verbose > 0 ? $verbose - 1 : 0,
+ }
);
};
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";
- }
- }
- }
+ foreach my $package (@packages) {
+ print "running action $id on package $package\n" if $verbose;
+ eval {
+ $action->run(
+ $package,
+ $repository,
+ $target,
+ $config->get_arg('define')
+ );
+ };
+ if ($@) {
+ print STDERR "Failed to run action $id on package $package: $@\n";
+ }
+ }
}
}
# perfrom post action
-my %skip_posts = map { $_ => 1 } @{$config->get('skip-post')};
-foreach my $id (@{$target{post}}) {
- next if $skip_posts{$id};
+my $skip_post = $config->get_arg('skip-post');
+my %skip_post = $skip_post ? map { $_ => 1 } @{$skip_post} : ();
+foreach my $id (@{$target_conf->{post}}) {
+ next if $skip_post{$id};
print "Creating post $id\n" if $verbose;
my $post;
+ my $post_conf = $config->get_param('posts')->{$id};
+
+ if (!$post_conf) {
+ print STDERR "No such action $id, skipping\n";
+ next;
+ }
eval {
$post = create_instance(
'Youri::Upload::Post',
- id => $id,
- test => $test,
- verbose => $verbose > 0 ? $verbose - 1 : 0,
- $config->get_section($id)
+ $post_conf,
+ {
+ id => $id,
+ test => $test,
+ verbose => $verbose > 0 ? $verbose - 1 : 0,
+ }
);
};
if ($@) {
@@ -400,11 +496,9 @@ foreach my $id (@{$target{post}}) {
}
}
-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;
+if ($config->get('clean')) {
+ foreach my $package (@packages) {
+ print "cleaning file $package\n" if $verbose;
+ unlink $package->as_file();
+ }
}
diff --git a/etc/bash_completion.d/youri-submit b/etc/bash_completion.d/youri-submit
new file mode 100644
index 0000000..be2f6e5
--- /dev/null
+++ b/etc/bash_completion.d/youri-submit
@@ -0,0 +1,60 @@
+# youri-submit completion
+# $Id$
+
+_youri-submit()
+{
+
+ local cur prev config
+
+ COMPREPLY=()
+ cur=${COMP_WORDS[COMP_CWORD]}
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ --config)
+ _filedir
+ return 0
+ ;;
+ --list)
+ COMPREPLY=( $( compgen -W 'targets checks actions' -- $cur ) )
+ return 0
+ ;;
+ --help)
+ COMPREPLY=( $( compgen -W 'repository check action' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--define --clean -l --list -h --help -t \
+ --test -v --verbose' -- $cur ) )
+ # add dangereous option for main command
+ if [[ ${COMP_WORDS[0]} == youri-submit ]]; then
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]} --config --skip-check \
+ --skip-action' -- $cur ) )
+ fi
+ else
+ _count_args
+ case $args in
+ 1)
+ _find_config
+ COMPREPLY=( $( compgen -W '$( youri-submit $config --list targets )' -- $cur ) )
+ ;;
+ *)
+ _filedir
+ ;;
+ esac
+ fi
+
+}
+complete -F _youri-submit youri-submit youri-submit-restricted youri-submit-proxy
+
+_find_config()
+{
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == --config ]]; then
+ config="--config ${COMP_WORDS[i+1]}"
+ break
+ fi
+ done
+}
diff --git a/etc/submit.conf b/etc/submit.conf
new file mode 100644
index 0000000..db12918
--- /dev/null
+++ b/etc/submit.conf
@@ -0,0 +1,134 @@
+# youri-submit sample configuration file
+# $Id$
+
+# helper variables
+home: /home/user
+
+# repository definition
+repository:
+ class: Youri::Repository::PLF
+ options:
+ install_root: ${home}/ftp/mandriva
+ version_root: ${home}/cvs
+ archive_root: ${home}/backup/mandriva
+ noarch: i586
+
+# targets definitions
+targets:
+ cooker:
+ checks:
+ - tag
+ - recency
+ - history
+ actions:
+ - sign
+ - install
+ - link
+ - archive
+ - clean
+ - bugzilla
+ - cvs
+ - mail
+ - rss
+
+ 2006.0:
+ checks:
+ - type
+ - tag
+ - recency
+ - history
+ - precedence
+ actions:
+ - sign
+ - install
+ - link
+ - archive
+ - clean
+
+# checks definitions
+checks:
+ tag:
+ class: Youri::Submit::Check::Tag
+ options:
+ tags:
+ release: 'plf$'
+ packager: '<\w+@zarb\.org>$'
+ distribution: '^Mandriva Linux$'
+ vendor: '^Penguin Liberation Front$'
+
+ recency:
+ class: Youri::Submit::Check::Recency
+
+ history:
+ class: Youri::Submit::Check::History
+
+ precedence:
+ class: Youri::Submit::Check::Precedence
+ options:
+ target: cooker
+
+ type:
+ class: Youri::Submit::Check::Type
+ type: binary
+
+# actions definitions
+actions:
+ sign:
+ class: Youri::Submit::Action::Sign
+ options:
+ name: plf@zarb.org
+ path: ${home}/.gnupg
+ passphrase: s3kr3t
+
+ install:
+ class: Youri::Submit::Action::Install
+
+ link:
+ class: Youri::Submit::Action::Link
+
+ archive:
+ class: Youri::Submit::Action::Archive
+
+ clean:
+ class: Youri::Submit::Action::Clean
+
+ mail:
+ class: Youri::Submit::Action::Mail
+ options:
+ mta: /usr/sbin/sendmail
+ to: plf-announce@zarb.org
+ reply_to: plf-discuss@zarb.org
+ from: plf@zarb.org
+ prefix: RPM
+ cc:
+ hot-base: david@dindinx.org bellamy@neverland.net
+ dcgui: mathen@ketelhot.de
+ dclib: mathen@ketelhot.de
+ Video-DVDRip: dvdrip-users@exit1.org
+ hackVideo-DVDRip: dvdrip-users@exit1.org
+ goosnes: tak@bard.sytes.net
+ avidemux: fixounet@free.fr
+ vobcopy: robos@muon.de
+ drip: drip-devel@lists.sourceforge.net
+ libdscaler: vektor@dumbterm.net
+ xawdecode: pingus77@ifrance.com
+
+ rss:
+ class: Youri::Submit::Action::RSS
+ options:
+ file: ${home}/www/changelog.rss
+ title: PLF packages updates
+ link: http://plf.zarb.org/
+ description: ChangeLog for PLF packages
+
+ cvs:
+ class: Youri::Submit::Action::CVS
+
+ bugzilla:
+ class: Youri::Submit::Action::Bugzilla
+ options:
+ host: localhost
+ base: plf_bugs
+ user: plf
+ pass: s3kr3t
+ contact: plf@zarb.org
diff --git a/lib/Youri/Submit/Plugin.pm b/lib/Youri/Submit/Plugin.pm
new file mode 100644
index 0000000..17c3c32
--- /dev/null
+++ b/lib/Youri/Submit/Plugin.pm
@@ -0,0 +1,93 @@
+# $Id: Base.pm 631 2006-01-26 22:22:23Z guillomovitch $
+package Youri::Submit::Plugin;
+
+=head1 NAME
+
+Youri::Submit::Plugin - Abstract youri-submit plugin
+
+=head1 DESCRIPTION
+
+This abstract class defines youri-submit plugin interface.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+
+=head1 CLASS METHODS
+
+=head2 new(%args)
+
+Creates and returns a new Youri::Submit::Plugin object.
+
+No generic parameters (subclasses may define additional ones).
+
+Warning: do not call directly, call subclass constructor instead.
+
+=cut
+
+sub new {
+ my $class = shift;
+ croak "Abstract class" if $class eq __PACKAGE__;
+
+ my %options = (
+ id => '', # object id
+ test => 0, # test mode
+ verbose => 0, # verbose mode
+ @_
+ );
+
+ my $self = bless {
+ _id => $options{id},
+ _test => $options{test},
+ _verbose => $options{verbose},
+ }, $class;
+
+ $self->_init(%options);
+
+ return $self;
+}
+
+sub _init {
+ # do nothing
+}
+
+=head1 INSTANCE METHODS
+
+=head2 get_id()
+
+Returns plugin identity.
+
+=cut
+
+sub get_id {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_id};
+}
+
+=head2 run($package, $repository, $target, $define)
+
+Execute action on given L<Youri::Package> object.
+
+=head1 SUBCLASSING
+
+The following methods have to be implemented:
+
+=over
+
+=item run
+
+=back
+
+=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
+
+1;
diff --git a/t/00distribution.t b/t/00distribution.t
new file mode 100755
index 0000000..8a4b2c4
--- /dev/null
+++ b/t/00distribution.t
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+# $Id$
+
+use Test::More;
+
+BEGIN {
+ eval {
+ require Test::Distribution;
+ };
+ if($@) {
+ plan skip_all => 'Test::Distribution not installed';
+ } else {
+ import Test::Distribution only => [ qw/use pod description/ ];
+ }
+}