From abc9a802404902718dc808fdce36f226533f02de Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Fri, 7 Jan 2011 08:07:11 +0000 Subject: get_file_name returns a full path, which Install does not like --- ChangeLog | 606 ++++++++++++++++++++++++++++++ MANIFEST.SKIP | 11 + Makefile.PL | 97 +++++ README | 45 +++ TODO | 6 + bin/youri-check.in | 395 +++++++++++++++++++ bin/youri-submit | 534 ++++++++++++++++++++++++++ bin/youri-submit-proxy.in | 77 ++++ bin/youri-submit-restricted.in | 64 ++++ bin/youri-submit.in | 534 ++++++++++++++++++++++++++ etc/bash_completion.d/youri-submit | 60 +++ etc/submit.conf | 134 +++++++ lib/Youri/Submit/Action.pm | 27 ++ lib/Youri/Submit/Action/Archive.pm | 90 +++++ lib/Youri/Submit/Action/Bugzilla.pm | 81 ++++ lib/Youri/Submit/Action/CVS.pm | 135 +++++++ lib/Youri/Submit/Action/Clean.pm | 40 ++ lib/Youri/Submit/Action/DkmsModuleInfo.pm | 111 ++++++ lib/Youri/Submit/Action/Install.pm | 75 ++++ lib/Youri/Submit/Action/Link.pm | 80 ++++ lib/Youri/Submit/Action/Mail.pm | 131 +++++++ lib/Youri/Submit/Action/Markrelease.pm | 56 +++ lib/Youri/Submit/Action/RSS.pm | 102 +++++ lib/Youri/Submit/Action/Rpminfo.pm | 69 ++++ lib/Youri/Submit/Action/Send.pm | 77 ++++ lib/Youri/Submit/Action/Sendcache.pm | 81 ++++ lib/Youri/Submit/Action/Sign.pm | 56 +++ lib/Youri/Submit/Action/Unpack.pm | 82 ++++ lib/Youri/Submit/Action/UpdateMdvDb.pm | 62 +++ lib/Youri/Submit/Check.pm | 27 ++ lib/Youri/Submit/Check/ACL.pm | 71 ++++ lib/Youri/Submit/Check/History.pm | 61 +++ lib/Youri/Submit/Check/Host.pm | 63 ++++ lib/Youri/Submit/Check/Precedence.pm | 58 +++ lib/Youri/Submit/Check/Queue_recency.pm | 40 ++ lib/Youri/Submit/Check/Recency.pm | 64 ++++ lib/Youri/Submit/Check/Rpmlint.pm | 90 +++++ lib/Youri/Submit/Check/SVN.pm | 79 ++++ lib/Youri/Submit/Check/Section.pm | 58 +++ lib/Youri/Submit/Check/Source.pm | 45 +++ lib/Youri/Submit/Check/Tag.pm | 61 +++ lib/Youri/Submit/Check/Type.pm | 54 +++ lib/Youri/Submit/Check/Version.pm | 102 +++++ lib/Youri/Submit/Plugin.pm | 93 +++++ lib/Youri/Submit/Post.pm | 27 ++ lib/Youri/Submit/Post/CleanRpmsrate.pm | 53 +++ lib/Youri/Submit/Post/Gendistrib.pm | 66 ++++ lib/Youri/Submit/Post/Genhdlist2.pm | 82 ++++ lib/Youri/Submit/Pre.pm | 27 ++ lib/Youri/Submit/Pre/Rsync.pm | 87 +++++ lib/Youri/Submit/Reject.pm | 27 ++ lib/Youri/Submit/Reject/Archive.pm | 61 +++ lib/Youri/Submit/Reject/Clean.pm | 36 ++ lib/Youri/Submit/Reject/Install.pm | 63 ++++ lib/Youri/Submit/Reject/Mail.pm | 112 ++++++ t/00distribution.t | 15 + 56 files changed, 5540 insertions(+) create mode 100644 ChangeLog create mode 100644 MANIFEST.SKIP create mode 100644 Makefile.PL create mode 100644 README create mode 100644 TODO create mode 100755 bin/youri-check.in create mode 100755 bin/youri-submit create mode 100755 bin/youri-submit-proxy.in create mode 100755 bin/youri-submit-restricted.in create mode 100755 bin/youri-submit.in create mode 100644 etc/bash_completion.d/youri-submit create mode 100644 etc/submit.conf create mode 100644 lib/Youri/Submit/Action.pm create mode 100644 lib/Youri/Submit/Action/Archive.pm create mode 100644 lib/Youri/Submit/Action/Bugzilla.pm create mode 100644 lib/Youri/Submit/Action/CVS.pm create mode 100644 lib/Youri/Submit/Action/Clean.pm create mode 100644 lib/Youri/Submit/Action/DkmsModuleInfo.pm create mode 100644 lib/Youri/Submit/Action/Install.pm create mode 100644 lib/Youri/Submit/Action/Link.pm create mode 100644 lib/Youri/Submit/Action/Mail.pm create mode 100644 lib/Youri/Submit/Action/Markrelease.pm create mode 100644 lib/Youri/Submit/Action/RSS.pm create mode 100644 lib/Youri/Submit/Action/Rpminfo.pm create mode 100644 lib/Youri/Submit/Action/Send.pm create mode 100644 lib/Youri/Submit/Action/Sendcache.pm create mode 100644 lib/Youri/Submit/Action/Sign.pm create mode 100644 lib/Youri/Submit/Action/Unpack.pm create mode 100644 lib/Youri/Submit/Action/UpdateMdvDb.pm create mode 100644 lib/Youri/Submit/Check.pm create mode 100644 lib/Youri/Submit/Check/ACL.pm create mode 100644 lib/Youri/Submit/Check/History.pm create mode 100644 lib/Youri/Submit/Check/Host.pm create mode 100644 lib/Youri/Submit/Check/Precedence.pm create mode 100644 lib/Youri/Submit/Check/Queue_recency.pm create mode 100644 lib/Youri/Submit/Check/Recency.pm create mode 100644 lib/Youri/Submit/Check/Rpmlint.pm create mode 100644 lib/Youri/Submit/Check/SVN.pm create mode 100644 lib/Youri/Submit/Check/Section.pm create mode 100644 lib/Youri/Submit/Check/Source.pm create mode 100644 lib/Youri/Submit/Check/Tag.pm create mode 100644 lib/Youri/Submit/Check/Type.pm create mode 100644 lib/Youri/Submit/Check/Version.pm create mode 100644 lib/Youri/Submit/Plugin.pm create mode 100644 lib/Youri/Submit/Post.pm create mode 100644 lib/Youri/Submit/Post/CleanRpmsrate.pm create mode 100644 lib/Youri/Submit/Post/Gendistrib.pm create mode 100644 lib/Youri/Submit/Post/Genhdlist2.pm create mode 100644 lib/Youri/Submit/Pre.pm create mode 100644 lib/Youri/Submit/Pre/Rsync.pm create mode 100644 lib/Youri/Submit/Reject.pm create mode 100644 lib/Youri/Submit/Reject/Archive.pm create mode 100644 lib/Youri/Submit/Reject/Clean.pm create mode 100644 lib/Youri/Submit/Reject/Install.pm create mode 100644 lib/Youri/Submit/Reject/Mail.pm create mode 100755 t/00distribution.t diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..031adca --- /dev/null +++ b/ChangeLog @@ -0,0 +1,606 @@ +2008-02-19 07:50 pixel + + * lib/Youri/Submit/Action/Unpack.pm: fix "grep_files" handling + +2008-02-12 09:42 blino + + * lib/Youri/Submit/Check/Rpmlint.pm: do not make rpmlint errors + fatal anymore (asked by fcrozat) + +2008-02-08 17:49 blino + + * lib/Youri/Submit/Check/Rpmlint.pm: remove results occurences and + update doc + +2008-02-08 17:48 blino + + * lib/Youri/Submit/Check/Rpmlint.pm: make all rpmlint errors fatal + +2008-02-08 17:44 blino + + * lib/Youri/Submit/Check/Rpmlint.pm: removed unneeded parentheses + +2008-02-08 17:44 blino + + * lib/Youri/Submit/Check/Rpmlint.pm: make clear + repository/target/define are unused + +2008-02-08 17:43 blino + + * lib/Youri/Submit/Check/Rpmlint.pm: use scalar for fd + +2008-01-31 16:35 pixel + + * lib/Youri/Submit/Action/Link.pm: also call ->set_arch_changed + when linking a noarch file to another arch + (this still doesn't explain media/media_info/MD5SUM not being + remade, but it + can help...) + +2007-12-21 14:37 blino + + * bin/youri-submit.in: merge youri-submit into youri-submit.in + +2007-12-19 13:43 blino + + * lib/Youri/Submit/Action/Archive.pm: only log main/updates + modifications, not contrib/updates or non-free/updates which are + legal + +2007-12-19 13:37 blino + + * lib/Youri/Submit/Action/Archive.pm: add spuk's debug code for bug + 34999 + +2007-12-17 19:45 blino + + * bin/youri-submit: add an "allow_omitting_packages" global option, + to be able to run youri even if no packages are specified on the + command line (useful if packages are fetched in pre action) + +2007-12-17 19:34 blino + + * bin/youri-submit: improve error messages for pres/posts actions + (patch from raoh's copy, probably from warly) + +2007-12-17 19:33 blino + + * bin/youri-submit: fix typo about posts actions (patch from raoh's + copy, probably from warly) + +2007-12-13 15:01 pixel + + * lib/Youri/Submit/Check/Version.pm: - empty {authorized_users} + doesn't imply every one is allowed to bypass freeze check! + - {authorized_users} should be checked more strictly + +2007-12-07 18:26 spuk + + * lib/Youri/Submit/Action/Sendcache.pm: - make Sendcache send debug + packages only if explicitly told to, to save space + +2007-11-30 19:29 spuk + + * lib/Youri/Submit/Action/UpdateMdvDb.pm: Youri action to update + the Mandriva maintainers database. + +2007-10-04 20:07 blino + + * lib/Youri/Submit/Check/Host.pm: make host reject message more + explicit by print arch (useful when VMware-player for x86_64 + actually uses i386 as rpm arch...) + +2007-09-26 11:21 blino + + * lib/Youri/Submit/Action/Install.pm: improve log message + +2007-09-26 11:19 blino + + * lib/Youri/Submit/Action/Install.pm: fix installed filename (oops) + +2007-09-26 09:58 blino + + * lib/Youri/Submit/Action/Install.pm: throw exception on failure, + not to delete files that can be copied because of lack of space + (upstream commit 1398) + +2007-09-25 10:49 pixel + + * lib/Youri/Submit/Action/Unpack.pm: allow to unpack only some + files (for release-notes.txt in mandriva-release-common) + +2007-09-22 13:11 blino + + * lib/Youri/Submit/Check/Version.pm: allow authorized users to + upload everything even during full freeze + +2007-08-31 12:51 pixel + + * lib/Youri/Submit/Check/Rpmlint.pm: handle new rpmlint format + (not useful at the moment since we still use old rpmlint, but may + be useful in + the future) + +2007-08-31 10:03 blino + + * lib/Youri/Submit/Action/DkmsModuleInfo.pm: adapt to new + SOURCEPACKAGE value in prebuilt dkms kernel + +2007-08-29 13:21 blino + + * lib/Youri/Submit/Action/DkmsModuleInfo.pm: initial + Youri::Submit::Action::DkmsModuleInfo module + +2007-08-07 12:50 pixel + + * lib/Youri/Submit/Action/Link.pm: we need the same workaround as + done in Action::Install + +2007-07-16 09:27 blino + + * lib/Youri/Submit/Post/Genhdlist2.pm: remove unused variable + +2007-07-08 02:44 spuk + + * lib/Youri/Submit/Check/Recency.pm: - check for newer/current + revisions in default section when submitted to another section + (bug #30635) + +2007-07-02 09:17 pixel + + * lib/Youri/Submit/Action/CVS.pm: drop mdv specific stuff (mdv + doesn't use this action anymore) + +2007-06-28 07:40 pixel + + * lib/Youri/Submit/Action/Link.pm: do update hdlist for every arch + after linking noarch packages (#31638) + +2007-06-28 07:37 pixel + + * lib/Youri/Submit/Action/Install.pm: simplify ($arch is not used + by ->set_install_dir_changed) + +2007-06-23 13:54 pixel + + * lib/Youri/Submit/Action/Mail.pm, lib/Youri/Submit/Reject/Mail.pm: + keep raw changelogs to avoid changing the format (backport) + +2007-06-23 08:10 spuk + + * lib/Youri/Submit/Check/Recency.pm: - check for newer and same + existing revisions in a single pass + - use proper get_revisions() instead of get_install_file() hack, + as the + latter will use the current file name, and thus will fail to + check for an + existing package revision when submitting, because submitted + SRPMs have a + different name ("@rev:foobar-...") than what goes into the + repository + +2007-06-22 13:51 pixel + + * lib/Youri/Submit/Post/CleanRpmsrate.pm: ensure we don't do + anything if nothing changed + +2007-06-22 13:41 pixel + + * lib/Youri/Submit/Post/Genhdlist2.pm: more atomic generation of + MD5SUM + +2007-06-22 13:35 pixel + + * lib/Youri/Submit/Post/Genhdlist2.pm: - need to redo global + MD5SUM. This MD5SUM is mostly obsolete, but is still needed up to + 2007.1 + (and needed even on cooker for existing urpmi.cfg) + - don't use --blind. hopefully not needed + +2007-06-22 06:45 pixel + + * lib/Youri/Submit/Post/Genhdlist2.pm: call genhdlist2 with (new) + option --allow-empty-media + +2007-06-21 10:13 blino + + * lib/Youri/Submit/Post/CleanRpmsrate.pm: uniquify arch list + +2007-06-21 08:16 pixel + + * lib/Youri/Submit/Action/Install.pm, + lib/Youri/Submit/Post/Genhdlist2.pm: new action Genhdlist2 + +2007-06-14 18:23 mrl + + * lib/Youri/Submit/Action/Sendcache.pm: - As this action is unique, + avoid too much flexibility and simplify the code. + - Use . for hidding temporary files instead of .new suffix. + +2007-06-13 18:36 mrl + + * lib/Youri/Submit/Action/Sendcache.pm: - Adapted for working with + iurt cache. + +2007-06-13 01:48 spuk + + * lib/Youri/Submit/Action/Link.pm: no such 'cd' function, 'chdir' + it is... + +2007-05-08 06:22 spuk + + * lib/Youri/Submit/Reject/Mail.pm: fixing the Big SVN Breakage: + reverting last commit, restoring state as of latest working + checkout in ken + +2007-05-08 06:06 spuk + + * lib/Youri/Submit/Post/Gendistrib.pm: fixing the Big SVN Breakage: + restoring state as of working checkout in ken + +2007-05-08 06:00 spuk + + * lib/Youri/Submit/Action/Scp.pm: fixing the Big SVN Breakage: + Scp.pm was changed into Send.pm + +2007-05-05 06:16 spuk + + * lib/Youri/Submit/Check/Section.pm: Check if package submission + was for the correct section. + +2007-03-24 11:36 spuk + + * lib/Youri/Submit/Action/Archive.pm: - moved hack for verbosity to + start of code, with a remark + - removed double $path from debug string + +2007-03-15 12:36 mrl + + * lib/Youri/Submit/Check/Version.pm: - Fixed version_freeze mode: + do not allow any upload with a different version + from what is already present on the repository. + - Added an ACL control for maintainers allowed to bypass this + restriction as option + authorized_users. + +2007-03-15 12:32 mrl + + * lib/Youri/Submit/Check/Version.pm: - Improved indentation. + - Added some comments regarding possible bugs in freeze modes. + +2005-05-24 14:40 Sawyer + + * lib/Youri/Submit/Reject/Mail.pm: LOST + +2007-03-10 07:49 spuk + + * lib/Youri/Submit/Action/Archive.pm: The extra '/' was causing the + string to not be matched by the regexp below + for getting $rep_section and $rep_main_section, in the end making + the SRPMs + of all other subsections be removed when a newer package was + uploaded for any + subsection. (#28719) + +2007-02-26 10:56 blino + + * lib/Youri/Submit/Post/CleanRpmsrate.pm: initial + Post::CleanRpmsrate module + +2007-02-14 12:10 blino + + * lib/Youri/Submit/Check/Rpmlint.pm: match rpmlint errors that have + no value (such as non-xdg-migrated-menu, the only one we + currently use...) + +2007-02-09 22:11 blino + + * bin/youri-submit: get -> get_arg + +2007-02-09 22:09 blino + + * bin/youri-submit: merge changes from ken/kenobi + +2007-02-09 22:09 blino + + * bin/youri-submit: create youri-submit from youri-submit.in + +2007-02-09 19:39 blino + + * lib/Youri/Submit/Check/ACL.pm: add section in acl error message + +2007-02-09 19:34 blino + + * lib/Youri/Submit/Reject/Mail.pm: do not use packager adress as + from, it may be invalid (non-free packages) or not subscribed to + maintainers + +2007-02-09 18:51 blino + + * lib/Youri/Submit/Reject/Mail.pm: fix changelog in reject mail + +2007-02-09 18:50 blino + + * lib/Youri/Submit/Reject/Mail.pm: fix reject mail + +2007-02-08 17:28 pixel + + * lib/Youri/Submit/Action/Unpack.pm: also give directories to "cpio + -pdu" to ensure directories are created with same rights + +2007-02-08 14:09 pixel + + * lib/Youri/Submit/Action/Unpack.pm: This action plugin unpack + package files somewhere. + When unpack_inside_distribution_root is set, dest_directory is + relative to the distribution root. + When the package is a noarch, the wanted files are unpacked in + distribution root of each archs. + + eg: + unpack_installer_images: + class: Youri::Submit::Action::Unpack + options: + name: drakx-installer-images + source_subdir: /usr/lib*/drakx-installer-images + dest_directory: . + unpack_inside_distribution_root: 1 + +2007-01-30 10:02 pixel + + * lib/Youri/Submit/Check/ACL.pm, lib/Youri/Submit/Check/Host.pm, + lib/Youri/Submit/Check/Queue_recency.pm, + lib/Youri/Submit/Check/Rpmlint.pm, lib/Youri/Submit/Check/SVN.pm, + lib/Youri/Submit/Check/Source.pm, lib/Youri/Submit/Check/Type.pm, + lib/Youri/Submit/Check/Version.pm, lib/Youri/Submit/Pre/Rsync.pm, + lib/Youri/Submit/Reject/Archive.pm, + lib/Youri/Submit/Reject/Clean.pm, + lib/Youri/Submit/Reject/Install.pm, + lib/Youri/Submit/Reject/Mail.pm: fix $Id$ expansion + +2007-01-30 10:01 pixel + + * lib/Youri/Submit/Plugin.pm, lib/Youri/Submit/Post.pm, + lib/Youri/Submit/Pre.pm, lib/Youri/Submit/Reject.pm: fix pod and + $Id$ expansion + +2007-01-30 10:00 pixel + + * lib/Youri/Submit/Post.pm: fix pod + +2007-01-30 09:59 pixel + + * lib/Youri/Submit/Action/Send.pm: fix pod + +2007-01-30 09:58 pixel + + * lib/Youri/Submit/Action/Markrelease.pm, + lib/Youri/Submit/Action/Scp.pm: fix pod + +2007-01-30 09:49 pixel + + * lib/Youri/Submit/Action/Clean.pm, + lib/Youri/Submit/Action/Link.pm, + lib/Youri/Submit/Action/Markrelease.pm, + lib/Youri/Submit/Action/Rpminfo.pm, + lib/Youri/Submit/Action/Scp.pm, lib/Youri/Submit/Action/Send.pm: + fix $Id$ expansion + +2007-01-26 11:25 blino + + * lib/Youri/Submit/Check/ACL.pm: really match section in ACL + +2007-01-26 11:24 blino + + * lib/Youri/Submit/Check/ACL.pm: fix arch ACL matching (and thus + allow ACLs to match again) + +2006-12-24 10:31 mandrake + + * lib/Youri/Submit/Post.pm, lib/Youri/Submit/Pre.pm, + lib/Youri/Submit/Reject.pm: Removing previous pristine/ + directory. + +2006-12-24 03:15 mandrake + + * lib/Youri/Submit/Action.pm: %repsys markrelease + version: 1.0 + release: 0.20061223.3mdv2007.1 + revision: 101968 + + Copying 1.0-0.20061223.3mdv2007.1 to releases/ directory. + +2006-10-16 16:05 warly + + * lib/Youri/Submit/Check.pm: merging dev with upstream + +2006-11-14 22:01 mrl + + * lib/Youri/Submit/Action/Rpminfo.pm: - Renamed package name tag. + +2006-11-14 16:38 mrl + + * lib/Youri/Submit/Action/RpmInfo.pm, + lib/Youri/Submit/Action/Rpminfo.pm: - Renamed, due to some + enforcement (cfengine?). + +2006-11-14 13:23 mrl + + * lib/Youri/Submit/Action/RpmInfo.pm: - Added package summary to + .info files. + +2006-11-13 12:40 mrl + + * lib/Youri/Submit/Action/RpmInfo.pm: - First version of web + interface. + +2006-10-31 11:40 mandrake + + * lib/Youri/Submit/Action/Archive.pm: unlink file in Archive for + the moment (should be done in clean but the code to detect which + packages is obsoleted has to be moved + +2006-10-26 11:26 mandrake + + * lib/Youri/Submit/Action/CVS.pm: we perform CVS commit + asynchronously + +2006-10-26 11:21 mandrake + + * lib/Youri/Submit/Action/Install.pm: rename the rpm to remove the + prefix + +2006-10-26 11:18 mandrake + + * lib/Youri/Submit/Action/Mail.pm: fix double . + +2006-10-26 11:16 mandrake + + * lib/Youri/Submit/Post/Gendistrib.pm: add gendistrib command + directly into gendistrib module + +2006-10-26 11:14 mandrake + + * lib/Youri/Submit/Pre/Rsync.pm: return correct packages table for + groups + +2006-10-26 11:10 mandrake + + * lib/Youri/Submit/Reject/Install.pm: get_reject_path seems to be + the new name + +2006-10-26 11:07 mandrake + + * lib/Youri/Submit/Reject/Mail.pm: $last_change is sometime empty + +2006-10-24 11:07 warly + + * bin/youri-submit.in: exit with an error code if an error occured + in one group; s/Upload/Submit/; use new structure name from + upstream + +2006-10-23 11:48 warly + + * lib/Youri/Submit/Check/ACL.pm, + lib/Youri/Submit/Check/Queue_recency.pm, + lib/Youri/Submit/Check/Rpmlint.pm, lib/Youri/Submit/Check/SVN.pm, + lib/Youri/Submit/Check/Source.pm, + lib/Youri/Submit/Check/Version.pm: must return an empty value + +2006-10-18 12:46 warly + + * lib/Youri/Submit/Check/Rpmlint.pm: remove debug code + +2006-10-17 16:10 warly + + * lib/Youri/Submit/Check/ACL.pm: now checks must return the error + message + +2006-10-17 16:04 warly + + * lib/Youri/Submit/Check/ACL.pm, lib/Youri/Submit/Check/Host.pm, + lib/Youri/Submit/Check/Queue_recency.pm, + lib/Youri/Submit/Check/Rpmlint.pm, lib/Youri/Submit/Check/SVN.pm, + lib/Youri/Submit/Check/Source.pm, + lib/Youri/Submit/Check/Version.pm: now checks must return the + error message + +2006-10-17 15:16 warly + + * lib/Youri/Submit/Action/Clean.pm, + lib/Youri/Submit/Action/Link.pm, lib/Youri/Submit/Check/ACL.pm, + lib/Youri/Submit/Check/Host.pm, + lib/Youri/Submit/Check/Queue_recency.pm, + lib/Youri/Submit/Check/SVN.pm, lib/Youri/Submit/Check/Source.pm, + lib/Youri/Submit/Check/Type.pm, + lib/Youri/Submit/Check/Version.pm, lib/Youri/Submit/Post.pm, + lib/Youri/Submit/Pre.pm, lib/Youri/Submit/Reject.pm: + s/Upload/Submit/g + +2006-10-17 13:53 warly + + * ., ChangeLog, MANIFEST.SKIP, Makefile.PL, README, TODO, + bin/youri-submit-proxy.in, bin/youri-submit-restricted.in, + bin/youri-submit.in, etc, etc/bash_completion.d, + etc/bash_completion.d/youri-submit, etc/submit.conf, + lib/Youri/Submit/Plugin.pm, t, t/00distribution.t: merge with + upstream + +2006-10-16 16:27 warly + + * lib/Youri/Submit/Post/Gendistrib.pm, + lib/Youri/Submit/Pre/Rsync.pm, + lib/Youri/Submit/Reject/Archive.pm, + lib/Youri/Submit/Reject/Clean.pm, + lib/Youri/Submit/Reject/Install.pm, + lib/Youri/Submit/Reject/Mail.pm: Now the module is Submit and not + Upload + +2006-10-16 16:26 warly + + * lib/Youri/Submit/Check, lib/Youri/Submit/Check/History.pm, + lib/Youri/Submit/Check/Precedence.pm, + lib/Youri/Submit/Check/Recency.pm, + lib/Youri/Submit/Check/Rpmlint.pm, lib/Youri/Submit/Check/Tag.pm, + lib/Youri/Submit/Check/Type.pm: merging dev with upstream + +2006-10-16 16:15 warly + + * lib/Youri/Submit/Post.pm, lib/Youri/Submit/Pre.pm, + lib/Youri/Submit/Reject.pm: now plugins are complete abstract + classes + +2006-10-16 16:08 warly + + * lib/Youri/Submit/Action.pm: merging dev with upstream + +2006-10-16 16:05 warly + + * lib/Youri/Submit/Check.pm: merging dev with upstream + +2006-10-16 13:03 warly + + * lib/Youri/Submit/Action/Markrelease.pm, + lib/Youri/Submit/Action/Scp.pm, lib/Youri/Submit/Action/Send.pm: + Now the Module is Submit + +2006-10-16 12:57 warly + + * lib/Youri/Submit/Action, lib/Youri/Submit/Action/Archive.pm, + lib/Youri/Submit/Action/Bugzilla.pm, + lib/Youri/Submit/Action/CVS.pm, lib/Youri/Submit/Action/Clean.pm, + lib/Youri/Submit/Action/Install.pm, + lib/Youri/Submit/Action/Link.pm, lib/Youri/Submit/Action/Mail.pm, + lib/Youri/Submit/Action/RSS.pm, lib/Youri/Submit/Action/Sign.pm: + merging dev with upstream + +2006-10-16 11:33 warly + + * bin/youri-check.in: add new youri subsections (from upstream) + +2006-10-16 11:30 warly + + * lib/Youri/Submit: add new youri subsections (from upstream) + +2006-10-16 11:30 warly + + * lib/Youri: add new youri subsections (from upstream) + +2006-10-16 11:30 warly + + * lib: add new youri subsections (from upstream) + +2006-10-16 11:22 warly + + * bin/youri-submit.in: add new youri subsections (from upstream) + +2006-10-16 11:18 warly + + * bin: add new youri subsections (from upstream) + +2006-10-16 11:18 warly + + * .: add new youri subsections (from upstream) + +2006-04-23 Guillaume Rousse 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..09ff7f7 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,97 @@ +# $Id: Makefile.PL 1723 2006-10-17 13:53:27Z warly $ +use ExtUtils::MakeMaker; +use Config; + +WriteMakefile( + NAME => 'youri-submit', + VERSION => 0.9, + AUTHOR => 'Youri project ', + 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 <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 , +Pascal Terjan +Damien Krotkine +Olivier Thauvin +Ville Skyttä + 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-check.in b/bin/youri-check.in new file mode 100755 index 0000000..b32f4fd --- /dev/null +++ b/bin/youri-check.in @@ -0,0 +1,395 @@ +#!/usr/bin/perl +# $Id: youri-check.in 1699 2006-10-16 11:33:58Z warly $ + +=head1 NAME + +youri-check - package check agent + +=head1 VERSION + +Version 1.0 + +=head1 SYNOPSIS + +youri-check [options] + +Options: + + --config use file as config file + --skip-media skip media + --skip-plugin skip plugin + --parallel parallel run + --verbose verbose run + --test test run + --help print this help message + +=head1 DESCRIPTION + +B allows to check packages in a repository. + +In input mode, all medias defined in configuration are passed to a list of +input plugins, each of them storing their result in a persistent resultset. In +output mode, this resultset is passed to a list of output plugins, each of them +producing arbitrary effects. + +=head1 OPTIONS + +=over + +=item B<--config> + +Use given file as configuration, instead of normal one. + +=item B<--skip-media> + +Skip media with given identity. + +=item B<--skip-plugin> + +Skip plugin with given identity. + +=item B<--parallel> + +Run all plugins parallelously + +=item B<--verbose> + +Produce more verbose output (can be used more than once) + +=item B<--test> + +Don't perform any modification. + +=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/check.conf + +=item * @sysconfdir@/youri/check.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 + +Declare a maintainer resolver object with identity I. + +=item B I + +Declare a maintainer preferences object with identity I. + +=item B I + +Declare a resultset object with identity I. + +=item B I + +Declares a list of media objects with identity taken in space-separated list +I. + +=item B I + +Declares a list of input plugin objects with identity taken in space-separated +list I. + +=item B I + +Declares a list of output plugin 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; +use Net::Config qw/%NetConfig/; +use DateTime; + +my $config = Youri::Config->new( + command_spec => [ + 'config=s', + 'skip-plugin=s@', + 'skip-media=s@', + 'parallel!', + 'help|h!', + 'test|t!', + 'verbose|v!' + ], + file_spec => [ + 'includes=s', + 'resolver=s', + 'preferences=s', + 'resultset=s', + 'medias=s', + 'inputs=s', + 'outputs=s' + ], + directories => [ '@sysconfdir@', "$ENV{HOME}/.youri" ], + file_name => 'check.conf', + caller => $0, +); + +pod2usage( + -verbose => 0, + -message => "No mode specified, aborting\n" +) unless @ARGV; + +my $mode = $ARGV[0]; + +# convenient global flags +my $test = $config->get('test'); +my $verbose = $config->get('verbose'); + +# libnet configuration +my %netconfig = $config->get_section('netconfig'); +$NetConfig{$_} = $netconfig{$_} foreach keys %netconfig; + +# resultset creation +my $resultset_id = $config->get('resultset'); +die "No resultset defined" unless $resultset_id; + +report("Creating resultset $resultset_id"); +my $resultset = create_instance( + 'Youri::Check::Resultset', + test => $test, + verbose => $verbose > 0 ? $verbose - 1 : 0, + $config->get_section($resultset_id) +); + +my $children; + +my %skip_plugins = map { $_ => 1 } @{$config->get('skip-plugin')}; + +if ($mode eq 'input') { + + # additional objects + + my $resolver; + my $resolver_id = $config->get('resolver'); + if ($resolver_id) { + report("Creating maintainer resolver $resolver_id"); + eval { + $resolver = create_instance( + 'Youri::Check::Maintainer::Resolver', + test => $test, + verbose => $verbose > 1 ? $verbose - 2 : 0, + $config->get_section($resolver_id) + ); + }; + print STDERR "Failed to create maintainer resolver $resolver_id: $@\n" if $@; + } + + my $preferences; + my $preferences_id = $config->get('preferences'); + if ($preferences_id) { + report("Creating maintainer preferences $preferences_id"); + eval { + $preferences = create_instance( + 'Youri::Check::Maintainer::Preferences', + test => $test, + verbose => $verbose > 1 ? $verbose - 2 : 0, + $config->get_section($preferences_id) + ); + }; + print STDERR "Failed to create maintainer preferences $preferences_id: $@\n" if $@; + } + + my @medias; + my %skip_medias = map { $_ => 1 } @{$config->get('skip-media')}; + foreach my $id (split(/\s+/, $config->get('medias'))) { + next if $skip_medias{$id}; + report("Creating media $id"); + eval { + push( + @medias, + create_instance( + 'Youri::Media', + id => $id, + test => $test, + verbose => $verbose > 0 ? $verbose - 1 : 0, + $config->get_section($id) + ) + ); + }; + print STDERR "Failed to create media $id: $@\n" if $@; + } + + # prepare resultset + $resultset->reset(); + $resultset->set_resolver($resolver); + + + foreach my $id (split(/\s+/, $config->get('inputs'))) { + next if $skip_plugins{$id}; + report("Creating input $id"); + my $input; + eval { + $input = create_instance( + 'Youri::Check::Input', + id => $id, + test => $test, + verbose => $verbose > 0 ? $verbose - 1 : 0, + resolver => $resolver, + preferences => $preferences, + $config->get_section($id) + ); + }; + if ($@) { + print STDERR "Failed to create input $id: $@\n"; + } else { + if ($config->get('parallel')) { + # fork + my $pid = fork; + die "Can't fork: $!" unless defined $pid; + if ($pid) { + # parent process + $children++; + next; + } + } + eval { + $input->prepare(@medias); + }; + if ($@) { + print STDERR "Failed to prepare input $id: $@\n"; + } else { + # clone resultset in child process + $resultset = $config->get('parallel') ? + $resultset->clone() : + $resultset; + + foreach my $media (@medias) { + next if $media->skip_input($id); + my $media_id = $media->get_id(); + report("running input $id on media $media_id"); + eval { + $input->run($media, $resultset); + }; + if ($@) { + print STDERR "Failed to run input $id on media $media_id: $@\n"; + } + } + } + if ($config->get('parallel')) { + # child process + exit; + } + } + } + +} elsif ($mode eq 'output') { + + foreach my $id (split(/\s+/, $config->get('outputs'))) { + next if $skip_plugins{$id}; + report("Creating output $id"); + my $output; + eval { + $output = create_instance( + 'Youri::Check::Output', + id => $id, + test => $test, + verbose => $verbose > 0 ? $verbose - 1 : 0, + config => $config, + $config->get_section($id) + ); + }; + if ($@) { + print STDERR "Failed to create output $id: $@\n"; + } else { + if ($config->get('parallel')) { + # fork + my $pid = fork; + die "Can't fork: $!" unless defined $pid; + if ($pid) { + # parent process + $children++; + next; + } + } + + # clone resultset in child process + $resultset = $config->get('parallel') ? + $resultset->clone() : + $resultset; + + report("running output $id"); + eval { + $output->run($resultset); + }; + if ($@) { + print STDERR "Failed to run output $id: $@\n"; + } + + if ($config->get('parallel')) { + # child process + exit; + } + } + } +} else { + die "Invalid mode $mode"; +} + +# wait for all forked processus termination +while ($children) { + wait; + $children--; +} + +sub report { + my ($message) = @_; + print DateTime->now()->strftime('[%H:%M:%S] ') + if $verbose > 1; + print "$message\n" + if $verbose > 0; +} diff --git a/bin/youri-submit b/bin/youri-submit new file mode 100755 index 0000000..2cec209 --- /dev/null +++ b/bin/youri-submit @@ -0,0 +1,534 @@ +#!/usr/bin/perl +# $Id: youri-submit 232579 2007-12-17 19:45:47Z blino $ + +=head1 NAME + +youri-submit - package submission tool + +=head1 VERSION + +Version 2.0 + +=head1 SYNOPSIS + +youri-submit [options] + +youri-submit --list [target] + +youri-submit --help [category] [item] + +Options: + + --config use file as config file + --skip-pre
       skip pre 
+    --skip-check    skip check 
+    --skip-action  skip action 
+    --skip-post      skip post 
+    --skip-reject  skip reject 
+    --define = pass additional values
+    --clean                delete package after success
+    --verbose              verbose run
+    --test                 test run
+    --list       list items from given category
+    --help [category]      display contextual help
+
+=head1 DESCRIPTION
+
+B 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
+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-pre> I
+
+Skip pre transaction plugin with given identity
+
+=item B<--skip-check> I
+
+Skip check plugin with given identity.
+
+=item B<--skip-action> I
+
+Skip action plugin with given identity.
+
+=item B<--skip-post> I
+
+Skip post transaction plugin with given identity.
+
+=item B<--skip-reject> I
+
+Skip reject action plugin with given identity.
+
+=item B<--define> =
+
+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)
+
+=item B<--test>
+
+Don't perform any modification.
+
+=item B<--list> I
+ 
+List available items from given category and exits. Category must be either
+B, B or B. A target is needed for the two last ones.
+ 
+=item B<--help> I
+ 
+Display help for given category and exits. Category must be either
+B, B or B. An item is needed for the two last ones.
+If no category given, display standard help.
+
+=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/submit.conf
+ 
+=item * /usr/local/etc/youri/submit.conf
+
+=back
+
+The configuration file should be a YAML-format files, with the following
+mandatory top-level directives:
+
+=over
+
+=item B
+
+The definition of repository plugin to be used.
+
+=item B
+
+The list of available submission targets, each one being composed from the
+following keys:
+
+=over
+
+=item B
+
+The list of check plugins to use for this target.
+
+=item B
+
+The list of action plugins to use for this target.
+
+=back
+
+=item B
+
+The list of check plugin definitions, indexed by their identity.
+
+=item B
+ 
+The list of action plugin definitions, indexed by their identity.
+
+=back
+
+=head1 SEE ALSO
+
+Youri::Config, for additional details about 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(
+    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", '/usr/local/etc/youri' ],
+    file => 'submit.conf',
+);
+
+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 || $config->get_param('allow_omitting_packages');
+
+# convenient global flags
+my $test    = $config->get_arg('test');
+my $verbose = $config->get_arg('verbose');
+
+# check target
+my $target = shift @ARGV;
+my $target_conf = $config->get_param('targets')->{$target};
+
+# create repository
+my $repository;
+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',
+        $repository_conf,
+        {
+            test    => $test,
+            verbose => $verbose > 0 ? $verbose - 1 : 0,
+            targets => [ keys %{$config->get_param('targets')} ],
+        }
+    );
+};
+die "Failed to create repository: $@\n" if $@;
+
+# perfrom pre action
+my @errors;
+my $pre_packages = [];
+my $skip_pres = $config->get_arg('skip-pre');
+my %skip_pres = $skip_pres ?  map { $_ => 1 } @{$skip_pres} : ();
+foreach my $id (@{$target_conf->{pres}}) { 
+    next if $skip_pres{$id};
+    print "Creating pre $id\n" if $verbose;
+    my $pre;
+    my $pre_conf = $config->get_param('pres')->{$id};
+
+    if (!$pre_conf) {
+	print STDERR "No such pre $id, skipping\n";
+	next;
+    }
+    eval {
+	$pre = create_instance(
+	    'Youri::Submit::Pre',
+	    $pre_conf,
+	    {
+		id       => $id,
+		test     => $test,
+		verbose  => $verbose > 0 ? $verbose - 1 : 0,
+	    }
+	);
+    };
+    if ($@) {
+	print STDERR "Failed to create pre $id: $@\n";
+    } else {
+	print "running pre $id\n" if $verbose;
+	my @err = $pre->run(
+	    $pre_packages,
+	    $repository,
+	    $target,
+	    $config->get_arg('define')
+	);
+	push(@errors, @err) if $err[0];
+    }
+}
+
+if (@errors) {
+    print "Pre-submission errors, aborting:\n";
+    foreach my $error (@errors) {
+	print " - $error\n";
+    }
+    exit(1)
+}
+
+# create packages group
+my $group_error;
+my @packages_group;
+foreach my $group ([ map { { section => "", file => $_ } } @ARGV ], @$pre_packages) {
+    my @packages;
+    foreach my $opt (@$group) {
+	print "Preparing upload for $opt->{file} in $opt->{section}\n" if $verbose;
+	$repository->{packages}{$opt->{file}}{section} = $opt->{section};
+	push(
+	    @packages,
+	    create_instance(
+		'Youri::Package',
+		{
+		    class => $repository->get_package_class(),
+		},
+		{
+		    file => $opt->{file},
+		    %$opt
+		},
+	    )
+	);
+    }
+    @packages or next;
+
+# check all packages pass all tests
+    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_conf->{checks}}) {
+	next if $skip_check{$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::Submit::Check',
+		$check_conf,
+		{ 
+		    id       => $id,
+		    test     => $test,
+		    verbose  => $verbose > 0 ? $verbose - 1 : 0,
+		}
+	    );
+	};
+	if ($@) {
+	    print STDERR "Failed to create check $id: $@\n";
+	} else {
+	    foreach my $package (@packages) {
+		print "running check $id on package $package\n" if $verbose;
+		my @errors = $check->run(
+		    $package,
+		    $repository,
+		    $target,
+		    $config->get_arg('define')
+		);
+		push(@{$errors{$package}}, @errors) if $errors[0];
+	    }
+	}
+    }
+    if (%errors) {
+	print "Submission errors, aborting:\n";
+	foreach my $package (keys %errors) {
+	    print "- $package:\n";
+	    foreach my $error (@{$errors{$package}}) {
+		print " - $error\n";
+	    }
+	}
+	# reject the packages
+	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};
+	
+	    if (!$reject_conf) {
+		print STDERR "No such reject $id, skipping\n";
+		next;
+	    }
+	    eval {
+		$reject = create_instance(
+		    'Youri::Submit::Reject',
+		    $reject_conf,
+		    {
+			id       => $id,
+			test     => $test,
+			verbose  => $verbose > 0 ? $verbose - 1 : 0,
+		    }
+		);
+	    };
+	    if ($@) {
+		print STDERR "Failed to create reject $id: $@\n";
+	    } else {
+		foreach my $package (@packages) {
+		    print "running reject $id on package $package\n" if $verbose;
+		    eval {
+			$reject->run($package, \%errors, $repository, $target, $config->get_arg('define'));
+		    };
+		    if ($@) {
+			print STDERR "Failed to run action $id on package $package: $@\n";
+		    }
+		}
+	    }
+	}
+	$group_error = 1;
+	next
+    } 
+
+# proceed further
+    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_action{$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::Submit::Action',
+		$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_arg('define')
+		    );
+		};
+		if ($@) {
+		    print STDERR "Failed to run action $id on package $package: $@\n";
+		}
+	    }
+	}
+    }
+
+    if ($config->get_arg('clean')) {
+	foreach my $package (@packages) {
+	    print "cleaning file $package\n" if $verbose;
+	    unlink $package->as_file();
+	}
+    }
+}
+
+# perfrom post action
+my $skip_post = $config->get_arg('skip-post');
+my %skip_post = $skip_post ?  map { $_ => 1 } @{$skip_post} : ();
+foreach my $id (@{$target_conf->{posts}}) {
+    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 post $id, skipping\n";
+	next;
+    }
+    eval {
+	$post = create_instance(
+	    'Youri::Submit::Post',
+	    $post_conf,
+	    { 
+		id       => $id,
+		test     => $test,
+		verbose  => $verbose > 0 ? $verbose - 1 : 0,
+	    }
+	);
+    };
+    if ($@) {
+	print STDERR "Failed to create post $id: $@\n";
+    } else {
+	print "running post $id\n" if $verbose;
+	my @err = $post->run($repository, $target, $config->get_arg('define'));
+	print STDERR "Error $id: @err\n" if @err
+    }
+}
+
+exit(1) if $group_error;
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]  
+
+=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]  
+
+=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
new file mode 100755
index 0000000..9892d0e
--- /dev/null
+++ b/bin/youri-submit.in
@@ -0,0 +1,534 @@
+#!/usr/bin/perl
+# $Id: youri-submit.in 232668 2007-12-21 14:37:04Z blino $
+
+=head1 NAME
+
+youri-submit - package submission tool
+
+=head1 VERSION
+
+Version 2.0
+
+=head1 SYNOPSIS
+
+youri-submit [options]  
+
+youri-submit --list  [target]
+
+youri-submit --help [category] [item]
+ 
+Options:
+
+    --config         use file  as config file
+    --skip-pre 
       skip pre 
+    --skip-check    skip check 
+    --skip-action  skip action 
+    --skip-post      skip post 
+    --skip-reject  skip reject 
+    --define = pass additional values
+    --clean                delete package after success
+    --verbose              verbose run
+    --test                 test run
+    --list       list items from given category
+    --help [category]      display contextual help
+
+=head1 DESCRIPTION
+
+B 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
+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-pre> I
+
+Skip pre transaction plugin with given identity
+
+=item B<--skip-check> I
+
+Skip check plugin with given identity.
+
+=item B<--skip-action> I
+
+Skip action plugin with given identity.
+
+=item B<--skip-post> I
+
+Skip post transaction plugin with given identity.
+
+=item B<--skip-reject> I
+
+Skip reject action plugin with given identity.
+
+=item B<--define> =
+
+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)
+
+=item B<--test>
+
+Don't perform any modification.
+
+=item B<--list> I
+ 
+List available items from given category and exits. Category must be either
+B, B or B. A target is needed for the two last ones.
+ 
+=item B<--help> I
+ 
+Display help for given category and exits. Category must be either
+B, B or B. An item is needed for the two last ones.
+If no category given, display standard help.
+
+=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/submit.conf
+ 
+=item * /usr/local/etc/youri/submit.conf
+
+=back
+
+The configuration file should be a YAML-format files, with the following
+mandatory top-level directives:
+
+=over
+
+=item B
+
+The definition of repository plugin to be used.
+
+=item B
+
+The list of available submission targets, each one being composed from the
+following keys:
+
+=over
+
+=item B
+
+The list of check plugins to use for this target.
+
+=item B
+
+The list of action plugins to use for this target.
+
+=back
+
+=item B
+
+The list of check plugin definitions, indexed by their identity.
+
+=item B
+ 
+The list of action plugin definitions, indexed by their identity.
+
+=back
+
+=head1 SEE ALSO
+
+Youri::Config, for additional details about 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(
+    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',
+);
+
+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 || $config->get_param('allow_omitting_packages');
+
+# convenient global flags
+my $test    = $config->get_arg('test');
+my $verbose = $config->get_arg('verbose');
+
+# check target
+my $target = shift @ARGV;
+my $target_conf = $config->get_param('targets')->{$target};
+
+# create repository
+my $repository;
+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',
+        $repository_conf,
+        {
+            test    => $test,
+            verbose => $verbose > 0 ? $verbose - 1 : 0,
+            targets => [ keys %{$config->get_param('targets')} ],
+        }
+    );
+};
+die "Failed to create repository: $@\n" if $@;
+
+# perfrom pre action
+my @errors;
+my $pre_packages = [];
+my $skip_pres = $config->get_arg('skip-pre');
+my %skip_pres = $skip_pres ?  map { $_ => 1 } @{$skip_pres} : ();
+foreach my $id (@{$target_conf->{pres}}) { 
+    next if $skip_pres{$id};
+    print "Creating pre $id\n" if $verbose;
+    my $pre;
+    my $pre_conf = $config->get_param('pres')->{$id};
+
+    if (!$pre_conf) {
+	print STDERR "No such pre $id, skipping\n";
+	next;
+    }
+    eval {
+	$pre = create_instance(
+	    'Youri::Submit::Pre',
+	    $pre_conf,
+	    {
+		id       => $id,
+		test     => $test,
+		verbose  => $verbose > 0 ? $verbose - 1 : 0,
+	    }
+	);
+    };
+    if ($@) {
+	print STDERR "Failed to create pre $id: $@\n";
+    } else {
+	print "running pre $id\n" if $verbose;
+	my @err = $pre->run(
+	    $pre_packages,
+	    $repository,
+	    $target,
+	    $config->get_arg('define')
+	);
+	push(@errors, @err) if $err[0];
+    }
+}
+
+if (@errors) {
+    print "Pre-submission errors, aborting:\n";
+    foreach my $error (@errors) {
+	print " - $error\n";
+    }
+    exit(1)
+}
+
+# create packages group
+my $group_error;
+my @packages_group;
+foreach my $group ([ map { { section => "", file => $_ } } @ARGV ], @$pre_packages) {
+    my @packages;
+    foreach my $opt (@$group) {
+	print "Preparing upload for $opt->{file} in $opt->{section}\n" if $verbose;
+	$repository->{packages}{$opt->{file}}{section} = $opt->{section};
+	push(
+	    @packages,
+	    create_instance(
+		'Youri::Package',
+		{
+		    class => $repository->get_package_class(),
+		},
+		{
+		    file => $opt->{file},
+		    %$opt
+		},
+	    )
+	);
+    }
+    @packages or next;
+
+# check all packages pass all tests
+    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_conf->{checks}}) {
+	next if $skip_check{$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::Submit::Check',
+		$check_conf,
+		{ 
+		    id       => $id,
+		    test     => $test,
+		    verbose  => $verbose > 0 ? $verbose - 1 : 0,
+		}
+	    );
+	};
+	if ($@) {
+	    print STDERR "Failed to create check $id: $@\n";
+	} else {
+	    foreach my $package (@packages) {
+		print "running check $id on package $package\n" if $verbose;
+		my @errors = $check->run(
+		    $package,
+		    $repository,
+		    $target,
+		    $config->get_arg('define')
+		);
+		push(@{$errors{$package}}, @errors) if $errors[0];
+	    }
+	}
+    }
+    if (%errors) {
+	print "Submission errors, aborting:\n";
+	foreach my $package (keys %errors) {
+	    print "- $package:\n";
+	    foreach my $error (@{$errors{$package}}) {
+		print " - $error\n";
+	    }
+	}
+	# reject the packages
+	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};
+	
+	    if (!$reject_conf) {
+		print STDERR "No such reject $id, skipping\n";
+		next;
+	    }
+	    eval {
+		$reject = create_instance(
+		    'Youri::Submit::Reject',
+		    $reject_conf,
+		    {
+			id       => $id,
+			test     => $test,
+			verbose  => $verbose > 0 ? $verbose - 1 : 0,
+		    }
+		);
+	    };
+	    if ($@) {
+		print STDERR "Failed to create reject $id: $@\n";
+	    } else {
+		foreach my $package (@packages) {
+		    print "running reject $id on package $package\n" if $verbose;
+		    eval {
+			$reject->run($package, \%errors, $repository, $target, $config->get_arg('define'));
+		    };
+		    if ($@) {
+			print STDERR "Failed to run action $id on package $package: $@\n";
+		    }
+		}
+	    }
+	}
+	$group_error = 1;
+	next
+    } 
+
+# proceed further
+    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_action{$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::Submit::Action',
+		$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_arg('define')
+		    );
+		};
+		if ($@) {
+		    print STDERR "Failed to run action $id on package $package: $@\n";
+		}
+	    }
+	}
+    }
+
+    if ($config->get_arg('clean')) {
+	foreach my $package (@packages) {
+	    print "cleaning file $package\n" if $verbose;
+	    unlink $package->as_file();
+	}
+    }
+}
+
+# perfrom post action
+my $skip_post = $config->get_arg('skip-post');
+my %skip_post = $skip_post ?  map { $_ => 1 } @{$skip_post} : ();
+foreach my $id (@{$target_conf->{posts}}) {
+    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 post $id, skipping\n";
+	next;
+    }
+    eval {
+	$post = create_instance(
+	    'Youri::Submit::Post',
+	    $post_conf,
+	    { 
+		id       => $id,
+		test     => $test,
+		verbose  => $verbose > 0 ? $verbose - 1 : 0,
+	    }
+	);
+    };
+    if ($@) {
+	print STDERR "Failed to create post $id: $@\n";
+    } else {
+	print "running post $id\n" if $verbose;
+	my @err = $post->run($repository, $target, $config->get_arg('define'));
+	print STDERR "Error $id: @err\n" if @err
+    }
+}
+
+exit(1) if $group_error;
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..ef23078
--- /dev/null
+++ b/etc/submit.conf
@@ -0,0 +1,134 @@
+# youri-submit sample configuration file
+# $Id: submit.conf 1723 2006-10-17 13:53:27Z warly $
+
+# 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/Action.pm b/lib/Youri/Submit/Action.pm
new file mode 100644
index 0000000..983fdc8
--- /dev/null
+++ b/lib/Youri/Submit/Action.pm
@@ -0,0 +1,27 @@
+# $Id: Base.pm 631 2006-01-26 22:22:23Z guillomovitch $
+package Youri::Submit::Action;
+
+=head1 NAME
+
+Youri::Submit::Action - Abstract action plugin
+
+=head1 DESCRIPTION
+
+This abstract class defines action plugin interface.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Plugin/;
+
+=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/lib/Youri/Submit/Action/Archive.pm b/lib/Youri/Submit/Action/Archive.pm
new file mode 100644
index 0000000..98ff37c
--- /dev/null
+++ b/lib/Youri/Submit/Action/Archive.pm
@@ -0,0 +1,90 @@
+# $Id: Archive.pm 265457 2010-01-28 13:09:30Z pterjan $
+package Youri::Submit::Action::Archive;
+
+=head1 NAME
+
+Youri::Submit::Action::Archive - Old revisions archiving
+
+=head1 DESCRIPTION
+
+This action plugin ensures archiving of old package revisions.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        perms => 644,
+        @_
+    );
+
+    $self->{_perms} = $options{perms};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    # FIXME: workaround for $self->{_verbose} not being initialized properly
+    $self->{_verbose} = 1;
+    # all this should be in Mandriva_upload.pm
+    my $section = $repository->_get_section($package, $target, $define);
+    my $main_section = $repository->_get_main_section($package, $target, $define);
+    print "section $section main_section $main_section\n" if $self->{_verbose};
+    my $arch = $package->get_arch();
+    $arch = $self->{_noarch} if $arch eq 'noarch';
+    my $path = $arch eq 'src' ? "$target/SRPMS" : "$target/$arch/media";
+    $path = "$repository->{_install_root}/$path";
+    $path =~ s,/+,/,g;
+    foreach my $replaced_package (
+        $repository->get_replaced_packages($package, $target, $define)
+    ) {
+        my $file = $replaced_package->get_file();
+
+        # trap for debugging bug 34999
+        if ($file =~ /\/[\d.]+\/(main\/updates|.*\/release)/) {
+            my $bugmsg = "BUG#34999 WARNING: trying to remove from a release: $file\n";
+            open(BUG34999LOG, '>>', "/home/mandrake/bug34999.log");
+            print $bugmsg;
+            print BUG34999LOG localtime().": ".$bugmsg;
+            close BUG34999LOG;
+
+            next;
+        }
+
+	my ($rep_section, $rep_main_section) = $file =~ m,$path/(([^/]+)/.*)/[^/]+.rpm,;
+	# We do accept duplicate version for other submedia of the same main media section
+	print "(path '$path') file '$file' section '$rep_section' main_section '$rep_main_section'\n" if $self->{_verbose};
+	next if $rep_main_section eq $main_section && $rep_section ne $section;
+        my $dest = $repository->get_archive_dir($package, $target, $define);
+
+        print "archiving file $file to $dest\n" if $self->{_verbose};
+
+        unless ($self->{_test}) {
+            # create destination dir if needed
+            system("install -d -m " . ($self->{_perms} + 111) . " $dest")
+                unless -d $dest;
+
+            # install file to new location
+            system("install -m $self->{_perms} $file $dest");
+
+	    print "deleting file $file\n" if $self->{_verbose};
+	    unlink $file unless $self->{_test};
+        }
+    }  
+}
+
+=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/lib/Youri/Submit/Action/Bugzilla.pm b/lib/Youri/Submit/Action/Bugzilla.pm
new file mode 100644
index 0000000..04eaa4c
--- /dev/null
+++ b/lib/Youri/Submit/Action/Bugzilla.pm
@@ -0,0 +1,81 @@
+# $Id: Bugzilla.pm 1700 2006-10-16 12:57:42Z warly $
+package Youri::Submit::Action::Bugzilla;
+
+=head1 NAME
+
+Youri::Submit::Action::Bugzilla - Bugzilla synchronisation
+
+=head1 DESCRIPTION
+
+This action plugin ensures synchronisation with Bugzilla.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use Youri::Bugzilla;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        host    => '',
+        base    => '',
+        user    => '',
+        pass    => '',
+        contact => '',
+        @_
+    );
+
+    $self->{_bugzilla} = Youri::Bugzilla->new(
+        $options{host},
+        $options{base},
+        $options{user},
+        $options{pass}
+    );
+    $self->{_contact}  = $options{contact};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    return unless $package->is_source();
+
+    my $name     = $package->get_name();
+    my $version  = $package->get_version();
+    my $summary  = $package->get_summary();
+    my $packager = $package->get_packager();
+    $packager =~ s/.*<(.*)>/$1/;
+
+    if ($self->{_bugzilla}->has_package($name)) {
+        my %versions =
+            map { $_ => 1 }
+            $self->{_bugzilla}->get_versions($name);
+        unless ($versions{$version}) {
+            print "adding version $version to bugzilla\n" if $self->{_verbose};
+            $self->{_bugzilla}->add_version($name, $version)
+                unless $self->{_test};
+        }
+    } else {
+        print "adding package $name to bugzilla\n" if $self->{_verbose};
+        $self->{_bugzilla}->add_package(
+            $name,
+            $summary,
+            $version,
+            $packager,
+            $self->{_contact}
+        ) unless $self->{_test};
+    }
+}
+
+=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/lib/Youri/Submit/Action/CVS.pm b/lib/Youri/Submit/Action/CVS.pm
new file mode 100644
index 0000000..e9f1f4f
--- /dev/null
+++ b/lib/Youri/Submit/Action/CVS.pm
@@ -0,0 +1,135 @@
+# $Id: CVS.pm 224115 2007-07-02 09:17:15Z pixel $
+package Youri::Submit::Action::CVS;
+
+=head1 NAME
+
+Youri::Submit::Action::CVS - CVS versionning
+
+=head1 DESCRIPTION
+
+This action plugin ensures CVS versionning of package sources.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use Cwd;
+use File::Temp qw/tempdir/;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        exclude => '\.(tar(\.(gz|bz2))?|zip)$',
+        perms   => 644,
+        @_
+    );
+
+    $self->{_exclude} = $options{exclude};
+    $self->{_perms}   = $options{perms};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    return unless $package->is_source();
+
+    my $name    = $package->get_name();
+    my $version = $package->get_version();
+    my $release = $package->get_release();
+
+    my $root = $repository->get_version_root();
+    my $path = $repository->get_version_path($package, $target, $define);
+
+    # remember original directory
+    my $original_dir = cwd();
+
+    # get a safe temporary directory
+    my $dir = tempdir( CLEANUP => 1 );
+    chdir $dir;
+
+    # first checkout base directory only
+    system("cvs -Q -d $root co -l $path");
+
+    # try to checkout package directory
+    my $dest = $path . '/' . $name;
+    system("cvs -Q -d $root co $dest");
+
+    # create directory if previous import failed
+    unless (-d $dest) {
+        print "adding directory $dest\n" if $self->{_verbose};
+        system("install -d -m " . ($self->{_perms} + 111) . " $dest");
+        system("cvs -Q -d $root add $dest");
+    }
+
+    chdir $dest;
+
+    # remove all files
+    unlink grep { -f } glob '*';
+
+    # extract all rpm files locally
+    $package->extract();
+
+    # remove excluded files
+    if ($self->{_exclude}) {
+        unlink grep { -f && /$self->{_exclude}/ } glob '*'; 
+    }
+
+    # uncompress all compressed files
+    system("bunzip2 *.bz2 2>/dev/null");
+    system("gunzip *.gz 2>/dev/null");
+
+    my (@to_remove, @to_add, @to_add_binary);
+    foreach my $line (`cvs -nq update`) {
+        if ($line =~ /^\? (\S+)/) {
+            if (-B $1) {
+                push(@to_add_binary, $1);
+            } else {
+                push(@to_add, $1);
+            }
+        }
+        if ($line =~ /^U (\S+)/) {
+            push(@to_remove, $1);
+        }
+    }
+    if (@to_remove) {
+        my $to_remove = join(' ', @to_remove);
+        print "removing file(s) $to_remove\n" if $self->{_verbose};
+        system("cvs -Q remove $to_remove");
+    }
+    if (@to_add) {
+        my $to_add = join(' ', @to_add);
+        print "adding text file(s) $to_add\n" if $self->{_verbose};
+        system("cvs -Q add $to_add");
+    }
+    if (@to_add_binary) {
+        my $to_add_binary = join(' ', @to_add_binary);
+        print "adding binary file(s) $to_add_binary\n" if $self->{_verbose};
+        system("cvs -Q add -kb $to_add_binary");
+    }
+
+    print "committing current directory\n" if $self->{_verbose};
+    system("cvs -Q commit -m $version-$release") unless $self->{_test};
+
+    # tag new release
+    my $tag = "r$version-$release";
+    $tag =~ s/\./_/g;
+    print "tagging current directory as $tag\n" if $self->{_verbose};
+    system("cvs -Q tag $tag") unless $self->{_test};
+
+    # get back to original directory
+    chdir $original_dir;
+
+}
+
+=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/lib/Youri/Submit/Action/Clean.pm b/lib/Youri/Submit/Action/Clean.pm
new file mode 100644
index 0000000..fa19254
--- /dev/null
+++ b/lib/Youri/Submit/Action/Clean.pm
@@ -0,0 +1,40 @@
+# $Id: Clean.pm 4742 2007-01-30 09:49:58Z pixel $
+package Youri::Submit::Action::Clean;
+
+=head1 NAME
+
+Youri::Submit::Action::Clean - Old revisions cleanup
+
+=head1 DESCRIPTION
+
+This action plugin ensures cleanup of old package revisions.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Action/;
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    foreach my $replaced_package (
+        $repository->get_replaced_packages($package, $target, $define)
+    ) {
+        my $file = $replaced_package->as_file();
+        print "deleting file $file\n" if $self->{_verbose};
+        unlink $file unless $self->{_test};
+    }
+}
+
+=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/lib/Youri/Submit/Action/DkmsModuleInfo.pm b/lib/Youri/Submit/Action/DkmsModuleInfo.pm
new file mode 100644
index 0000000..d1dd4a8
--- /dev/null
+++ b/lib/Youri/Submit/Action/DkmsModuleInfo.pm
@@ -0,0 +1,111 @@
+# $Id$
+package Youri::Submit::Action::DkmsModuleInfo;
+
+=head1 NAME
+
+Youri::Submit::Action::DkmsModuleInfo - extract and commit info from dkms package.
+
+=head1 DESCRIPTION
+
+This action plugin extract modalias and description from dkms packages and commit them
+on a SVN module.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Action/;
+use File::Temp qw/tempdir/;
+use File::Basename;
+use SVN::Client;
+
+#- inlineed from MDK::Common::Various
+sub chomp_ { my @l = @_; chomp @l; wantarray() ? @l : $l[0] }
+
+sub _init {
+    my ($self, %options) = @_;
+
+    croak "undefined svn module" unless $options{svn_module};
+
+    foreach my $var ('svn_module') {
+	$self->{"_$var"} = $options{$var};
+    }
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my ($dkms_name) = $package->get_canonical_name =~ /^dkms-(.*)$/ or return;
+    my $package_name = $package->get_name;
+    my ($kver) = $package_name =~ /^$dkms_name-kernel-(.*)$/ or return;
+
+    my @files = map { $_->[0] } $package->get_files;
+    my @module_files = grep { m!^(/lib/modules/|/var/lib/dkms-binary/).*\.ko(\.gz)?$! } @files
+      or return;
+
+    print "Submit::Action::DkmsModuleInfo: proceeding with $package_name\n" if $self->{_verbose};
+
+    my $tempdir = tempdir(CLEANUP => 1);
+    my $file = $package->as_file;
+    my $cmd = "rpm2cpio $file | (cd $tempdir ; cpio --quiet -id)";
+    print "Submit::Action::DkmsModuleInfo: doing $cmd\n" if $self->{_verbose};
+    if (system($cmd) != 0) {
+	print "Submit::Action::DkmsModuleInfo: failed!\n" if $self->{_verbose};
+	return;
+    }
+
+    my @fields = qw(description alias);
+
+    my (%modules);
+    foreach my $file (@module_files) {
+        print "Submit::Action::DkmsModuleInfo: extracting $file\n" if $self->{_verbose};
+        my $module = $file;
+        $module =~ s!.*/!!;
+        $module =~ s!\.ko(\.gz)$!!;
+        $modules{$module}{$_} = [ chomp_(`/sbin/modinfo -F $_ $tempdir$file`) ]
+          foreach @fields;
+    }
+
+    eval {
+        my $svn = SVN::Client->new();
+        my $dir = $tempdir . '/' . basename($self->{_svn_module});
+        my $revision = $svn->checkout($self->{_svn_module}, $dir, 'HEAD', 0);
+        my $vdir = $dir . '/' . $kver;
+        $svn->update($vdir, 'HEAD', 0);
+        -d $vdir or $svn->mkdir($vdir);
+        foreach my $module (keys %modules) {
+            print "Submit::Action::DkmsModuleInfo: adding module $module\n" if $self->{_verbose};
+            foreach my $field (@fields) {
+                my $file = "$vdir/$module.$field";
+                $svn->update($file, 'HEAD', 0);
+                my $exists = -f $file;
+                open(my $fh, ">", $file);
+                print $fh map { "$_\n" } @{$modules{$module}{$field}};
+                $svn->add($file, 1) if !$exists;
+            }
+        }
+
+        $svn->log_msg(sub { $_[0] = \"add dkms info for $dkms_name with kernel $kver" });
+        $svn->commit($vdir, 0);
+    };
+    if (my $error = $@) {
+	print "Submit::Action::DkmsModuleInfo: commit to svn failed ($error)!\n" if $self->{_verbose};
+	return;
+    }
+
+    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
+
+1;
diff --git a/lib/Youri/Submit/Action/Install.pm b/lib/Youri/Submit/Action/Install.pm
new file mode 100644
index 0000000..80e8de2
--- /dev/null
+++ b/lib/Youri/Submit/Action/Install.pm
@@ -0,0 +1,75 @@
+# $Id: Install.pm 229772 2007-09-26 11:21:07Z blino $
+package Youri::Submit::Action::Install;
+
+=head1 NAME
+
+Youri::Submit::Action::Install - Package installation
+
+=head1 DESCRIPTION
+
+This action plugin ensures installation of new package revisions.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use File::Basename;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        perms => 644,
+        @_
+    );
+
+    $self->{_perms} = $options{perms};
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my $file = $package->as_file();
+    my $rpm = basename($package->get_file_name());
+    my $dest = $repository->get_install_dir($package, $target, $define);
+
+    # FIXME remove prefix this should be done by a function
+    $rpm =~ s/^\d{14}\.\w*\.\w+\.\d+_//;
+    $rpm =~ s/^\@\d+://;
+    print "installing file $file to $dest/$rpm\n" if $self->{_verbose};
+
+    unless ($self->{_test}) {
+        # create destination dir if needed
+        if (! -d $dest) {
+            my $status =
+                system("install -d -m " . ($self->{_perms} + 111) . " $dest");
+            croak "Unable to create directory $dest: $?" if $status;
+        }
+
+        # install file to new location
+        my $status =
+            system("install -m $self->{_perms} $file $dest/$rpm");
+        croak "Unable to install file $file to $dest/$rpm: $?" if $status;
+
+	my $arch = $package->get_arch();
+	$repository->set_arch_changed($target, $arch);
+	$repository->set_install_dir_changed($dest);
+    }
+    $package->{_file} = "$dest/$rpm";
+    print "deleting file $file\n" if $self->{_verbose};
+    unlink $file unless $self->{_test};
+}
+
+=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/lib/Youri/Submit/Action/Link.pm b/lib/Youri/Submit/Action/Link.pm
new file mode 100644
index 0000000..336eafb
--- /dev/null
+++ b/lib/Youri/Submit/Action/Link.pm
@@ -0,0 +1,80 @@
+# $Id: Link.pm 233641 2008-01-31 16:35:55Z pixel $
+package Youri::Submit::Action::Link;
+
+=head1 NAME
+
+Youri::Submit::Action::Link - Noarch packages linking
+
+=head1 DESCRIPTION
+
+This action plugin ensures linking of noarch packages between arch-specific
+directories.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use Cwd;
+use File::Spec;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        symbolic => 0, # use symbolic linking
+        @_
+    );
+
+    $self->{_symbolic} = $options{symbolic};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    # only needed for noarch packages
+    return unless $package->get_arch() eq 'noarch';
+
+    my $default_dir = $repository->get_install_dir($package, $target, $define);
+    my $file = $package->get_file_name();
+
+    # FIXME remove prefix this should be done by a function
+    $file =~ s/^\d{14}\.\w*\.\w+\.\d+_//;
+    $file =~ s/^\@\d+://;
+
+    foreach my $arch ($repository->get_extra_arches()) {
+        # compute installation target, forcing arch
+        my $other_dir = $repository->get_install_dir(
+            $package,
+            $target,
+            $define,
+            { arch => $arch }
+        );
+
+        if (! $self->{_test}) {
+            my $current_dir = cwd();
+            chdir $other_dir;
+            my $default_file = File::Spec->abs2rel($default_dir) . '/' . $file;
+            if ($self->{_symbolic}) {
+                symlink $default_file, $file;
+            } else {
+                link $default_file, $file;
+            }
+            chdir $current_dir;
+	    print "set_install_dir_changed($other_dir) for updated $file\n";
+	    $repository->set_install_dir_changed($other_dir);
+	    $repository->set_arch_changed($target, $arch);
+        }
+    }
+}
+
+=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/lib/Youri/Submit/Action/Mail.pm b/lib/Youri/Submit/Action/Mail.pm
new file mode 100644
index 0000000..c9bbcbe
--- /dev/null
+++ b/lib/Youri/Submit/Action/Mail.pm
@@ -0,0 +1,131 @@
+# $Id: Mail.pm 223952 2007-06-23 13:54:13Z pixel $
+package Youri::Submit::Action::Mail;
+
+=head1 NAME
+
+Youri::Submit::Action::Mail - Mail notification
+
+=head1 DESCRIPTION
+
+This action plugin ensures mail notification of new package revisions.
+
+=cut
+
+use warnings;
+use strict;
+use MIME::Entity;
+use Encode qw/from_to/;
+use Carp;
+use Youri::Package;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        mta      => '/usr/sbin/sendmail',
+        to       => '',
+        from     => '',
+        cc       => '',
+        prefix   => '',
+        encoding => 'quoted-printable',
+        charset  => 'iso-8859-1',
+        @_
+    );
+
+    croak "undefined mail MTA" unless $options{mta};
+    croak "invalid mail MTA $options{mta}" unless -x $options{mta};
+    croak "undefined to" unless $options{to};
+    if ($options{cc}) {
+        croak "cc should be an hashref" unless ref $options{cc} eq 'HASH';
+    }
+    croak "invalid charset $options{charset}"
+        unless Encode::resolve_alias($options{charset});
+
+    $self->{_mta}      = $options{mta};
+    $self->{_to}       = $options{to};
+    $self->{_from}     = $options{from};
+    $self->{_cc}       = $options{cc};
+    $self->{_prefix}   = $options{prefix};
+    $self->{_encoding} = $options{encoding};
+    $self->{_charset}  = $options{charset};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    return unless $package->is_source();
+
+    my $from = $package->get_packager();
+
+    # force from adress if defined
+    $from =~ s/<.*>/<$self->{_from}>/ if $self->{_from};
+
+    my $subject = $self->get_subject($package, $repository, $target, $define);
+    my $content = $self->get_content($package, $repository, $target, $define);
+
+    # ensure proper codeset conversion
+    # for informations coming from package
+    my $charset = $repository->get_package_charset();
+    from_to($content, $charset, $self->{_charset});
+    from_to($subject, $charset, $self->{_charset});
+
+    my $mail = MIME::Entity->build(
+        Type     => 'text/plain',
+        Charset  => $self->{_charset},
+        Encoding => $self->{_encoding},
+        From     => $from,
+        To       => $self->{_to},
+        Subject  => $subject,
+        Data     => $content,
+    );
+
+    if ($self->{_cc}) {
+        my $cc = $self->{_cc}->{$package->get_name()};
+        $mail->head()->add('cc', $cc) if $cc;
+    }
+
+    if ($self->{_test}) {
+        $mail->print(\*STDOUT);
+    } else {
+        open(MAIL, "| $self->{_mta} -t -oi -oem") or die "Can't open MTA program: $!";
+        $mail->print(\*MAIL);
+        close MAIL;
+    }
+
+}
+
+sub get_subject {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my $section = $repository->_get_section($package, $target, $define);
+    return 
+        ($self->{_prefix} ?  '[' . $self->{_prefix} . '] ' : '' ) . 
+	"$target " . ($section ? "$section " : '' ) .
+        $package->as_formated_string('%{name}-%{version}-%{release}');
+}
+
+sub get_content {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my $information = $package->get_information();
+    my $last_change = $package->get_last_change();
+
+    return
+        $information . "\n" .
+        $last_change->[Youri::Package::CHANGE_AUTHOR] . ":\n" .
+	$last_change->[Youri::Package::CHANGE_TEXT];
+}
+
+
+=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/lib/Youri/Submit/Action/Markrelease.pm b/lib/Youri/Submit/Action/Markrelease.pm
new file mode 100644
index 0000000..a409c7c
--- /dev/null
+++ b/lib/Youri/Submit/Action/Markrelease.pm
@@ -0,0 +1,56 @@
+# $Id: Markrelease.pm 4743 2007-01-30 09:58:30Z pixel $
+package Youri::Submit::Action::Markrelease;
+
+=head1 NAME
+
+Youri::Submit::Action::Markrelease - calls markrelease
+
+=head1 DESCRIPTION
+
+This action plugin calls markrelease
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        perms => 644,
+        @_
+    );
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    $package->is_source or return 1;
+    my $file = $package->get_file();
+    my $srpm_name = $package->get_canonical_name;
+
+    if ($repository->package_in_svn($srpm_name)) {
+	my $svn = $repository->get_svn_url();
+	my ($rev) = $file =~ /.*\/.*?\@(\d+):/;
+	print "Run repsys markrelease -f $file -r $rev $svn/$srpm_name\n";
+	# FIXME repsys ask for a username and password
+	# FIXME we should use the key in /var/home/mandrake so that /home/mandrake does not
+	# need to be mounted
+	system('repsys', 'markrelease', '-f', $file, '-r', $rev, "$svn/$srpm_name");
+    }
+    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
+
+1;
diff --git a/lib/Youri/Submit/Action/RSS.pm b/lib/Youri/Submit/Action/RSS.pm
new file mode 100644
index 0000000..51da825
--- /dev/null
+++ b/lib/Youri/Submit/Action/RSS.pm
@@ -0,0 +1,102 @@
+# $Id: RSS.pm 1700 2006-10-16 12:57:42Z warly $
+package Youri::Submit::Action::RSS;
+
+=head1 NAME
+
+Youri::Submit::Action::RSS - RSS notification
+
+=head1 DESCRIPTION
+
+This action plugin ensures RSS notification of new package revisions.
+
+=cut
+
+use warnings;
+use strict;
+use XML::RSS;
+use Encode qw/from_to/;
+use Carp;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        file        => '',
+        title       => '',
+        link        => '',
+        description => '',
+        charset    => 'iso-8859-1',
+        max_items   => 10,
+        @_
+    );
+
+    croak "undefined rss file" unless $options{file};
+    croak "invalid charset $options{charset}"
+        unless Encode::resolve_alias($options{charset});
+
+    $self->{_file}        = $options{file};
+    $self->{_title}       = $options{title};
+    $self->{_link}        = $options{link};
+    $self->{_description} = $options{description};
+    $self->{_charset}    = $options{charset};
+    $self->{_max_items}   = $options{max_items};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    return unless $package->is_source();
+
+    my $subject = $package->as_formated_string('%{name}-%{version}-%{release}');
+    my $content = $package->get_information();
+
+    $content =~ s/$//mg;
+
+    # ensure proper codeset conversion
+    # for informations coming from package
+    my $charset = $repository->get_package_charset();
+    from_to($content, $charset, $self->{_charset});
+    from_to($subject, $charset, $self->{_charset});
+
+    my $rss = XML::RSS->new(
+        encoding      => $self->{_charset},
+        encode_output => 1
+    );
+
+    my $file = $self->{_file};
+    if (-e $file) {
+        $rss->parsefile($file);
+        splice(@{$rss->{items}}, $self->{_max_items})
+            if @{$rss->{items}} >= $self->{_max_items};
+    } else {
+        $rss->channel(
+            title       => $self->{_title},
+            link        => $self->{_link},
+            description => $self->{_description},
+            language    => 'en'
+        );
+    }
+
+    $rss->add_item(
+        title       => $subject,
+        description => $content,
+        mode        => 'insert'
+    );
+
+    if ($self->{_test}) {
+        print $rss->as_string();
+    } else {
+        $rss->save($file);
+    }
+}
+
+=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/lib/Youri/Submit/Action/Rpminfo.pm b/lib/Youri/Submit/Action/Rpminfo.pm
new file mode 100644
index 0000000..c96efb1
--- /dev/null
+++ b/lib/Youri/Submit/Action/Rpminfo.pm
@@ -0,0 +1,69 @@
+# $Id: Rpminfo.pm 4742 2007-01-30 09:49:58Z pixel $
+package Youri::Submit::Action::Rpminfo;
+
+=head1 NAME
+
+Youri::Submit::Action::RpmInfo - Creates .info files
+
+=head1 DESCRIPTION
+
+This action plugin ensures the creation of .info files
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use File::Basename;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        perms => 644,
+	uphost => '',
+	user => '',
+	ssh_key => '',
+	verbose => '',
+        @_
+    );
+    croak "undefined upload host" unless $options{uphost};
+    croak "undefined ssh key" unless $options{ssh_key};
+
+    foreach my $var ('perms', 'user', 'uphost', 'ssh_key', 'verbose') {
+	$self->{"_$var"} = $options{$var};
+    }
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my $file = $package->get_file();
+    my $dest = $repository->get_upload_dir($package, $target, $define);
+
+    print "Caching rpm information $file on $dest\n" if $self->{_verbose};
+    my $base = basename ($file);
+    $dest =~ s/\/[0-9]{14}\./\/*./;
+
+    my $cmd = "ssh -i $self->{_ssh_key} $self->{_user}\@$self->{_uphost} \"srpm=`echo /$dest$base`; rpm -q --qf '\%{name}\n\%{epoch}\n\%{version}-\%{release}\n\%{summary}\n' -p \\\$srpm > \\\$srpm.info\"";
+    print "Submit::Action::RpmInfo: doing $cmd\n" if $self->{_verbose};
+    if (!$self->{_test}) {
+	if (!system($cmd)) {
+		print "Submit::Action::RpmInfo: rpminfo succeeded!\n";
+		return 1
+	}
+	print "Submit::Action::RpmInfo: rpminfo failed!\n";
+    }
+}
+=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/lib/Youri/Submit/Action/Send.pm b/lib/Youri/Submit/Action/Send.pm
new file mode 100644
index 0000000..9ba630b
--- /dev/null
+++ b/lib/Youri/Submit/Action/Send.pm
@@ -0,0 +1,77 @@
+# $Id: Send.pm 4744 2007-01-30 09:59:07Z pixel $
+package Youri::Submit::Action::Send;
+
+=head1 NAME
+
+Youri::Submit::Action::Send - upload package
+
+=head1 DESCRIPTION
+
+This action plugin uploads the package on uphost
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use File::Basename;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        perms => 644,
+	uphost => '',
+	user => '',
+	ssh_key => '',
+	verbose => '',
+	keep_svn_release => '',
+        @_
+    );
+    croak "undefined upload host" unless $options{uphost};
+    croak "undefined ssh key" unless $options{ssh_key};
+
+    foreach my $var ('perms', 'user', 'uphost', 'ssh_key', 'verbose', 'keep_svn_release') {
+	$self->{"_$var"} = $options{$var};
+    }
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my $file = $package->get_file();
+    my $dest = $repository->get_upload_dir($package, $target, $define);
+
+    print "Sending file $file to $dest\n" if $self->{_verbose};
+    my $base;
+    if ($self->{_keep_svn_release}) {
+	$base = basename($file)
+    } else {
+	($base) = $file =~ /.*\/(?:@\d+:)?([^\/]*)/
+    }
+
+    my $cmd = "scp -i $self->{_ssh_key} $file $self->{_user}\@$self->{_uphost}:/$dest$base.new";
+    my $cmd2 = "ssh -i $self->{_ssh_key} $self->{_user}\@$self->{_uphost} \"mv /$dest$base.new /$dest$base\"";
+    print "Submit::Action::Send: doing $cmd\n$cmd2\n" if 1 || $self->{_verbose};
+    if (!$self->{_test}) {
+	if (!system($cmd)) {
+	    if (!system($cmd2)) {
+		print "Submit::Action::Send: upload succeeded!\n";
+		return 1
+	    }
+	}
+	print "Submit::Action::Send: upload failed!\n";
+    }
+}
+=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/lib/Youri/Submit/Action/Sendcache.pm b/lib/Youri/Submit/Action/Sendcache.pm
new file mode 100644
index 0000000..9ea14ea
--- /dev/null
+++ b/lib/Youri/Submit/Action/Sendcache.pm
@@ -0,0 +1,81 @@
+# $Id: Sendcache.pm 232350 2007-12-07 18:26:17Z spuk $
+package Youri::Submit::Action::Sendcache;
+
+=head1 NAME
+
+Youri::Submit::Action::Sendcache - upload package to cache
+
+=head1 DESCRIPTION
+
+This action plugin uploads the package on uphost
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use File::Basename;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        perms => 644,
+	uphost => '',
+	user => '',
+	ssh_key => '',
+	verbose => '',
+	root => '',
+	debug_pkgs => 0,
+        @_
+    );
+    croak "undefined upload host" unless $options{uphost};
+    croak "undefined ssh key" unless $options{ssh_key};
+
+    foreach my $var ('perms', 'user', 'uphost', 'ssh_key', 'verbose', 'root', 'debug_pkgs') {
+	$self->{"_$var"} = $options{$var};
+    }
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    # only cache debug packages if option debug_pkgs is true
+    return if ($package->is_debug() && !$self->{_debug_pkgs});
+
+    my $file = $package->get_file();
+    my $dest = $repository->get_upload_dir($package, $target, $define);
+    $dest =~ s!$repository->{_upload_root}/$repository->{_queue}!$self->{_root}!;
+
+    print "Sending file $file to $dest\n" if $self->{_verbose};
+    my $destfile = "$dest".basename($file);
+    $destfile =~ s,/[^/_]+_([^/]+)$,/$1,;
+    $destfile =~ s,/@\d+:,/,;
+    my $destfilehidden = $destfile;
+    $destfilehidden =~ s,/([^/]+)$,/.$1,;
+
+    my $cmd = "scp -i $self->{_ssh_key} $file $self->{_user}\@$self->{_uphost}:/$destfilehidden";
+    my $cmd2 = "ssh -i $self->{_ssh_key} $self->{_user}\@$self->{_uphost} \"mv /$destfilehidden /$destfile\"";
+    print "Submit::Action::Send: doing $cmd\n$cmd2\n" if 1 || $self->{_verbose};
+    if (!$self->{_test}) {
+	if (!system($cmd)) {
+	    if (!system($cmd2)) {
+		print "Submit::Action::Sendcache: upload succeeded!\n";
+		return 1
+	    }
+	}
+	print "Submit::Action::Sendcache: upload failed!\n";
+    }
+}
+=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/lib/Youri/Submit/Action/Sign.pm b/lib/Youri/Submit/Action/Sign.pm
new file mode 100644
index 0000000..f016351
--- /dev/null
+++ b/lib/Youri/Submit/Action/Sign.pm
@@ -0,0 +1,56 @@
+# $Id: Sign.pm 1700 2006-10-16 12:57:42Z warly $
+package Youri::Submit::Action::Sign;
+
+=head1 NAME
+
+Youri::Submit::Action::Sign - GPG signature
+
+=head1 DESCRIPTION
+
+This action plugin ensures GPG signature of packages.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        name       => '',
+        path       => $ENV{HOME} . '/.gnupg',
+        passphrase => '',
+        @_
+    );
+
+    croak "undefined name" unless $options{name};
+    croak "undefined path" unless $options{path};
+    croak "invalid path $options{path}" unless -d $options{path};
+
+    $self->{_name}       = $options{name};
+    $self->{_path}       = $options{path};
+    $self->{_passphrase} = $options{passphrase};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    $package->sign(
+        $self->{_name},
+        $self->{_path},
+        $self->{_passphrase}
+    ) unless $self->{_test};
+}
+
+=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/lib/Youri/Submit/Action/Unpack.pm b/lib/Youri/Submit/Action/Unpack.pm
new file mode 100644
index 0000000..03444df
--- /dev/null
+++ b/lib/Youri/Submit/Action/Unpack.pm
@@ -0,0 +1,82 @@
+# $Id: Unpack.pm 115370 2007-01-30 09:59:07Z pixel $
+package Youri::Submit::Action::Unpack;
+
+=head1 NAME
+
+Youri::Submit::Action::Unpack - unpack package files
+
+=head1 DESCRIPTION
+
+This action plugin unpack package files somewhere.
+When unpack_inside_distribution_root is set, dest_directory is relative to the distribution root.
+When the package is a noarch, the wanted files are unpacked in distribution root of each archs.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use File::Temp qw/tempdir/;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my ($self, %options) = @_;
+
+    croak "undefined package name" unless $options{name};
+    croak "undefined source sub directory" unless $options{source_subdir};
+    croak "undefined destination directory" unless $options{dest_directory};
+
+    foreach my $var ('name', 'dest_directory', 'source_subdir', 'grep_files', 'unpack_inside_distribution_root') {
+	$self->{"_$var"} = $options{$var};
+    }
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    $package->get_name eq $self->{_name} or return;
+
+    my @dests = $self->{_unpack_inside_distribution_root} ? 
+	(map { "$_/$self->{_dest_directory}" } $repository->get_distribution_roots($package, $target))
+	: $self->{_dest_directory};
+    my $file = $package->as_file;
+    print "Unpacking rpm $file$self->{_source_subdir} to @dests\n" if $self->{_verbose};
+
+    my $tempdir = tempdir(CLEANUP => 1);
+
+    my $cmd = "rpm2cpio $file | (cd $tempdir ; cpio -id)";
+    print "Submit::Action::Unpack: doing $cmd\n" if $self->{_verbose};
+    if (!$self->{_test} && system($cmd) != 0) {
+	print "Submit::Action::Unpack: failed!\n" if $self->{_verbose};
+	return;
+    }
+
+    foreach my $dest (@dests) {
+	my $find_grep = $self->{_grep_files} ? "find | grep '$self->{_grep_files}'" : 'find';
+	my $cmd = "cd $tempdir/$self->{_source_subdir}; $find_grep | cpio -pdu $dest";
+	print "Submit::Action::Unpack: doing $cmd\n" if $self->{_verbose};
+	if (!$self->{_test}) {
+	    my @l = glob("$tempdir/$self->{_source_subdir}");
+	    if (@l == 1 && -d $l[0]) {
+		if (system($cmd) != 0) {
+		    print "Submit::Action::Unpack: failed!\n" if $self->{_verbose};
+		}
+	    } else {
+		print "Submit::Action::Unpack: directory $self->{_source_subdir} doesn't exist in package $self->{_name}\n";
+	    }
+	}
+    }
+}
+
+=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/lib/Youri/Submit/Action/UpdateMdvDb.pm b/lib/Youri/Submit/Action/UpdateMdvDb.pm
new file mode 100644
index 0000000..7906080
--- /dev/null
+++ b/lib/Youri/Submit/Action/UpdateMdvDb.pm
@@ -0,0 +1,62 @@
+# $Id$
+package Youri::Submit::Action::UpdateMdvDb;
+
+=head1 NAME
+
+Youri::Submit::Action::UpdateMdvDb - Mandriva maintainers database updater
+
+=head1 DESCRIPTION
+
+This action plugin calls an external script to update last commit info, as
+well as add new packages, in the package maintainers database at
+.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Action/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        @_
+    );
+
+    # path for mdvdb-updaterep script
+    $self->{_mdvdb_updaterep} = $options{mdvdb_updaterep};
+
+    return $self;
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    # only SRPMs matter
+    return unless $package->is_source();
+
+    unless ($self->{_test}) {
+        my $pkg_name = $package->get_name();
+        my $pkg_media = $repository->_get_main_section($package, $target, $define);
+        $package->get_packager() =~ m/(\w[-_.\w]+\@[-_.\w]+)\W/;
+        my $pkg_commiter = $1;
+
+        if (system($self->{_mdvdb_updaterep}, "update", $pkg_name, $pkg_media, $pkg_commiter, "youri")) {
+            print "ERROR: ".$self->{_mdvdb_updaterep}." failed for '$pkg_name', '$pkg_media', '$pkg_commiter'.\n";
+        } else {
+            print "Updated package maintainers DB for '$pkg_name', '$pkg_media', '$pkg_commiter'.\n" if $self->{_verbose};
+        }
+    }
+}
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2007, Mandriva
+
+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/lib/Youri/Submit/Check.pm b/lib/Youri/Submit/Check.pm
new file mode 100644
index 0000000..cfa8f04
--- /dev/null
+++ b/lib/Youri/Submit/Check.pm
@@ -0,0 +1,27 @@
+# $Id: Base.pm 631 2006-01-26 22:22:23Z guillomovitch $
+package Youri::Submit::Check;
+
+=head1 NAME
+
+Youri::Submit::Check - Abstract check plugin
+
+=head1 DESCRIPTION
+
+This abstract class defines check plugin interface.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Plugin/;
+
+=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/lib/Youri/Submit/Check/ACL.pm b/lib/Youri/Submit/Check/ACL.pm
new file mode 100644
index 0000000..925dc00
--- /dev/null
+++ b/lib/Youri/Submit/Check/ACL.pm
@@ -0,0 +1,71 @@
+# $Id: ACL.pm 4817 2007-02-09 19:39:05Z blino $
+package Youri::Submit::Check::ACL;
+
+=head1 NAME
+
+Youri::Submit::Check::Tag - Incorrect tag values check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages with incorrect tag values, based on regular
+expressions.
+
+=cut
+
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+my $acl;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+	acl_file => '',
+        @_
+    );
+    $acl = get_acl($options{acl_file});
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+    my $file = $package->get_full_name();
+    my $arch = $package->get_arch();
+    my $srpm = $package->get_canonical_name;
+    my $section = $repository->_get_section($package, $target, $define);
+    my $user = $define->{user};
+    foreach my $t (keys %$acl) {
+	next if $target !~ /$t/;
+	foreach my $acl (@{$acl->{$t}}) {
+	    my ($a, $media, $r, $users) = @$acl;
+	    next if $arch !~ $a || $srpm !~ $r || $section !~ $media;
+	    if ($user =~ /$users/) {
+		return 
+	    } else { 
+		return "$user is not authorized to upload packages belonging to $srpm in section $section (authorized persons: " . join(', ', split '\|',  $users) . ")";
+	    }
+	}
+    }
+    return
+}
+
+sub get_acl {
+    my ($file) = @_;
+    my %acl;
+    open my $f, $file;
+    while (<$f>) { 
+	my ($dis, $arch, $media, $regexp, $users) = split ' ';
+	push @{$acl{$dis}}, [ $arch , $media, $regexp, $users ]
+    }
+    \%acl
+}
+
+=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/lib/Youri/Submit/Check/History.pm b/lib/Youri/Submit/Check/History.pm
new file mode 100644
index 0000000..c127ed6
--- /dev/null
+++ b/lib/Youri/Submit/Check/History.pm
@@ -0,0 +1,61 @@
+# $Id: History.pm 1707 2006-10-16 16:26:42Z warly $
+package Youri::Submit::Check::History;
+
+=head1 NAME
+
+Youri::Submit::Check::History - Non-linear history check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages whose history does not include last
+available revision one.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use Youri::Package;
+use base qw/Youri::Submit::Check/;
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @errors;
+
+    my $last_revision =
+        $repository->get_last_older_revision($package, $target, $define);
+    
+    if ($last_revision) {
+        # skip the test if last revision has been produced from another source package, as it occurs during package split/merges
+        return 
+            if $last_revision->get_canonical_name()
+            ne $package->get_canonical_name();
+    
+        my ($last_revision_number) = $last_revision->get_last_change()->[Youri::Package::CHANGE_AUTHOR] =~ /(\S+)\s*$/;
+        my %entries =
+            map { $_ => 1 }
+            map { /(\S+)\s*$/ }
+            map { $_->[Youri::Package::CHANGE_AUTHOR] }
+            $package->get_changes();
+        unless ($entries{$last_revision_number}) {
+            push(
+                @errors,
+                "Last changelog entry $last_revision_number from last revision " . $last_revision->get_full_name() . "  missing from current changelog"
+            );
+        }
+    }
+
+    return @errors;
+}
+
+=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/lib/Youri/Submit/Check/Host.pm b/lib/Youri/Submit/Check/Host.pm
new file mode 100644
index 0000000..cadda4c
--- /dev/null
+++ b/lib/Youri/Submit/Check/Host.pm
@@ -0,0 +1,63 @@
+# $Id: Host.pm 230850 2007-10-04 20:07:25Z blino $
+package Youri::Submit::Check::Host;
+
+=head1 NAME
+
+Youri::Submit::Check::Tag - Incorrect tag values check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages with incorrect tag values, based on regular
+expressions.
+
+=cut
+
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+my $host;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+	host_file => '',
+        @_
+    );
+    $host = get_host($options{host_file})
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+    my $file = $package->get_file;
+    my $arch = $package->get_arch;
+    my $buildhost = $package->as_formated_string('%{buildhost}');
+    foreach my $h (keys %$host) {
+	next if $buildhost !~ $h;
+	if ($arch =~ $host->{$h}) {
+	    return
+	}
+    }
+    "Packages build on host $buildhost are not authorized for arch $arch";
+}
+
+sub get_host {
+    my ($file) = @_;
+    my %host;
+    open my $f, $file;
+    while (<$f>) { 
+	my ($host, $arch) = split ' ';
+	$host{$host} = $arch
+    }
+    \%host
+}
+
+=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/lib/Youri/Submit/Check/Precedence.pm b/lib/Youri/Submit/Check/Precedence.pm
new file mode 100644
index 0000000..c5f1a9e
--- /dev/null
+++ b/lib/Youri/Submit/Check/Precedence.pm
@@ -0,0 +1,58 @@
+# $Id: Precedence.pm 1707 2006-10-16 16:26:42Z warly $
+package Youri::Submit::Check::Precedence;
+
+=head1 NAME
+
+Youri::Submit::Check::Precedence - Release check against another check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages whose an older revision already exists for
+another upload target.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        _target => undef, # mandatory targets
+        @_
+    );
+
+    die "undefined target" unless $options{target};
+
+    $self->{_target} = $options{target};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @errors;
+
+    my @older_revisions = 
+        $repository->get_older_revisions($package, $self->{_target}, $define);
+    if (@older_revisions) {
+        push(
+            @errors,
+            "Older revisions still exists for $self->{_target}: " . join(', ', @older_revisions)
+        );
+    }
+
+    return @errors;
+}
+
+=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/lib/Youri/Submit/Check/Queue_recency.pm b/lib/Youri/Submit/Check/Queue_recency.pm
new file mode 100644
index 0000000..170d2af
--- /dev/null
+++ b/lib/Youri/Submit/Check/Queue_recency.pm
@@ -0,0 +1,40 @@
+# $Id: Queue_recency.pm 4747 2007-01-30 10:02:41Z pixel $
+package Youri::Submit::Check::Queue_recency;
+
+=head1 NAME
+
+Youri::Submit::Check::Recency - Release check against current target
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages whose a current or newer revision already
+exists for current upload target.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @newer_revisions = 
+        $repository->get_upload_newer_revisions($package, $target, $define);
+    if (@newer_revisions) {
+        return "Newer revisions already exists for $target in upload queue: " . join(', ', @newer_revisions);
+    }
+    return
+}
+
+=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/lib/Youri/Submit/Check/Recency.pm b/lib/Youri/Submit/Check/Recency.pm
new file mode 100644
index 0000000..04994b8
--- /dev/null
+++ b/lib/Youri/Submit/Check/Recency.pm
@@ -0,0 +1,64 @@
+# $Id: Recency.pm 224793 2007-07-08 02:44:48Z spuk $
+package Youri::Submit::Check::Recency;
+
+=head1 NAME
+
+Youri::Submit::Check::Recency - Release check against current target
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages whose a current or newer revision already
+exists for current upload target.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @errors;
+
+    my @revisions = $repository->get_revisions($package, $target, $define, undef, sub { return $_[0]->compare($package) >= 0 });
+    if (@revisions) {
+        my $section = $repository->_get_section($package, $target, $define);
+        push(
+            @errors,
+            "Current or newer revision(s) already exists in $section for $target: " .
+                join(', ', @revisions)
+        );
+    }
+
+    my $defined_section = $define->{section};
+
+    # if the user provided a section, check also in the default section
+    if ($defined_section) {
+        $define->{section} = undef;
+        my @default_revisions = $repository->get_revisions($package, $target, $define, undef, sub { return $_[0]->compare($package) >= 0 });
+        if (@default_revisions) {
+            my $section = $repository->_get_section($package, $target, $define);
+            push(
+                @errors,
+                "Current or newer revision(s) already exists in $section for $target: " .
+                    join(', ', @default_revisions)
+            );
+        }
+        $define->{section} = $defined_section;
+    }
+
+    return @errors;
+}
+
+=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/lib/Youri/Submit/Check/Rpmlint.pm b/lib/Youri/Submit/Check/Rpmlint.pm
new file mode 100644
index 0000000..c57dd60
--- /dev/null
+++ b/lib/Youri/Submit/Check/Rpmlint.pm
@@ -0,0 +1,90 @@
+# $Id: Rpmlint.pm 234384 2008-02-12 09:42:32Z blino $
+package Youri::Submit::Check::Rpmlint;
+
+=head1 NAME
+
+Youri::Submit::Check::Rpmlint - Rpmlint-based check
+
+=head1 DESCRIPTION
+
+This check plugin wraps rpmlint, and reject packages triggering results
+declared as fatal.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+=head2 new(%args)
+
+Creates and returns a new Youri::Submit::Check::Rpmlint object.
+
+Specific parameters:
+
+=over
+
+=item results $results
+
+List of rpmlint result id considered as fatal.
+
+=item path $path
+
+Path to the rpmlint executable (default: /usr/bin/rpmlint)
+
+=item config $config
+
+Specific rpmlint configuration.
+
+=back
+
+=cut
+
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        results  => undef,
+        path   => '/usr/bin/rpmlint',
+        config => '',
+        @_
+    );
+
+    croak "no results to check" unless $options{results};
+    croak "fatal should be an arrayref" unless ref $options{results} eq 'ARRAY';
+
+    $self->{_config} = $options{config};
+    $self->{_path} = $options{path};
+    $self->{_pattern} = '^(?:' . join('|', @{$options{results}}) . ')$';
+}
+
+sub run {
+    my ($self, $package, $_repository, $_target, $_define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @errors;
+
+    my $command = "$self->{_path} -f $self->{_config} " . $package->as_file;
+    open(my $RPMLINT, "$command |") or die "Can't run $command: $!";
+    while (my $line = <$RPMLINT>) {
+	$line =~ /^[EW]: \S+ (\S+)(.*)$/ # old rpmlint format
+	  || $line =~ /^\S+: [EW]: (\S+)(.*)$/ or next; # new rpmlint format
+        my ($id, $value) = ($1, $2);
+        if ($id =~ /$self->{_pattern}/o) {
+            push(@errors, "$id$value");
+        }
+    }
+
+    return @errors;
+}
+=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/lib/Youri/Submit/Check/SVN.pm b/lib/Youri/Submit/Check/SVN.pm
new file mode 100644
index 0000000..e3362c8
--- /dev/null
+++ b/lib/Youri/Submit/Check/SVN.pm
@@ -0,0 +1,79 @@
+# $Id: SVN.pm 4747 2007-01-30 10:02:41Z pixel $
+package Youri::Submit::Check::SVN;
+
+=head1 NAME
+
+Youri::Submit::Check::Tag - Incorrect tag values check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages with incorrect tag values, based on regular
+expressions.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+	svn => '',
+	@_
+    );
+    $self->{_svn} = $options{svn};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my $section = $repository->_get_section($package, $target, $define);
+    if ($section =~ /\/(testing|backport)$/) {
+	# FIXME, right now ignore packages in SVN for testing and backports
+	# we need to find a clean way to handle them
+	return
+    }
+
+    $package->is_source or return;
+    my $file = $package->get_file_name;
+    my $srpm_name = $package->get_canonical_name;
+    if ($repository->package_in_svn($srpm_name)) {
+	if ($file !~ /(^|\/|$define->{prefix}_)@\d+:\Q$srpm_name/)  {
+	    return "package $srpm_name is in the SVN, the uploaded SRPM must look like @:$srpm_name--.src.rpm (created with getsrpm-mdk $srpm_name)";
+	} else  {
+	    print "Package $file is correct\n";
+	}
+    }
+    return
+}
+
+sub simple_prompt {
+    my $cred = shift;
+    my $realm = shift;
+    my $default_username = shift;
+    my $may_save = shift;
+    my $pool = shift;
+
+    print "Enter authentication info for realm: $realm\n";
+    print "Username: ";
+    my $username = <>;
+    chomp($username);
+    $cred->username($username);
+    print "Password: ";
+    my $password = <>;
+    chomp($password);
+    $cred->password($password);
+}
+
+=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/lib/Youri/Submit/Check/Section.pm b/lib/Youri/Submit/Check/Section.pm
new file mode 100644
index 0000000..4ff1675
--- /dev/null
+++ b/lib/Youri/Submit/Check/Section.pm
@@ -0,0 +1,58 @@
+# $Id: Precedence.pm 1707 2006-10-16 16:26:42Z warly $
+package Youri::Submit::Check::Section;
+
+=head1 NAME
+
+Youri::Submit::Check::Section - Check if package was submitted to the right section
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages which were submitted to a section
+different than the one where an older version already exists.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @errors;
+
+    my $submitted_main_section = $repository->_get_main_section($package, $target, $define);
+
+    # undefine section, so that Repository::_get_section() of Mandriva_upload.pm
+    # finds the section from existing packages
+    my $defined_section = $define->{section};
+    undef $define->{section};
+
+    my $old_main_section = $repository->_get_main_section($package, $target, $define);
+    my @older_revisions = $repository->get_older_revisions($package, $target, $define);
+
+    # restore defined section
+    $define->{section} = $defined_section;
+
+    if (@older_revisions && $submitted_main_section ne $old_main_section) {
+        push(
+            @errors,
+	     "Section should be $old_main_section, not $submitted_main_section."
+        );
+    }
+
+
+    return @errors;
+}
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2007, Mandriva
+
+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/lib/Youri/Submit/Check/Source.pm b/lib/Youri/Submit/Check/Source.pm
new file mode 100644
index 0000000..9c47f5d
--- /dev/null
+++ b/lib/Youri/Submit/Check/Source.pm
@@ -0,0 +1,45 @@
+# $Id: Source.pm 4747 2007-01-30 10:02:41Z pixel $
+package Youri::Submit::Check::Source;
+
+=head1 NAME
+
+Youri::Submit::Check::Tag - Incorrect tag values check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages with incorrect tag values, based on regular
+expressions.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        @_
+    );
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+    my $file = $package->as_file();
+    if (!$package->is_source()) {
+        return "Package $file is not a source rpm";
+    }
+    return
+}
+
+=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/lib/Youri/Submit/Check/Tag.pm b/lib/Youri/Submit/Check/Tag.pm
new file mode 100644
index 0000000..c0f9b9c
--- /dev/null
+++ b/lib/Youri/Submit/Check/Tag.pm
@@ -0,0 +1,61 @@
+# $Id: Tag.pm 1707 2006-10-16 16:26:42Z warly $
+package Youri::Submit::Check::Tag;
+
+=head1 NAME
+
+Youri::Submit::Check::Tag - Incorrect tag values check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages with incorrect tag values, based on regular
+expressions.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        tags => undef, # expected tag values
+        @_
+    );
+
+    croak "no tags to check" unless $options{tags};
+    croak "tag should be an hashref" unless ref $options{tags} eq 'HASH';
+
+    $self->{_tags} = $options{tags};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @errors;
+
+    foreach my $tag (keys %{$self->{_tags}}) {
+        my $value = $package->get_tag($tag);
+        if ($value !~ /$self->{_tags}->{$tag}/) {
+            push(
+                @errors,
+                "invalid value $value for tag $tag"
+            );
+        }
+    }
+
+    return @errors;
+
+}
+
+=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/lib/Youri/Submit/Check/Type.pm b/lib/Youri/Submit/Check/Type.pm
new file mode 100644
index 0000000..d95af5a
--- /dev/null
+++ b/lib/Youri/Submit/Check/Type.pm
@@ -0,0 +1,54 @@
+# $Id: Type.pm 4747 2007-01-30 10:02:41Z pixel $
+package Youri::Submit::Check::Type;
+
+=head1 NAME
+
+Youri::Submit::Check::Type - Type check
+
+=head1 DESCRIPTION
+
+This check plugin rejects packages with incorrect type.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use base qw/Youri::Submit::Check/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        type => undef, # expected type
+        @_
+    );
+
+    croak "no type to check" unless $options{type};
+    croak "invalid type value" unless $options{type} =~ /^(?:source|binary)$/;
+
+    $self->{_type} = $options{type};
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+
+    my @errors;
+
+    my $type = $package->get_type();
+    if ($type ne $self->{_type}) {
+        push(@errors, "invalid type $type");
+    }
+
+    return @errors;
+}
+
+=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/lib/Youri/Submit/Check/Version.pm b/lib/Youri/Submit/Check/Version.pm
new file mode 100644
index 0000000..a9c2ae8
--- /dev/null
+++ b/lib/Youri/Submit/Check/Version.pm
@@ -0,0 +1,102 @@
+# $Id: Version.pm 267050 2010-03-23 17:36:49Z nvigier $
+package Youri::Submit::Check::Version;
+
+=head1 NAME
+
+Youri::Submit::Check::Version - Check if older version already exist in cooker (used in freeze period)
+
+=head1 DESCRIPTION
+
+This check plugin rejects new version of packages if they are not mentioned as authorized 
+in the configuration file or in a non frozen section.
+
+=cut
+
+use warnings;
+use strict;
+use Carp;
+use URPM;
+use base qw/Youri::Submit::Check/;
+
+sub _init {
+    my $self   = shift;
+    my %options = (
+        @_
+    );
+
+    foreach my $target (keys %options) { 
+	$self->{$target} = $options{$target}
+    }
+}
+
+sub run {
+    my ($self, $package, $repository, $target, $define) = @_;
+    croak "Not a class method" unless ref $self;
+    my $opt = $self->{$target};
+    return if $opt->{mode} eq 'normal';
+    my $section = $repository->_get_section($package, $target, $define);
+    my $name = $package->get_canonical_name;
+    return if $name =~ /$opt->{authorized_packages}/;
+    my $arch = $repository->get_arch($package, $target, $define);
+    return if $arch =~ /$opt->{authorized_arches}/;
+    if ($opt->{mode} eq 'version_freeze') {
+	return if $section =~ /$opt->{authorized_sections}/;
+	my $user = $define->{user};
+	return if $user =~ /^($opt->{authorized_users})$/;
+	my ($package_version) = $package =~ /-([^-]+)-[^-]+\.src$/;
+	$define->{arch} = 'src';
+	my @revisions = $repository->get_revisions($package, $target, $define, undef,
+	    sub {
+		my ($version) = $_[0] =~ /-([^-]+)-[^-]+\.src$/;
+		URPM::ranges_overlap("== $version", "< $package_version")
+	    }
+	);
+	$define->{arch} = '';
+	if (@revisions) {
+	    return "FREEZE, package @revisions of different versions exist in $target\n";
+	}
+    }
+    # FIXME: The following code is not working and must be reviewed.
+    elsif ($opt->{mode} eq 'freeze') {
+	my $user = $define->{user};
+	return if (defined($opt->{authorized_users}) && $user =~ /^($opt->{authorized_users})$/);
+	# XXX: So freeze mode really only check for this exceptions?
+	if ($section !~ /$opt->{authorized_sections}/) {
+	    return "FREEZE: repository $target section $section is frozen, you can still submit your packages in testing\nTo do so use your.devel --define section=
$target ... "; + } + } else { + # FIXME: Calls to get_source_package seems invalid nowadays. + # This results on $source having a null content. + my $source = $package->get_source_package; + my ($package_version) = $source =~ /-([^-]+)-[^-]+\.src\.rpm$/; + $define->{arch} = 'src'; + # FIXME: get_revisions now expects the filter as the 5th element, and not the 4th. + my @revisions = $repository->get_revisions($package, $target, $define, + sub { + # FIXME: Calls to get_source_package seems invalid nowadays. + # This results on $source_package having a null content. + my $source_package = $_[0]->get_source_package; + my ($version) = $source_package =~ /-([^-]+)-[^-]+\.src\.rpm$/; + print STDERR "Found version $version\n"; + URPM::ranges_overlap("== $version", "< $package_version") + } + ); + $define->{arch} = ''; + if (@revisions) { + return "FREEZE, package @revisions of different versions exist in $target\n"; + } + } + return +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2006, YOURI project +Copyright (C) 2006, Mandriva + +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/lib/Youri/Submit/Plugin.pm b/lib/Youri/Submit/Plugin.pm new file mode 100644 index 0000000..4c72ff7 --- /dev/null +++ b/lib/Youri/Submit/Plugin.pm @@ -0,0 +1,93 @@ +# $Id: Plugin.pm 4746 2007-01-30 10:01:14Z pixel $ +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 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/lib/Youri/Submit/Post.pm b/lib/Youri/Submit/Post.pm new file mode 100644 index 0000000..b708b11 --- /dev/null +++ b/lib/Youri/Submit/Post.pm @@ -0,0 +1,27 @@ +# $Id: Post.pm 4746 2007-01-30 10:01:14Z pixel $ +package Youri::Submit::Post; + +=head1 NAME + +Youri::Submit::Post - Abstract post plugin + +=head1 DESCRIPTION + +This abstract class defines post plugin interface. + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Plugin/; + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2006, Mandriva + +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/lib/Youri/Submit/Post/CleanRpmsrate.pm b/lib/Youri/Submit/Post/CleanRpmsrate.pm new file mode 100644 index 0000000..977e2a0 --- /dev/null +++ b/lib/Youri/Submit/Post/CleanRpmsrate.pm @@ -0,0 +1,53 @@ +# $Id: CleanRpmsrate.pm 115367 2007-01-30 09:47:04Z pixel $ +package Youri::Submit::Post::CleanRpmsrate; + +=head1 NAME + +Youri::Submit::Post::CleanRpmsrate - calls clean-rpmsrate + +=head1 DESCRIPTION + +Calls clean-rpmsrate + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Post/; + +#- inlined from MDK::Common::DataStructure +sub uniq { my %l; $l{$_} = 1 foreach @_; grep { delete $l{$_} } @_ } + +sub _init { +} + +sub run { + my ($self, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + my $root = $repository->get_install_root(); + my @changed = @{$repository->get_arch_changed($target)}; + if (grep { $_ eq 'i586' } @changed) { + # x86_64 uses i586 pkgs, so rpmsrate need to be rebuild + @changed = uniq(@changed, 'x86_64'); + } + foreach my $arch (@changed) { + my $rpmsrate = "$root/$target/$arch/media/media_info/rpmsrate"; + my @media = "$root/$target/$arch/media/main/release"; + system("cp", "$rpmsrate-raw", "$rpmsrate-new"); + system("clean-rpmsrate", "$rpmsrate-new", @media); + system("mv", "-f", "$rpmsrate-new", $rpmsrate); + } + return +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2007, Mandriva + +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/lib/Youri/Submit/Post/Gendistrib.pm b/lib/Youri/Submit/Post/Gendistrib.pm new file mode 100644 index 0000000..98205c7 --- /dev/null +++ b/lib/Youri/Submit/Post/Gendistrib.pm @@ -0,0 +1,66 @@ +# $Id: Gendistrib.pm 115367 2007-01-30 09:47:04Z pixel $ +package Youri::Submit::Post::Gendistrib; + +=head1 NAME + +Youri::Submit::Post::Gendistrib - calls gendistrib + +=head1 DESCRIPTION + +Calls gendistrib + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Post/; + +sub _init { + my $self = shift; + my %options = ( + user => '', + host => '', + source => '', + destination => '', + @_ + ); + + foreach my $var ('tmpdir', 'command') { + $self->{"_$var"} = $options{$var}; + } +} + +sub run { + my ($self, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + my $root = $repository->get_install_root(); + (undef, undef, my $hour) = gmtime(time); + # during the night, use complete hdlist rebuild + my $fast = '--fast'; + $fast = ''; # blino: don't use fast for now, it might be broken + if ($hour > 22 && $hour < 5) { + if ($hour < 4) { + $fast = '--blind' + } else { + $fast = '' + } + } + foreach my $arch (@{$repository->get_arch_changed($target)}) { + my $cmd = "TMPDIR=$self->{_tmpdir}/$target/$arch time $self->{_command} --nochkdep --nobadrpm $fast --noclean $root/$target/$arch"; + print "$cmd\n"; + system($cmd); + } + return +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2002-2006, Mandriva + +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/lib/Youri/Submit/Post/Genhdlist2.pm b/lib/Youri/Submit/Post/Genhdlist2.pm new file mode 100644 index 0000000..60886ef --- /dev/null +++ b/lib/Youri/Submit/Post/Genhdlist2.pm @@ -0,0 +1,82 @@ +# $Id: Gendistrib.pm 115367 2007-01-30 09:47:04Z pixel $ +package Youri::Submit::Post::Genhdlist2; + +=head1 NAME + +Youri::Submit::Post::Genhdlist2 - calls genhdlist2 + +=head1 DESCRIPTION + +Calls genhdlist2 + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Post/; + +sub _init { + my $self = shift; + my %options = ( + user => '', + host => '', + source => '', + destination => '', + @_ + ); + + foreach my $var ('command') { + $self->{"_$var"} = $options{$var}; + } +} + +sub run { + my ($self, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + my $root = $repository->get_install_root(); + my @changed = @{$repository->get_install_dir_changed($target)}; + if (!@changed) { + print "nothing to do\n"; + return; + } + foreach my $dir (@changed) { + my $file_deps = "$dir/../../media_info/file-deps"; + my $file_deps_option = -e $file_deps ? "--file-deps $file_deps" : ''; + my $cmd = "time $self->{_command} -v --versioned --allow-empty-media $file_deps_option $dir"; + print "$cmd\n"; + system($cmd) == 0 or print "ERROR: $cmd failed\n"; + } + + # need to redo global MD5SUM. This MD5SUM is mostly obsolete, but is still needed up to 2007.1 + # (and even on cooker for existing urpmi.cfg) + foreach my $arch (@{$repository->get_arch_changed($target)}) { + my $dir = "$root/$target/$arch/media/media_info"; + my $cmd = "cd $dir ; time md5sum hdlist_* synthesis.*"; + print "$cmd\n"; + my $m = `$cmd`; + open my $f, '>', "$dir/MD5SUM" or die "Can't write $dir/MD5SUM: $!\n"; + print $f $m; + + { + require MDV::Distribconf::Build; + my $distrib = MDV::Distribconf::Build->new("$root/$target/$arch"); + $distrib->loadtree or die "$root/$target/$arch does not seem to be a distribution tree\n"; + $distrib->parse_mediacfg; + $distrib->write_version($distrib->getfullpath(undef, "VERSION")); + print "updated $root/$target/$arch/VERSION\n"; + } + } + return; +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2002-2006, Mandriva + +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/lib/Youri/Submit/Pre.pm b/lib/Youri/Submit/Pre.pm new file mode 100644 index 0000000..2d5b5c8 --- /dev/null +++ b/lib/Youri/Submit/Pre.pm @@ -0,0 +1,27 @@ +# $Id: Pre.pm 4746 2007-01-30 10:01:14Z pixel $ +package Youri::Submit::Pre; + +=head1 NAME + +Youri::Submit::Pre - Abstract pre plugin + +=head1 DESCRIPTION + +This abstract class defines pre plugin interface. + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Plugin/; + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2006, Mandriva + +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/lib/Youri/Submit/Pre/Rsync.pm b/lib/Youri/Submit/Pre/Rsync.pm new file mode 100644 index 0000000..accaace --- /dev/null +++ b/lib/Youri/Submit/Pre/Rsync.pm @@ -0,0 +1,87 @@ +# $Id: Rsync.pm 267280 2010-04-01 19:57:53Z bogdano $ +package Youri::Submit::Pre::Rsync; + +=head1 NAME + +Youri::Submit::Pre::Rsync - Old revisions archiving + +=head1 DESCRIPTION + +This action plugin ensures archiving of old package revisions. + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Pre/; + +sub _init { + my $self = shift; + my %options = ( + user => '', + host => '', + source => '', + destination => '', + @_ + ); + + foreach my $var ('user', 'host', 'source', 'destination') { + $self->{"_$var"} = $options{$var}; + } +} + +sub run { + my ($self, $pre_packages, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + + if (system("rsync --exclude '*.new' --exclude '.*' --remove-sent-files -avlPHe 'ssh -xc arcfour' $self->{_user}\@$self->{_host}:$self->{_source}/$target/ $self->{_destination}/$target/")) { + $self->{_error} = "Rsync command failed ($!)"; + return + } + my $queue = "$self->{_destination}/$target"; + $self->{_error} = "Reading queue directory failed"; + # now get the packages downloaded + my %packages; + opendir my $queuedh, "$self->{_destination}/$target/" or return "Could not open $self->{_destination}/$target"; + opendir my $targetdh, $queue or return "Could not open $queue"; + my $idx; + foreach my $media (readdir $targetdh) { + $media =~ /^\.{1,2}$/ and next; + print "$target - $media\n"; + if (-d "$queue/$media") { + opendir my $submediadh, "$queue/$media" or return "Could not open $queue/$media"; + foreach my $submedia (readdir $submediadh) { + $submedia =~ /^\.{1,2}$/ and next; + print "$target - $media - $submedia\n"; + opendir my $rpmdh, "$queue/$media/$submedia" or return "Could not open $queue/$media/$submedia"; + foreach my $rpm (readdir $rpmdh) { + $rpm =~ /^\.{1,2}$/ and next; + print "$target - $media - $submedia : $rpm\n"; + my $file = "$queue/$media/$submedia/$rpm"; + $file =~ s/\/+/\//g; + if ($rpm =~ /^(\d{14}\.\w+\.\w+\.\d+)_.*\.rpm$/) { + push @{$packages{$1}{rpms}}, { section => "$media/$submedia", file => $file }; + } elsif ($rpm =~ /\.rpm$/) { + $idx++; + push @{$packages{"independant_$idx"}{rpms}}, { section => "$media/$submedia", file => $file } + } + } + } + } + } + foreach my $key (keys %packages) { + push @$pre_packages, $packages{$key}{rpms} + } + return +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2002-2006, Mandriva + +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/lib/Youri/Submit/Reject.pm b/lib/Youri/Submit/Reject.pm new file mode 100644 index 0000000..7d70e22 --- /dev/null +++ b/lib/Youri/Submit/Reject.pm @@ -0,0 +1,27 @@ +# $Id: Reject.pm 4746 2007-01-30 10:01:14Z pixel $ +package Youri::Submit::Reject; + +=head1 NAME + +Youri::Submit::Reject - Abstract reject plugin + +=head1 DESCRIPTION + +This abstract class defines reject plugin interface. + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Plugin/; + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2006, Mandriva + +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/lib/Youri/Submit/Reject/Archive.pm b/lib/Youri/Submit/Reject/Archive.pm new file mode 100644 index 0000000..e90bc19 --- /dev/null +++ b/lib/Youri/Submit/Reject/Archive.pm @@ -0,0 +1,61 @@ +# $Id: Archive.pm 4747 2007-01-30 10:02:41Z pixel $ +package Youri::Submit::Reject::Install; + +=head1 NAME + +Youri::Submit::Action::Archive - Old revisions archiving + +=head1 DESCRIPTION + +This action plugin ensures archiving of old package revisions. + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Reject/; + +sub _init { + my $self = shift; + my %options = ( + perms => 644, + @_ + ); + + $self->{_perms} = $options{perms}; + + return $self; +} + +sub run { + my ($self, $package, $errors, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + + my $file = $package->get_file(); + my $rpm = $package->get_file_name(); + my $dest = $repository->get_reject_dir($package, $target, $define); + + # FIXME remove prefix this should be done by a function + $rpm =~ s/^\d{14}\.\w+\.\w+\.\d+_//; + print "installing file $file to $dest/$rpm\n" ;#if $self->{_verbose}; + + unless ($self->{_test}) { + # create destination dir if needed + system("install -d -m " . ($self->{_perms} + 111) . " $dest/") + unless -d $dest; + + # install file to new location + system("install -m $self->{_perms} $file $dest/$rpm"); + } +} + +=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/lib/Youri/Submit/Reject/Clean.pm b/lib/Youri/Submit/Reject/Clean.pm new file mode 100644 index 0000000..9d6d003 --- /dev/null +++ b/lib/Youri/Submit/Reject/Clean.pm @@ -0,0 +1,36 @@ +# $Id: Clean.pm 4747 2007-01-30 10:02:41Z pixel $ +package Youri::Submit::Reject::Clean; + +=head1 NAME + +Youri::Submit::Action::Clean - Old revisions cleanup + +=head1 DESCRIPTION + +This action plugin ensures cleanup of old package revisions. + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Reject/; + +sub run { + my ($self, $package, $errors, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + + my $file = $package->get_file(); + print "deleting file $file\n" if $self->{_verbose}; + unlink $file unless $self->{_test}; +} + +=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/lib/Youri/Submit/Reject/Install.pm b/lib/Youri/Submit/Reject/Install.pm new file mode 100644 index 0000000..f5215d1 --- /dev/null +++ b/lib/Youri/Submit/Reject/Install.pm @@ -0,0 +1,63 @@ +# $Id: Install.pm 4747 2007-01-30 10:02:41Z pixel $ +package Youri::Submit::Reject::Install; + +=head1 NAME + +Youri::Submit::Action::Archive - Old revisions archiving + +=head1 DESCRIPTION + +This action plugin ensures archiving of old package revisions. + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Reject/; + +sub _init { + my $self = shift; + my %options = ( + perms => 644, + @_ + ); + + $self->{_perms} = $options{perms}; + $self->{_verbose} = $options{verbose}; +} + +sub run { + my ($self, $package, $errors, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + + my $file = $package->get_file(); + my $rpm = $package->get_file_name(); + my $dest = $repository->get_reject_path($package, $target, $define); + + # FIXME remove prefix this should be done by a function + $rpm =~ s/^\d{14}\.\w+\.\w+\.\d+_//; + print "installing file $file to $dest/$rpm\n" if $self->{_verbose}; + + unless ($self->{_test}) { + # create destination dir if needed + system("install -d -m " . ($self->{_perms} + 111) . " $dest/") + unless -d $dest; + + # install file to new location + system("install -m $self->{_perms} $file $dest/$rpm"); + } + $package->{_file} = "$dest/$rpm"; + print "deleting file $file\n" if $self->{_verbose}; + unlink $file unless $self->{_test}; +} + +=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/lib/Youri/Submit/Reject/Mail.pm b/lib/Youri/Submit/Reject/Mail.pm new file mode 100644 index 0000000..6fa50f7 --- /dev/null +++ b/lib/Youri/Submit/Reject/Mail.pm @@ -0,0 +1,112 @@ +# $Id: Mail.pm 223952 2007-06-23 13:54:13Z pixel $ +package Youri::Submit::Reject::Mail; + +=head1 NAME + +Youri::Submit::Action::Mail - Mail notification + +=head1 DESCRIPTION + +This action plugin ensures mail notification of new package revisions. + +=cut + +use warnings; +use strict; +use MIME::Entity; +use Encode qw/from_to/; +use Carp; +use Youri::Package; +use base qw/Youri::Submit::Reject/; + +sub _init { + my $self = shift; + my %options = ( + mta => '/usr/sbin/sendmail', + to => '', + from => '', + cc => '', + prefix => '', + encoding => 'quoted-printable', + charset => 'iso-8859-1', + @_ + ); + + croak "undefined mail MTA" unless $options{mta}; + croak "invalid mail MTA $options{mta}" unless -x $options{mta}; + croak "undefined to" unless $options{to}; + if ($options{cc}) { + croak "cc should be an hashref" unless ref $options{cc} eq 'HASH'; + } + croak "invalid charset $options{charset}" + unless Encode::resolve_alias($options{charset}); + + $self->{_mta} = $options{mta}; + $self->{_to} = $options{to}; + $self->{_from} = $options{from}; + $self->{_cc} = $options{cc}; + $self->{_prefix} = $options{prefix}; + $self->{_encoding} = $options{encoding}; + $self->{_charset} = $options{charset}; +} + +sub run { + my ($self, $package, $errors, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + + my $section = $repository->_get_section($package, $target, $define); + + my $subject = + ($self->{_prefix} ? '[' . $self->{_prefix} . '] ' : '' ) . ($section ? "$section " : '') . + $package->get_revision_name(); + my $information = $package->get_information(); + my $last_change = $package->get_last_change(); + my $author = $last_change->[Youri::Package::CHANGE_AUTHOR] if $last_change; + my $list = $last_change->[Youri::Package::CHANGE_TEXT] if $last_change; + my $content = + "Errors: \n\n" . join("\n", map { + ( "* $_", (map { " - $_" } @{$errors->{$_}}), "\n"); + } sort(keys %$errors)) . "\n" . + $information . "\n" . + $author . ":\n$list"; + + # ensure proper codeset conversion + # for informations coming from package + my $charset = $repository->get_package_charset(); + from_to($content, $charset, $self->{_charset}); + from_to($subject, $charset, $self->{_charset}); + + my $mail = MIME::Entity->build( + Type => 'text/plain', + Charset => $self->{_charset}, + Encoding => $self->{_encoding}, + From => $self->{_from}, + To => $self->{_to}, + Subject => $subject, + Data => $content, + ); + + if ($self->{_cc}) { + my $cc = $self->{_cc}->{$package->get_name()}; + $mail->head()->add('cc', $cc) if $cc; + } + + if ($self->{_test}) { + $mail->print(\*STDOUT); + } else { + open(MAIL, "| $self->{_mta} -t -oi -oem") or die "Can't open MTA program: $!"; + $mail->print(\*MAIL); + close MAIL; + } + +} + +=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..3286c0e --- /dev/null +++ b/t/00distribution.t @@ -0,0 +1,15 @@ +#!/usr/bin/perl +# $Id: 00distribution.t 1723 2006-10-17 13:53:27Z warly $ + +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/ ]; + } +} -- cgit v1.2.1 From 5c6ecec2883da9738911338811b275704f256b1b Mon Sep 17 00:00:00 2001 From: Nicolas Vigier Date: Thu, 20 Jan 2011 16:38:50 +0000 Subject: add script to sign package --- mga-signpackage | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100755 mga-signpackage diff --git a/mga-signpackage b/mga-signpackage new file mode 100755 index 0000000..435e92e --- /dev/null +++ b/mga-signpackage @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +use strict; +use RPM4::Sign; +use File::Spec; + +sub signpackage { + my ($file, $name, $path) = @_; + + # check if parent directory is writable + my $parent = (File::Spec->splitpath($file))[1]; + die "Unsignable package, parent directory is read-only" + unless -w $parent; + + my $sign = RPM4::Sign->new( + name => $name, + path => $path, + passphrase => '', + ); + + $sign->rpmssign($file) +} + +if (@ARGV != 3) { + exit 1; +} + +signpackage(@ARGV); + -- cgit v1.2.1 From 070375858115c58bacd63ec880236f1ddac33612 Mon Sep 17 00:00:00 2001 From: Nicolas Vigier Date: Thu, 20 Jan 2011 17:10:16 +0000 Subject: use mga-signpackage script with sudo to sign packages --- lib/Youri/Submit/Action/Sign.pm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/Youri/Submit/Action/Sign.pm b/lib/Youri/Submit/Action/Sign.pm index f016351..d9580b8 100644 --- a/lib/Youri/Submit/Action/Sign.pm +++ b/lib/Youri/Submit/Action/Sign.pm @@ -19,6 +19,8 @@ use base qw/Youri::Submit::Action/; sub _init { my $self = shift; my %options = ( + signuser => 'signbot', + signscript => '/usr/bin/mga-signpackage', name => '', path => $ENV{HOME} . '/.gnupg', passphrase => '', @@ -32,17 +34,17 @@ sub _init { $self->{_name} = $options{name}; $self->{_path} = $options{path}; $self->{_passphrase} = $options{passphrase}; + $self->{_signuser} = $options{signuser}; + $self->{_signscript} = $options{signscript}; } sub run { my ($self, $package, $repository, $target, $define) = @_; croak "Not a class method" unless ref $self; - $package->sign( - $self->{_name}, - $self->{_path}, - $self->{_passphrase} - ) unless $self->{_test}; + if (! $self->{_test}) { + system('/usr/bin/sudo', '-u', $self->{_signuser}, $self->{_signscript}, $package->{_file}, $self->{_name}, $self->{_path}) == 0; + } } =head1 COPYRIGHT AND LICENSE -- cgit v1.2.1 From 7654a1f262d0da0cb3ddea8c92baf07cfab3b1be Mon Sep 17 00:00:00 2001 From: Nicolas Vigier Date: Thu, 20 Jan 2011 17:35:27 +0000 Subject: move mga-signpackage to bin directory and add it in Makefile.PL --- Makefile.PL | 3 ++- bin/mga-signpackage | 29 +++++++++++++++++++++++++++++ mga-signpackage | 29 ----------------------------- 3 files changed, 31 insertions(+), 30 deletions(-) create mode 100755 bin/mga-signpackage delete mode 100755 mga-signpackage diff --git a/Makefile.PL b/Makefile.PL index 09ff7f7..933d412 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -9,7 +9,8 @@ WriteMakefile( EXE_FILES => [ 'bin/youri-submit', 'bin/youri-submit-restricted', - 'bin/youri-submit-proxy' + 'bin/youri-submit-proxy', + 'bin/mga-signpackage' ], PREREQ_PM => { 'Youri::Config' => 0, diff --git a/bin/mga-signpackage b/bin/mga-signpackage new file mode 100755 index 0000000..435e92e --- /dev/null +++ b/bin/mga-signpackage @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +use strict; +use RPM4::Sign; +use File::Spec; + +sub signpackage { + my ($file, $name, $path) = @_; + + # check if parent directory is writable + my $parent = (File::Spec->splitpath($file))[1]; + die "Unsignable package, parent directory is read-only" + unless -w $parent; + + my $sign = RPM4::Sign->new( + name => $name, + path => $path, + passphrase => '', + ); + + $sign->rpmssign($file) +} + +if (@ARGV != 3) { + exit 1; +} + +signpackage(@ARGV); + diff --git a/mga-signpackage b/mga-signpackage deleted file mode 100755 index 435e92e..0000000 --- a/mga-signpackage +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/perl -w - -use strict; -use RPM4::Sign; -use File::Spec; - -sub signpackage { - my ($file, $name, $path) = @_; - - # check if parent directory is writable - my $parent = (File::Spec->splitpath($file))[1]; - die "Unsignable package, parent directory is read-only" - unless -w $parent; - - my $sign = RPM4::Sign->new( - name => $name, - path => $path, - passphrase => '', - ); - - $sign->rpmssign($file) -} - -if (@ARGV != 3) { - exit 1; -} - -signpackage(@ARGV); - -- cgit v1.2.1 From 9b8e206898849b530b72f9ca803eab9b711f1a4a Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Sat, 22 Jan 2011 14:49:03 +0000 Subject: Ugly code rejecting submit when buildrequires are missing --- lib/Youri/Submit/Check/Deps.pm | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 lib/Youri/Submit/Check/Deps.pm diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm new file mode 100644 index 0000000..6812d38 --- /dev/null +++ b/lib/Youri/Submit/Check/Deps.pm @@ -0,0 +1,87 @@ +package Youri::Submit::Check::Deps; + +=head1 NAME + +Youri::Submit::Check::Deps - Check dependencies + +=head1 DESCRIPTION + +This check plugin rejects packages with unresolved dependencies. + +=cut + +use warnings; +use strict; +use Carp; +use Youri::Media::URPM; +use base qw/Youri::Submit::Check/; + +sub resolvedep { + my ($media, @requires) = @_; + + my @errors; + my $index = sub { + my ($package) = @_; + + my @provides = $package->get_provides(); + + @requires = grep { + my $require = $_; + my $notfound = 1; + foreach my $provide (@provides) { + next unless $provide->[Youri::Package::DEPENDENCY_NAME] eq $require->[Youri::Package::DEPENDENCY_NAME]; + if ($require->[Youri::Package::DEPENDENCY_RANGE]) { + next unless $package->check_ranges_compatibility($provide->[Youri::Package::DEPENDENCY_RANGE], $require->[Youri::Package::DEPENDENCY_RANGE]); + } + $notfound = 0; + } + + if ($notfound && $require->[Youri::Package::DEPENDENCY_NAME] =~ m|/|) { + foreach my $file ($package->get_files()) { + next unless $file eq $require->[Youri::Package::DEPENDENCY_NAME]; + $notfound = 0; + last; + } + } + $notfound; + } @requires; + }; + $media->traverse_headers($index); + foreach my $require (@requires) { + push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME]); + } + return @errors; +} + +sub run { + my ($self, $package, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + + # FIXME Define some Youri::Media with allowed_deps in the config and + # match target + section to a media + my $section = $repository->_get_section($package, $target, $define); + return unless $target eq "cauldron" && $section eq 'core/release'; + + my @requires = $package->get_requires(); + + my $path = $repository->get_install_root() . "/" . $target; + # FIXME we need dependencies on all archs except for ExclusiveArch + my $arch = 'i586'; +# foreach my $arch ($repository->get_extra_arches()) { + my $media = new Youri::Media::URPM(name => "core.".$arch, + type => "binary", + hdlist => "$path/$arch/media/$section/media_info/hdlist.cz"); + return resolvedep($media, @requires); +# } + +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2011, YOURI project + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=cut + +1; -- cgit v1.2.1 From ca35aed375324b08a53226f2db2a897d9be893b0 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Tue, 25 Jan 2011 11:03:14 +0000 Subject: Check dependencies on x86_64 as this is where the src.rpm is generated --- lib/Youri/Submit/Check/Deps.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm index 6812d38..fa239df 100644 --- a/lib/Youri/Submit/Check/Deps.pm +++ b/lib/Youri/Submit/Check/Deps.pm @@ -66,7 +66,9 @@ sub run { my $path = $repository->get_install_root() . "/" . $target; # FIXME we need dependencies on all archs except for ExclusiveArch - my $arch = 'i586'; + # Unfortunately some dependencies depend on the arch were the src.rpm was geenrated + # Currently src.rpm is generated on x86_64, so we need to check on that one + my $arch = 'x86_64'; # foreach my $arch ($repository->get_extra_arches()) { my $media = new Youri::Media::URPM(name => "core.".$arch, type => "binary", -- cgit v1.2.1 From 0a086e6f377ee200265c1ac8be9b0556f76bfe85 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Thu, 27 Jan 2011 21:26:04 +0000 Subject: Display the required version of missing dep --- lib/Youri/Submit/Check/Deps.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm index fa239df..06567d4 100644 --- a/lib/Youri/Submit/Check/Deps.pm +++ b/lib/Youri/Submit/Check/Deps.pm @@ -48,7 +48,7 @@ sub resolvedep { }; $media->traverse_headers($index); foreach my $require (@requires) { - push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME]); + push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME] . " " . $require->[Youri::Package::DEPENDENCY_RANGE]); } return @errors; } -- cgit v1.2.1 From 3760bb5c7f6b2cc24cc263d7c3e8b7348b8ed5bf Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Tue, 8 Feb 2011 13:13:52 +0000 Subject: Allow submitting drakx-installer-images where BuildRequires version is in the name --- lib/Youri/Submit/Check/Deps.pm | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm index 06567d4..463d29a 100644 --- a/lib/Youri/Submit/Check/Deps.pm +++ b/lib/Youri/Submit/Check/Deps.pm @@ -45,10 +45,23 @@ sub resolvedep { } $notfound; } @requires; + # Try to handle BuildRequires: kernel-server-2.6.37-3.mga-1-1.mga1 + @requires = grep { + my $require = $_; + my $notfound = 1; + if (!$require->[Youri::Package::DEPENDENCY_RANGE] && + $require->[Youri::Package::DEPENDENCY_NAME] =~ /-/) { + foreach my $provide (@provides) { + next unless $require->[Youri::Package::DEPENDENCY_NAME] =~ /^$provide->[Youri::Package::DEPENDENCY_NAME]-/; + $notfound = 0; + } + } + $notfound; + } @requires; }; $media->traverse_headers($index); foreach my $require (@requires) { - push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME] . " " . $require->[Youri::Package::DEPENDENCY_RANGE]); + push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME] . " " . $require->[Youri::Package::DEPENDENCY_RANGE]); } return @errors; } -- cgit v1.2.1 From 106a77fcd243501b4f4eb435fa5453953df79dd1 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Tue, 8 Feb 2011 13:30:15 +0000 Subject: Revert, the package was actually wrong --- lib/Youri/Submit/Check/Deps.pm | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm index 463d29a..fa239df 100644 --- a/lib/Youri/Submit/Check/Deps.pm +++ b/lib/Youri/Submit/Check/Deps.pm @@ -45,23 +45,10 @@ sub resolvedep { } $notfound; } @requires; - # Try to handle BuildRequires: kernel-server-2.6.37-3.mga-1-1.mga1 - @requires = grep { - my $require = $_; - my $notfound = 1; - if (!$require->[Youri::Package::DEPENDENCY_RANGE] && - $require->[Youri::Package::DEPENDENCY_NAME] =~ /-/) { - foreach my $provide (@provides) { - next unless $require->[Youri::Package::DEPENDENCY_NAME] =~ /^$provide->[Youri::Package::DEPENDENCY_NAME]-/; - $notfound = 0; - } - } - $notfound; - } @requires; }; $media->traverse_headers($index); foreach my $require (@requires) { - push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME] . " " . $require->[Youri::Package::DEPENDENCY_RANGE]); + push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME]); } return @errors; } -- cgit v1.2.1 From 71ae16047f87cfa6b065f5e1a7c72b3f8bfd7e23 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Mon, 14 Feb 2011 20:42:47 +0000 Subject: Add a mirror action --- lib/Youri/Submit/Post/Mirror.pm | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 lib/Youri/Submit/Post/Mirror.pm diff --git a/lib/Youri/Submit/Post/Mirror.pm b/lib/Youri/Submit/Post/Mirror.pm new file mode 100644 index 0000000..387fe90 --- /dev/null +++ b/lib/Youri/Submit/Post/Mirror.pm @@ -0,0 +1,55 @@ +# $Id: Gendistrib.pm 115367 2007-01-30 09:47:04Z pixel $ +package Youri::Submit::Post::Mirror; + +=head1 NAME + +Youri::Submit::Post::Mirror - synchronizes repository to mirror + +=head1 DESCRIPTION + +Calls genhdlist2 + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Post/; + +sub _init { + my $self = shift; + my %options = ( + destination => '', + @_ + ); + + foreach my $var ('destination') { + $self->{"_$var"} = $options{$var}; + } +} + +sub run { + my ($self, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + my $root = $repository->get_install_root(); + + croak "Missing destination" unless $self->{'_destination'}; + + + if (system("rsync -alH $root/$target/ $self->{_destination}/$target/")) { + $self->{_error} = "Rsync command failed ($!)"; + } + + return; +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2010, Mageia + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=cut + +1; + -- cgit v1.2.1 From bd429c24a4e5d9a5011813c7d3015f8cdcc392d6 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Mon, 14 Feb 2011 22:49:17 +0000 Subject: Delete old rpms --- lib/Youri/Submit/Post/Mirror.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Youri/Submit/Post/Mirror.pm b/lib/Youri/Submit/Post/Mirror.pm index 387fe90..961cc1e 100644 --- a/lib/Youri/Submit/Post/Mirror.pm +++ b/lib/Youri/Submit/Post/Mirror.pm @@ -36,7 +36,7 @@ sub run { croak "Missing destination" unless $self->{'_destination'}; - if (system("rsync -alH $root/$target/ $self->{_destination}/$target/")) { + if (system("rsync -alH --delete $root/$target/ $self->{_destination}/$target/")) { $self->{_error} = "Rsync command failed ($!)"; } -- cgit v1.2.1 From 9be47f7f05f307e346fd549f219f1db21610d067 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Sun, 20 Feb 2011 20:49:53 +0000 Subject: Display full dependency --- lib/Youri/Submit/Check/Deps.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm index fa239df..69cd1f9 100644 --- a/lib/Youri/Submit/Check/Deps.pm +++ b/lib/Youri/Submit/Check/Deps.pm @@ -48,7 +48,7 @@ sub resolvedep { }; $media->traverse_headers($index); foreach my $require (@requires) { - push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME]); + push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME] . " " . $require->[Youri::Package::DEPENDENCY_RANGE]); } return @errors; } -- cgit v1.2.1 From e76d2721b2f2a42c4dd03f592ff3c0669e2cfdc7 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Sun, 20 Feb 2011 20:50:18 +0000 Subject: Only check deps for packages buildable on x86_64 --- lib/Youri/Submit/Check/Deps.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm index 69cd1f9..3d5d235 100644 --- a/lib/Youri/Submit/Check/Deps.pm +++ b/lib/Youri/Submit/Check/Deps.pm @@ -68,7 +68,10 @@ sub run { # FIXME we need dependencies on all archs except for ExclusiveArch # Unfortunately some dependencies depend on the arch were the src.rpm was geenrated # Currently src.rpm is generated on x86_64, so we need to check on that one + # If the package is not buildable on x86_64 we just don't test anything my $arch = 'x86_64'; + my @exclusivearchs = $package->get_tag("exclusivearchs"); + return if @exclusivearchs && ! (grep {$_ eq $arch} @exclusivearchs); # foreach my $arch ($repository->get_extra_arches()) { my $media = new Youri::Media::URPM(name => "core.".$arch, type => "binary", -- cgit v1.2.1 From 5e724f8dedbe5e956ebe3eab9be9517ada3bb08f Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Sat, 26 Feb 2011 23:18:54 +0000 Subject: Drop some MDV specific debugging code --- lib/Youri/Submit/Action/Archive.pm | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/Youri/Submit/Action/Archive.pm b/lib/Youri/Submit/Action/Archive.pm index 98ff37c..41a8b8f 100644 --- a/lib/Youri/Submit/Action/Archive.pm +++ b/lib/Youri/Submit/Action/Archive.pm @@ -46,17 +46,6 @@ sub run { ) { my $file = $replaced_package->get_file(); - # trap for debugging bug 34999 - if ($file =~ /\/[\d.]+\/(main\/updates|.*\/release)/) { - my $bugmsg = "BUG#34999 WARNING: trying to remove from a release: $file\n"; - open(BUG34999LOG, '>>', "/home/mandrake/bug34999.log"); - print $bugmsg; - print BUG34999LOG localtime().": ".$bugmsg; - close BUG34999LOG; - - next; - } - my ($rep_section, $rep_main_section) = $file =~ m,$path/(([^/]+)/.*)/[^/]+.rpm,; # We do accept duplicate version for other submedia of the same main media section print "(path '$path') file '$file' section '$rep_section' main_section '$rep_main_section'\n" if $self->{_verbose}; -- cgit v1.2.1 From 7f23105fffc1c5f0149ff44b6560d089dfaa47ea Mon Sep 17 00:00:00 2001 From: Romain d'Alverny Date: Thu, 24 Mar 2011 16:25:37 +0000 Subject: Add action to notify maintainers database of a package upload --- lib/Youri/Submit/Action/UpdateMaintDb.pm | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 lib/Youri/Submit/Action/UpdateMaintDb.pm diff --git a/lib/Youri/Submit/Action/UpdateMaintDb.pm b/lib/Youri/Submit/Action/UpdateMaintDb.pm new file mode 100644 index 0000000..3af27f6 --- /dev/null +++ b/lib/Youri/Submit/Action/UpdateMaintDb.pm @@ -0,0 +1,81 @@ +# $Id$ +package Youri::Submit::Action::UpdateMaintDb; + +=head1 NAME + +Youri::Submit::Action::UpdateMaintDb - Mageia maintainers database updater + +=head1 DESCRIPTION + +This action plugin HTTP POSTs to package maintainers database to notify +of the action. See . + +=cut + +use warnings; +use strict; +use Carp; +use base qw/Youri::Submit::Action/; + +use HTTP::Request::Common qw(POST); +use LWP::UserAgent; + +sub _init { + my $self = shift; + my %options = ( + maintdb_url => '', + maintdb_key => '', + @_ + ); + + $self->{_maintdb_url} = $options{maintdb_url}; + $self->{_maintdb_key} = $options{maintdb_key}; + + return $self; +} + +sub run { + my ($self, $package, $repository, $target, $define) = @_; + croak "Not a class method" unless ref $self; + + # only SRPMs matter + return unless $package->is_source(); + + unless ($self->{_test}) { + my $pkg_name = $package->get_name(); + my $pkg_media = $repository->_get_main_section($package, $target, $define); + $package->get_packager() =~ m/(\w[-_.\w]+\@[-_.\w]+)\W/; + my $pkg_commiter = $1; + + $ua = LWP::UserAgent->new; + $ua->agent('Youri/0.1 ' . $ua->agent); + + my $req = POST $self->{_maintdb_url}, + [ + key => $self->{_maintdb_key}, + from => "youri", + package => $pkg_name, + media => $pkg_media, + uid => $pkg_commiter + ]; + + my $res = $ua->request($req); + + if ($res->is_success) { + print "Updated package maintainers DB for '$pkg_name', '$pkg_media', '$pkg_commiter'.\n" if $self->{_verbose}; + } else { + print "ERROR: POST failed to ".$self->{_maintdb_url}." for '$pkg_name', '$pkg_media', '$pkg_commiter'.\n"; + } + } +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2007, Mandriva +Copyright (C) 2011, Mageia.Org + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=cut + +1; -- cgit v1.2.1 From 11bc968a2b89d5b0d147c2948123a0c9cc0e5b68 Mon Sep 17 00:00:00 2001 From: Nicolas Vigier Date: Thu, 24 Mar 2011 17:36:02 +0000 Subject: fix syntax --- lib/Youri/Submit/Action/UpdateMaintDb.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Youri/Submit/Action/UpdateMaintDb.pm b/lib/Youri/Submit/Action/UpdateMaintDb.pm index 3af27f6..e9fe49a 100644 --- a/lib/Youri/Submit/Action/UpdateMaintDb.pm +++ b/lib/Youri/Submit/Action/UpdateMaintDb.pm @@ -47,7 +47,7 @@ sub run { $package->get_packager() =~ m/(\w[-_.\w]+\@[-_.\w]+)\W/; my $pkg_commiter = $1; - $ua = LWP::UserAgent->new; + my $ua = LWP::UserAgent->new; $ua->agent('Youri/0.1 ' . $ua->agent); my $req = POST $self->{_maintdb_url}, -- cgit v1.2.1 From 3264befbb510b7ba72e516c404ad54d6361c2973 Mon Sep 17 00:00:00 2001 From: Nicolas Vigier Date: Thu, 24 Mar 2011 18:40:42 +0000 Subject: fix username of submitter (thanks to pterjan) --- lib/Youri/Submit/Action/UpdateMaintDb.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Youri/Submit/Action/UpdateMaintDb.pm b/lib/Youri/Submit/Action/UpdateMaintDb.pm index e9fe49a..10eed21 100644 --- a/lib/Youri/Submit/Action/UpdateMaintDb.pm +++ b/lib/Youri/Submit/Action/UpdateMaintDb.pm @@ -44,8 +44,7 @@ sub run { unless ($self->{_test}) { my $pkg_name = $package->get_name(); my $pkg_media = $repository->_get_main_section($package, $target, $define); - $package->get_packager() =~ m/(\w[-_.\w]+\@[-_.\w]+)\W/; - my $pkg_commiter = $1; + my $pkg_commiter = $define->{user}; my $ua = LWP::UserAgent->new; $ua->agent('Youri/0.1 ' . $ua->agent); -- cgit v1.2.1 From ed6a9183e6c78942dc11377c15366323ac08714f Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Thu, 24 Mar 2011 23:20:57 +0000 Subject: Port to new Youri API --- lib/Youri/Submit/Check/Deps.pm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Youri/Submit/Check/Deps.pm b/lib/Youri/Submit/Check/Deps.pm index 3d5d235..0adcf37 100644 --- a/lib/Youri/Submit/Check/Deps.pm +++ b/lib/Youri/Submit/Check/Deps.pm @@ -29,16 +29,16 @@ sub resolvedep { my $require = $_; my $notfound = 1; foreach my $provide (@provides) { - next unless $provide->[Youri::Package::DEPENDENCY_NAME] eq $require->[Youri::Package::DEPENDENCY_NAME]; - if ($require->[Youri::Package::DEPENDENCY_RANGE]) { - next unless $package->check_ranges_compatibility($provide->[Youri::Package::DEPENDENCY_RANGE], $require->[Youri::Package::DEPENDENCY_RANGE]); + next unless $provide->[Youri::Package::Relationship::NAME] eq $require->[Youri::Package::Relationship::NAME]; + if ($require->[Youri::Package::Relationship::RANGE]) { + next unless $package->check_ranges_compatibility($provide->[Youri::Package::Relationship::RANGE], $require->[Youri::Package::Relationship::RANGE]); } $notfound = 0; } - if ($notfound && $require->[Youri::Package::DEPENDENCY_NAME] =~ m|/|) { + if ($notfound && $require->[Youri::Package::Relationship::NAME] =~ m|/|) { foreach my $file ($package->get_files()) { - next unless $file eq $require->[Youri::Package::DEPENDENCY_NAME]; + next unless $file eq $require->[Youri::Package::Relationship::NAME]; $notfound = 0; last; } @@ -48,7 +48,7 @@ sub resolvedep { }; $media->traverse_headers($index); foreach my $require (@requires) { - push (@errors, "Unresolved dep on " . $require->[Youri::Package::DEPENDENCY_NAME] . " " . $require->[Youri::Package::DEPENDENCY_RANGE]); + push (@errors, "Unresolved dep on " . $require->[Youri::Package::Relationship::NAME] . " " . $require->[Youri::Package::Relationship::RANGE]); } return @errors; } -- cgit v1.2.1 From 329303a9e34dcc3b9d44902b712821b738edc48d Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Fri, 25 Mar 2011 10:33:42 +0000 Subject: Fix changelog mail content for new youri --- lib/Youri/Submit/Action/Mail.pm | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/Youri/Submit/Action/Mail.pm b/lib/Youri/Submit/Action/Mail.pm index c9bbcbe..02e36cd 100644 --- a/lib/Youri/Submit/Action/Mail.pm +++ b/lib/Youri/Submit/Action/Mail.pm @@ -110,13 +110,24 @@ sub get_content { my ($self, $package, $repository, $target, $define) = @_; croak "Not a class method" unless ref $self; - my $information = $package->get_information(); + my $information = $package->as_formated_string(<get_last_change(); return $information . "\n" . - $last_change->[Youri::Package::CHANGE_AUTHOR] . ":\n" . - $last_change->[Youri::Package::CHANGE_TEXT]; + $last_change->get_author() . ":\n" . + $last_change->get_raw_text(); } -- cgit v1.2.1 From 51d5d4e7a0d1d1cca9a5214782575b5f8aa7aa8b Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Mon, 28 Mar 2011 11:23:58 +0000 Subject: fix clean-rpmsrate to use core/release --- lib/Youri/Submit/Post/CleanRpmsrate.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Youri/Submit/Post/CleanRpmsrate.pm b/lib/Youri/Submit/Post/CleanRpmsrate.pm index 977e2a0..899c80f 100644 --- a/lib/Youri/Submit/Post/CleanRpmsrate.pm +++ b/lib/Youri/Submit/Post/CleanRpmsrate.pm @@ -33,7 +33,8 @@ sub run { } foreach my $arch (@changed) { my $rpmsrate = "$root/$target/$arch/media/media_info/rpmsrate"; - my @media = "$root/$target/$arch/media/main/release"; + # FIXME: have a method to get core/release instead of hardcoding it + my @media = "$root/$target/$arch/media/core/release"; system("cp", "$rpmsrate-raw", "$rpmsrate-new"); system("clean-rpmsrate", "$rpmsrate-new", @media); system("mv", "-f", "$rpmsrate-new", $rpmsrate); -- cgit v1.2.1