summaryrefslogtreecommitdiffstats
path: root/zarb-ml/mageia-sysadm/2011-January/001513.html
diff options
context:
space:
mode:
Diffstat (limited to 'zarb-ml/mageia-sysadm/2011-January/001513.html')
-rw-r--r--zarb-ml/mageia-sysadm/2011-January/001513.html11447
1 files changed, 11447 insertions, 0 deletions
diff --git a/zarb-ml/mageia-sysadm/2011-January/001513.html b/zarb-ml/mageia-sysadm/2011-January/001513.html
new file mode 100644
index 000000000..46a37a5b0
--- /dev/null
+++ b/zarb-ml/mageia-sysadm/2011-January/001513.html
@@ -0,0 +1,11447 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+ <HEAD>
+ <TITLE> [Mageia-sysadm] [210] add mandriva version of youri-core, downloaded from http://svn. mandriva.com/svn/soft/build_system/youri/core/trunk/ at revision 271600
+ </TITLE>
+ <LINK REL="Index" HREF="index.html" >
+ <LINK REL="made" HREF="mailto:mageia-sysadm%40mageia.org?Subject=Re%3A%20%5BMageia-sysadm%5D%20%5B210%5D%20add%20mandriva%20version%20of%20youri-core%2C%0A%20downloaded%20from%20http%3A//svn.%0A%20mandriva.com/svn/soft/build_system/youri/core/trunk/%20at%20revision%20271600&In-Reply-To=%3C20110105132345.9727D41942%40valstar.mageia.org%3E">
+ <META NAME="robots" CONTENT="index,nofollow">
+ <META http-equiv="Content-Type" content="text/html; charset=us-ascii">
+ <LINK REL="Previous" HREF="001512.html">
+ <LINK REL="Next" HREF="001514.html">
+ </HEAD>
+ <BODY BGCOLOR="#ffffff">
+ <H1>[Mageia-sysadm] [210] add mandriva version of youri-core, downloaded from http://svn. mandriva.com/svn/soft/build_system/youri/core/trunk/ at revision 271600</H1>
+ <B>root at mageia.org</B>
+ <A HREF="mailto:mageia-sysadm%40mageia.org?Subject=Re%3A%20%5BMageia-sysadm%5D%20%5B210%5D%20add%20mandriva%20version%20of%20youri-core%2C%0A%20downloaded%20from%20http%3A//svn.%0A%20mandriva.com/svn/soft/build_system/youri/core/trunk/%20at%20revision%20271600&In-Reply-To=%3C20110105132345.9727D41942%40valstar.mageia.org%3E"
+ TITLE="[Mageia-sysadm] [210] add mandriva version of youri-core, downloaded from http://svn. mandriva.com/svn/soft/build_system/youri/core/trunk/ at revision 271600">root at mageia.org
+ </A><BR>
+ <I>Wed Jan 5 14:23:45 CET 2011</I>
+ <P><UL>
+ <LI>Previous message: <A HREF="001512.html">[Mageia-sysadm] [209] add mandriva version of youri-submit, downloaded from http://svn. mandriva.com/svn/soft/build_system/youri/submit/trunk at revision 271600
+</A></li>
+ <LI>Next message: <A HREF="001514.html">[Mageia-sysadm] [654] Add ssh key for pterjan.
+</A></li>
+ <LI> <B>Messages sorted by:</B>
+ <a href="date.html#1513">[ date ]</a>
+ <a href="thread.html#1513">[ thread ]</a>
+ <a href="subject.html#1513">[ subject ]</a>
+ <a href="author.html#1513">[ author ]</a>
+ </LI>
+ </UL>
+ <HR>
+<!--beginarticle-->
+<PRE>Revision: 210
+Author: boklm
+Date: 2011-01-05 14:23:45 +0100 (Wed, 05 Jan 2011)
+Log Message:
+-----------
+add mandriva version of youri-core, downloaded from <A HREF="http://svn.mandriva.com/svn/soft/build_system/youri/core/trunk/">http://svn.mandriva.com/svn/soft/build_system/youri/core/trunk/</A> at revision 271600
+
+Added Paths:
+-----------
+ build_system/mdv-youri-core/
+ build_system/mdv-youri-core/branches/
+ build_system/mdv-youri-core/tags/
+ build_system/mdv-youri-core/trunk/
+ build_system/mdv-youri-core/trunk/ChangeLog
+ build_system/mdv-youri-core/trunk/MANIFEST.SKIP
+ build_system/mdv-youri-core/trunk/Makefile.PL
+ build_system/mdv-youri-core/trunk/README
+ build_system/mdv-youri-core/trunk/TODO
+ build_system/mdv-youri-core/trunk/bin/
+ build_system/mdv-youri-core/trunk/bin/fillbugzilla
+ build_system/mdv-youri-core/trunk/cgi/
+ build_system/mdv-youri-core/trunk/cgi/maintainers.cgi
+ build_system/mdv-youri-core/trunk/etc/
+ build_system/mdv-youri-core/trunk/etc/bash_completion.d/
+ build_system/mdv-youri-core/trunk/etc/bash_completion.d/youri
+ build_system/mdv-youri-core/trunk/etc/check.conf
+ build_system/mdv-youri-core/trunk/etc/upload.conf
+ build_system/mdv-youri-core/trunk/lib/
+ build_system/mdv-youri-core/trunk/lib/Youri/
+ build_system/mdv-youri-core/trunk/lib/Youri/Bugzilla.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Age.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/Iurt.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/LBD.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Conflicts.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Dependencies.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/MandrivaConflicts.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Missing.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Orphans.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Rpmlint.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Signature.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/CPAN.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Debian.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Fedora.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Freshmeat.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/GNOME.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Gentoo.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/NetBSD.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/RAA.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Sourceforge.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences/File.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/Bugzilla.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/CGI.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/HTML.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/RSS.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/Text.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/HTML.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/Text.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/DBI.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/Iterator.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Config.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Media/
+ build_system/mdv-youri-core/trunk/lib/Youri/Media/URPM.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Media.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Package/
+ build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM4.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Package/Test.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Package/URPM.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Package.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Repository/
+ build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload_pre.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Repository/PLF.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Repository.pm
+ build_system/mdv-youri-core/trunk/lib/Youri/Utils.pm
+ build_system/mdv-youri-core/trunk/t/
+ build_system/mdv-youri-core/trunk/t/00distribution.t
+ build_system/mdv-youri-core/trunk/t/cowsay-3.03-11mdv2007.0.noarch.rpm
+ build_system/mdv-youri-core/trunk/t/gpghome/
+ build_system/mdv-youri-core/trunk/t/gpghome/pubring.gpg
+ build_system/mdv-youri-core/trunk/t/gpghome/secring.gpg
+ build_system/mdv-youri-core/trunk/t/gpghome/trustdb.gpg
+ build_system/mdv-youri-core/trunk/t/package.t
+ build_system/mdv-youri-core/trunk/t/version.t
+
+Added: build_system/mdv-youri-core/trunk/ChangeLog
+===================================================================
+--- build_system/mdv-youri-core/trunk/ChangeLog (rev 0)
++++ build_system/mdv-youri-core/trunk/ChangeLog 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,2 @@
++2006-04-23 Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at zarb.org</A>&gt; 0.9
++ * initial release
+
+Added: build_system/mdv-youri-core/trunk/MANIFEST.SKIP
+===================================================================
+--- build_system/mdv-youri-core/trunk/MANIFEST.SKIP (rev 0)
++++ build_system/mdv-youri-core/trunk/MANIFEST.SKIP 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,14 @@
++CVS/.*
++\.svn/.*
++^cover_db/
++^blib/
++\.bak$
++\.swp$
++\.tar$
++\.tgz$
++\.tar\.gz$
++\.SKIP$
++~$
++^pm_to_blib$
++^Makefile$
++^Makefile\.old$
+
+Added: build_system/mdv-youri-core/trunk/Makefile.PL
+===================================================================
+--- build_system/mdv-youri-core/trunk/Makefile.PL (rev 0)
++++ build_system/mdv-youri-core/trunk/Makefile.PL 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,31 @@
++# $Id: Makefile.PL 1724 2006-10-17 13:55:27Z warly $
++use ExtUtils::MakeMaker;
++
++WriteMakefile(
++ NAME =&gt; 'youri-core',
++ VERSION =&gt; 0.9,
++ AUTHOR =&gt; 'Youri project &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">youri at zarb.org</A>&gt;',
++ PREREQ_PM =&gt; {
++ 'AppConfig' =&gt; 0,
++ 'YAML' =&gt; 0,
++ 'Pod::Simple::HTMLBatch' =&gt; 0,
++ 'Test::Exception' =&gt; 0,
++ 'Exception' =&gt; 0,
++ 'RPM4' =&gt; 0,
++ 'URPM' =&gt; 0
++ }
++);
++
++package MY;
++
++sub top_targets {
++ my ($self) = @_;
++ my $top_targets = $self-&gt;SUPER::top_targets(@_);
++ $top_targets =~ s/all :: pure_all manifypods/all :: pure_all manifypods htmlifypods/;
++ $top_targets .= &lt;&lt;'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
++EOF
++ return $top_targets;
++}
+
+Added: build_system/mdv-youri-core/trunk/README
+===================================================================
+--- build_system/mdv-youri-core/trunk/README (rev 0)
++++ build_system/mdv-youri-core/trunk/README 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,33 @@
++youri-core
++----------
++
++Youri core libraries.
++
++Description
++-----------
++YOURI stands for &quot;Youri Offers an Upload &amp; Repository Infrastucture&quot;. It aims
++to build tools making management of a coherent set of packages easier.
++
++This package provides basic components used by other youri programs.
++
++Installation
++------------
++To install, just use:
++perl Makefile.PL
++make
++make test
++
++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 &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at zarb.org</A>&gt;,
++Pascal Terjan &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">pterjan at zarb.org</A>&gt;
++Damien Krotkine &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dams at zarb.org</A>&gt;
++Olivier Thauvin &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">nanardon at zarb.org</A>&gt;
++Ville Skytt\xE4 &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">ville.skytta at iki.fi</A>&gt;
+
+Added: build_system/mdv-youri-core/trunk/TODO
+===================================================================
+--- build_system/mdv-youri-core/trunk/TODO (rev 0)
++++ build_system/mdv-youri-core/trunk/TODO 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,7 @@
++1.0 Goals
++=========
++
++library:
++- API-based bugzilla interface, instead of SQL-based one
++- more generic check-specific options handling in medias (don't use a
++specific attribute for each of them)
+
+Added: build_system/mdv-youri-core/trunk/bin/fillbugzilla
+===================================================================
+--- build_system/mdv-youri-core/trunk/bin/fillbugzilla (rev 0)
++++ build_system/mdv-youri-core/trunk/bin/fillbugzilla 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,81 @@
++#!/usr/bin/perl
++# fillbugzilla
++# copyright (c) 2002 Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at zarb.org</A>&gt;
++# $Id: fillbugzilla 1179 2006-08-05 08:30:57Z warly $
++
++use strict;
++use warnings;
++use Getopt::Long;
++use Bugzilla;
++use Mail::Sendmail;
++
++# constants
++my $name = &quot;fillbugzilla&quot;;
++my $version = &quot;1.0&quot;;
++
++# command-line parameters
++my ($base, $user, $pass, $project, $mode, $help);
++GetOptions(
++ &quot;base=s&quot; =&gt; \$base,
++ &quot;user=s&quot; =&gt; \$user,
++ &quot;pass=s&quot; =&gt; \$pass,
++ &quot;mode=s&quot; =&gt; \$mode,
++ &quot;help&quot; =&gt; \$help,
++);
++
++# mandatory argument
++die usage() unless ($base &amp;&amp; $user &amp;&amp; $pass);
++die usage() unless ($mode eq 'package' || $mode eq 'packager');
++
++usage() &amp;&amp; exit 0 if $help;
++
++my $bugzilla = Bugzilla-&gt;new('localhost', $base, $user, $pass);
++
++if ($mode eq 'packager') {
++ while (my $packager = &lt;&gt;) {
++ chomp $packager;
++ my ($name, $login) = split(/\t/, $packager);
++
++ # random passwd
++ my @chars = (0..9, 'A'..'Z', 'a'..'z', '-', '_', '!', '@', '#', '$', '%', '^', '&amp;', '*');
++ my $password = join('', map { $chars[rand(scalar @chars)] } 1 .. 8);
++
++ # insert into database
++ $bugzilla-&gt;add_packager($name, $login, $password);
++
++ # mail user
++ my %mail = (
++ smtp =&gt; 'localhost',
++ To =&gt; $login,
++ From =&gt; '<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">bugmaster at zarb.org</A>',
++ Subject =&gt; 'bugzilla password',
++ 'X-Mailer' =&gt; &quot;$name $version&quot;,
++ );
++ $mail{Message} .= &quot;login: $login\n&quot;;
++ $mail{Message} .= &quot;password: $password\n&quot;;
++ sendmail(%mail) or warn $Mail::Sendmail::error;
++ }
++}
++
++if ($mode eq 'package') {
++ while (my $line = &lt;&gt;) {
++ chomp $line;
++ my ($name, $summary, $version, $maintainer) = split(/\t/, $line);
++ $bugzilla-&gt;add_package($name, $summary, $version, $maintainer);
++ }
++}
++
++sub usage {
++ print &lt;&lt;EOF;
++$name $version
++
++Usage:
++$name --base &lt;base&gt; --user &lt;user&gt; --pass &lt;pass&gt; --mode &lt;mode&gt; &lt; $file
++
++Options:
++--base &lt;base&gt; bugzilla base name
++--user &lt;user&gt; bugzilla base user
++--pass &lt;pass&gt; bugzilla base password
++--mode &lt;mode&gt; package or packager
++EOF
++}
+
+
+Property changes on: build_system/mdv-youri-core/trunk/bin/fillbugzilla
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: build_system/mdv-youri-core/trunk/cgi/maintainers.cgi
+===================================================================
+--- build_system/mdv-youri-core/trunk/cgi/maintainers.cgi (rev 0)
++++ build_system/mdv-youri-core/trunk/cgi/maintainers.cgi 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,65 @@
++#!/usr/bin/perl
++# $Id: maintainers.cgi 1179 2006-08-05 08:30:57Z warly $
++
++=head1 NAME
++
++maintainers.cgi - youri CGI interface to maintainers list
++
++=head1 VERSION
++
++Version 1.0
++
++=head1 DESCRIPTION
++
++This script allows to get package maintainers list through CGI interface.
++
++=head1 SYNOPSIS
++
++=head1 COPYRIGHT AND LICENSE
++
++Copyright (C) 2004-2005, YOURI project
++
++This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
++
++=head1 AUTHORS
++
++Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at zarb.org</A>&gt;,
++
++=cut
++
++use Youri::Bugzilla;
++use CGI;
++use AppConfig qw/:argcount :expand/;
++use strict;
++use warnings;
++
++my $config = AppConfig-&gt;new(
++ {
++ GLOBAL =&gt; {
++ DEFAULT =&gt; undef,
++ EXPAND =&gt; EXPAND_ALL,
++ ARGCOUNT =&gt; ARGCOUNT_ONE,
++ }
++ },
++ host =&gt; { ARGCOUNT =&gt; ARGCOUNT_ONE },
++ base =&gt; { ARGCOUNT =&gt; ARGCOUNT_ONE },
++ user =&gt; { ARGCOUNT =&gt; ARGCOUNT_ONE },
++ pass =&gt; { ARGCOUNT =&gt; ARGCOUNT_ONE },
++);
++
++my $home = (getpwnam($ENV{PROJECT}))[7];
++foreach my $file (&quot;/etc/youri/maintainers.conf&quot;, &quot;$home/.youri/maintainers.conf&quot;) {
++ $config-&gt;file($file) if -f $file &amp;&amp; -r $file;
++}
++
++my $bugzilla = Bugzilla-&gt;new(
++ $config-&gt;host(),
++ $config-&gt;base(),
++ $config-&gt;user(),
++ $config-&gt;pass(),
++);
++
++my $cgi = CGI-&gt;new();
++print $cgi-&gt;header(-type=&gt;'text/plain');
++
++$bugzilla-&gt;browse_packages(sub { print &quot;$_[0]\t$_[2]\n&quot;; });
+
+
+Property changes on: build_system/mdv-youri-core/trunk/cgi/maintainers.cgi
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: build_system/mdv-youri-core/trunk/etc/bash_completion.d/youri
+===================================================================
+--- build_system/mdv-youri-core/trunk/etc/bash_completion.d/youri (rev 0)
++++ build_system/mdv-youri-core/trunk/etc/bash_completion.d/youri 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,141 @@
++# youri tools completion
++# $Id$
++
++_youri-check()
++{
++
++ local cur prev config i mode
++
++ COMPREPLY=()
++ cur=${COMP_WORDS[COMP_CWORD]}
++ prev=${COMP_WORDS[COMP_CWORD-1]}
++
++ case &quot;$prev&quot; in
++ --config)
++ _filedir
++ return 0
++ ;;
++ --skip-plugin)
++ _find_config check.conf
++ if [ -n &quot;$config&quot; ]; then
++ # try to guess mode
++ for (( i=1; i &lt; COMP_CWORD; i++ )); do
++ if [[ &quot;${COMP_WORDS[i]}&quot; != -* ]]; then
++ mode=${COMP_WORDS[i]}
++ break
++ fi
++ done
++
++ if [ -n $mode ]; then
++ COMPREPLY=( $( awk -F= '/^'$mode's/ {print $2}' $config \
++ | grep &quot;^$cur&quot; ) )
++ fi
++ fi
++ return 0
++ ;;
++ --skip-media)
++ _find_config check.conf
++ if [ -n &quot;$config&quot; ]; then
++ COMPREPLY=( $( awk -F= '/^medias/ {print $2}' $config \
++ | grep &quot;^$cur&quot; ) )
++ fi
++ return 0
++ ;;
++ esac
++
++ if [[ &quot;$cur&quot; == -* ]]; then
++ COMPREPLY=( $( compgen -W '--config --skip-plugin --skip-media -h \
++ --help -t --test -v --verbose' -- $cur ) )
++ else
++ _count_args
++ case $args in
++ 1)
++ COMPREPLY=( $( compgen -W 'input output' -- $cur ) )
++ ;;
++ esac
++ fi
++
++}
++complete -F _youri-check youri-check
++
++_youri-upload()
++{
++
++ local cur prev config
++
++ COMPREPLY=()
++ cur=${COMP_WORDS[COMP_CWORD]}
++ prev=${COMP_WORDS[COMP_CWORD-1]}
++
++ case &quot;$prev&quot; in
++ --config)
++ _filedir
++ return 0
++ ;;
++ --skip-check)
++ _find_config upload.conf
++ if [ -n &quot;$config&quot; ]; then
++ COMPREPLY=( $( awk -F= '/^checks/ {print $2}' $config \
++ | grep &quot;^$cur&quot; ) )
++ fi
++ return 0
++ ;;
++ --skip-action)
++ _find_config upload.conf
++ if [ -n &quot;$config&quot; ]; then
++ COMPREPLY=( $( awk -F= '/^actions/ {print $2}' $config \
++ | grep &quot;^$cur&quot; ) )
++ fi
++ return 0
++ ;;
++ esac
++
++ if [[ &quot;$cur&quot; == -* ]]; then
++ COMPREPLY=( $( compgen -W '--config --skip-check --skip-action \
++ --define -h --help -t --test -v --verbose' -- $cur ) )
++ else
++ _count_args
++ case $args in
++ 1)
++ _find_config upload.conf
++ if [ -n &quot;$config&quot; ]; then
++ COMPREPLY=( $( awk -F= '/^targets/ {print $2}' $config \
++ | grep &quot;^$cur&quot; ) )
++ fi
++ ;;
++ *)
++ _filedir
++ ;;
++ esac
++ fi
++
++}
++complete -F _youri-upload youri-upload
++
++_find_config()
++{
++ local name i
++
++ name=$1
++
++ for (( i=1; i &lt; COMP_CWORD; i++ )); do
++ if [[ &quot;${COMP_WORDS[i]}&quot; == --config ]]; then
++ config=${COMP_WORDS[i+1]}
++ break
++ fi
++ done
++ if [ -f &quot;$config&quot; ]; then
++ return 0
++ fi
++
++ if [ -f &quot;$HOME/.youri/$name&quot; ]; then
++ config=$HOME/.youri/$name
++ return 0
++ fi
++
++ if [ -f &quot;/etc/youri/$name&quot; ]; then
++ config=/etc/youri/$name
++ return 0
++ fi
++
++}
+
+Added: build_system/mdv-youri-core/trunk/etc/check.conf
+===================================================================
+--- build_system/mdv-youri-core/trunk/etc/check.conf (rev 0)
++++ build_system/mdv-youri-core/trunk/etc/check.conf 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,300 @@
++# youri-check sample configuration file
++# $Id: check.conf 1179 2006-08-05 08:30:57Z warly $
++
++# resolver declaration
++resolver = cgi
++
++# preferences declaration
++preferences = file_pref
++
++# resultset declaration
++resultset = dbi
++
++# input plugins declaration
++inputs = rpmlint \
++ age \
++ updates \
++ build \
++ conflicts \
++ dependencies \
++ missing \
++ orphans
++
++# output plugins declaration
++outputs = file mail
++
++# medias declaration
++medias = main.i586 \
++ main.x86_64 \
++ main.sources \
++ contrib.i586 \
++ contrib.x86_64 \
++ contrib.sources \
++ free \
++ non-free \
++ free.sources \
++ non-free.sources
++
++# helper variables
++mirror = <A HREF="ftp://ftp.free.fr/pub/Distributions_Linux/Mandrakelinux/devel/cooker">ftp://ftp.free.fr/pub/Distributions_Linux/Mandrakelinux/devel/cooker</A>
++mirror_i586 = $mirror/i586/media
++mirror_x86_64 = $mirror/x86_64/media
++
++# resolver definition
++[cgi]
++class = Youri::Check::Maintainer::Resolver::CGI
++url = <A HREF="http://plf.zarb.org/cgi-bin/maintainers.cgi">http://plf.zarb.org/cgi-bin/maintainers.cgi</A>
++
++# preferences definition
++[file_pref]
++class = Youri::Check::Maintainer::Preferences::File
++
++# resultset definition
++[dbi]
++class = Youri::Check::Resultset::DBI
++driver = mysql
++host = localhost
++base = plf_youri
++user = plf
++pass = s3kr3t
++
++# checks definitions
++[updates]
++class = Youri::Check::Input::Updates
++aliases = &lt;&lt;EOF
++--- #YAML:1.0
++libfame0.8: ~
++EOF
++sources = &lt;&lt;EOF
++--- #YAML:1.0
++debian:
++ class: Youri::Check::Input::Updates::Source::Debian
++ aliases:
++ fuse-emulator: ~
++cpan:
++ class: Youri::Check::Input::Updates::Source::CPAN
++fedora:
++ class: Youri::Check::Input::Updates::Source::Fedora
++gentoo:
++ class: Youri::Check::Input::Updates::Source::Gentoo
++freshmeat:
++ class: Youri::Check::Input::Updates::Source::Freshmeat
++netbsd:
++ class: Youri::Check::Input::Updates::Source::NetBSD
++raa:
++ class: Youri::Check::Input::Updates::Source::RAA
++sourceforge:
++ class: Youri::Check::Input::Updates::Source::Sourceforge
++ aliases:
++ openquicktime: ~
++ klibido: ~
++EOF
++
++[rpmlint]
++class = Youri::Check::Input::Rpmlint
++
++[age]
++class = Youri::Check::Input::Age
++max_age = 12 months
++pattern = %m months
++
++[dependencies]
++class = Youri::Check::Input::Dependencies
++
++[conflicts]
++class = Youri::Check::Input::Conflicts
++
++[build]
++class = Youri::Check::Input::Build
++sources = &lt;&lt;EOF
++--- #YAML:1.0
++stefan:
++ class: Youri::Check::Input::Build::Source::LBD
++ url: <A HREF="http://eijk.homelinux.org/build/">http://eijk.homelinux.org/build/</A>
++ medias:
++ - cooker_plf-free
++ - cooker_plf-non-free
++ archs:
++ - i586
++EOF
++
++[missing]
++class = Youri::Check::Input::Missing
++
++[orphans]
++class = Youri::Check::Input::Orphans
++
++# reports definitions
++[file]
++class = Youri::Check::Output::File
++to = ${HOME}/www/qa
++global = 1
++individual = 1
++formats = &lt;&lt;EOF
++--- #YAML:1.0
++html:
++ class: Youri::Check::Output::File::Format::HTML
++text:
++ class: Youri::Check::Output::File::Format::Text
++rss:
++ class: Youri::Check::Output::File::Format::RSS
++EOF
++
++[mail]
++class = Youri::Check::Output::Mail
++mta = /usr/sbin/sendmail
++to = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf-admin at zarb.org</A>
++from = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf at zarb.org</A>
++reply_to = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf-admin at zarb.org</A>
++formats = &lt;&lt;EOF
++--- #YAML:1.0
++text:
++ class: Youri::Check::Output::Mail::Format::Text
++EOF
++
++# media definitions
++[main.i586]
++class = Youri::Media::URPM
++name = main
++type = binary
++path = $mirror_i586/main
++hdlist = $mirror_i586/media_info/hdlist_main.cz
++skip_inputs = &lt;&lt;EOF
++--- #YAML:1.0
++- all
++EOF
++
++[main.x86_64]
++class = Youri::Media::URPM
++name = main
++type = binary
++path = $mirror_x86_64/main
++hdlist = $mirror_x86_64/media_info/hdlist_main.cz
++skip_inputs = &lt;&lt;EOF
++--- #YAML:1.0
++- all
++EOF
++
++[main.sources]
++class = Youri::Media::URPM
++name = main
++type = source
++path = $mirror_i586/main
++hdlist = $mirror_i586/media_info/hdlist_main.src.cz
++skip_inputs = &lt;&lt;EOF
++--- #YAML:1.0
++- all
++EOF
++
++[contrib.i586]
++class = Youri::Media::URPM
++name = contrib
++type = binary
++path = $mirror_i586/contrib
++hdlist = $mirror_i586/media_info/hdlist_contrib.cz
++skip_inputs = &lt;&lt;EOF
++--- #YAML:1.0
++- all
++EOF
++
++[contrib.x86_64]
++class = Youri::Media::URPM
++name = contrib
++type = binary
++path = $mirror_x86_64/contrib
++hdlist = $mirror_x86_64/media_info/hdlist_contrib.cz
++skip_inputs = &lt;&lt;EOF
++--- #YAML:1.0
++- all
++EOF
++
++[contrib.sources]
++class = Youri::Media::URPM
++name = contrib
++type = source
++path = $mirror_i586/contrib
++hdlist = $mirror_i586/media_info/hdlist_contrib.src.cz
++skip_inputs = &lt;&lt;EOF
++--- #YAML:1.0
++- all
++EOF
++
++[free]
++class = Youri::Media::URPM
++name = free
++type = binary
++path = ${HOME}/ftp/mandrake/free/cooker/i586
++hdlist = ${HOME}/ftp/mandrake/free/cooker/i586/hdlist.cz
++rpmlint_config = ${HOME}/etc/rpmlint-free.conf
++allow_deps = &lt;&lt;EOF
++--- #YAML:1.0
++- main.i586
++- main.x86_64
++- contrib.i586
++- contrib.x86_64
++- free
++EOF
++allow_srcs = &lt;&lt;EOF
++--- #YAML:1.0
++- free.sources
++- main.sources
++- contrib.sources
++EOF
++skip_archs = &lt;&lt;EOF
++--- #YAML:1.0
++- ppc
++EOF
++
++[free.sources]
++class = Youri::Media::URPM
++name = free
++type = source
++path = ${HOME}/ftp/mandrake/free/src
++hdlist = ${HOME}/ftp/mandrake/free/src/hdlist.cz
++rpmlint_config = ${HOME}/etc/rpmlint-free.conf
++allow_deps = &lt;&lt;EOF
++--- #YAML:1.0
++- main.i586
++- contrib.i586
++- free
++EOF
++
++[non-free]
++class = Youri::Media::URPM
++name = non-free
++type = binary
++path = ${HOME}/ftp/mandrake/non-free/cooker/i586
++hdlist = ${HOME}/ftp/mandrake/non-free/cooker/i586/hdlist.cz
++rpmlint_config = ${HOME}/etc/rpmlint-non-free.conf
++allow_deps = &lt;&lt;EOF
++--- #YAML:1.0
++- main.i586
++- main.x86_64
++- contrib.i586
++- contrib.x86_64
++- free
++- non-free
++EOF
++allow_srcs = &lt;&lt;EOF
++--- #YAML:1.0
++- non-free.sources
++EOF
++skip_archs = &lt;&lt;EOF
++--- #YAML:1.0
++- ppc
++EOF
++
++[non-free.sources]
++class = Youri::Media::URPM
++name = non-free
++type = source
++path = ${HOME}/ftp/mandrake/non-free/src
++hdlist = ${HOME}/ftp/mandrake/non-free/src/hdlist.cz
++rpmlint_config = ${HOME}/etc/rpmlint-non-free.conf
++allow_deps = &lt;&lt;EOF
++--- #YAML:1.0
++- main.i586
++- contrib.i586
++- free
++- non-free
++EOF
+
+Added: build_system/mdv-youri-core/trunk/etc/upload.conf
+===================================================================
+--- build_system/mdv-youri-core/trunk/etc/upload.conf (rev 0)
++++ build_system/mdv-youri-core/trunk/etc/upload.conf 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,139 @@
++# youri-upload sample configuration file
++# $Id: upload.conf 1179 2006-08-05 08:30:57Z warly $
++
++# repository declaration
++repository = plf
++
++# targets declaration
++targets = cooker 2006.0
++
++# repository definition
++[plf]
++class = Youri::Repository::PLF
++install_root = ${HOME}/ftp/mandriva
++version_root = ${HOME}/cvs
++archive_root = ${HOME}/backup/mandriva
++noarch = i586
++
++# targets definition
++[cooker]
++checks = &lt;&lt;EOF
++--- #YAML:1.0
++- tag
++- recency
++- history
++EOF
++actions = &lt;&lt;EOF
++--- #YAML:1.0
++- sign
++- install
++- link
++- archive
++- clean
++- bugzilla
++- cvs
++- mail
++- rss
++EOF
++
++[2006.0]
++checks = &lt;&lt;EOF
++--- #YAML:1.0
++- type
++- tag
++- recency
++- history
++- precedence
++EOF
++actions = &lt;&lt;EOF
++--- #YAML:1.0
++- sign
++- install
++- link
++- archive
++- clean
++EOF
++
++# checks definition
++[tag]
++class = Youri::Upload::Check::Tag
++tags = &lt;&lt;EOF
++--- #YAML:1.0
++release: 'plf$'
++packager: '&lt;\<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">w+ at zarb</A>\.org&gt;$'
++distribution: '^Mandriva Linux$'
++vendor: '^Penguin Liberation Front$'
++EOF
++
++[recency]
++class = Youri::Upload::Check::Recency
++
++[history]
++class = Youri::Upload::Check::History
++
++[precedence]
++class = Youri::Upload::Check::Precedence
++target = cooker
++
++[type]
++class = Youri::Upload::Check::Type
++type = binary
++
++# actions definitions
++[sign]
++class = Youri::Upload::Action::Sign
++name = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf at zarb.org</A>
++path = ${HOME}/.gnupg
++passphrase = s3kr3t
++
++[install]
++class = Youri::Upload::Action::Install
++
++[link]
++class = Youri::Upload::Action::Link
++
++[archive]
++class = Youri::Upload::Action::Archive
++
++[clean]
++class = Youri::Upload::Action::Clean
++
++[mail]
++class = Youri::Upload::Action::Mail
++mta = /usr/sbin/sendmail
++to = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf-announce at zarb.org</A>
++reply_to = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf-discuss at zarb.org</A>
++from = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf at zarb.org</A>
++prefix = RPM
++cc = &lt;&lt;EOF
++--- #YAML:1.0
++hot-base: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">david at dindinx.org</A> <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">bellamy at neverland.net</A>
++dcgui: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">mathen at ketelhot.de</A>
++dclib: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">mathen at ketelhot.de</A>
++Video-DVDRip: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dvdrip-users at exit1.org</A>
++hackVideo-DVDRip: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">dvdrip-users at exit1.org</A>
++goosnes: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">tak at bard.sytes.net</A>
++avidemux: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">fixounet at free.fr</A>
++vobcopy: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">robos at muon.de</A>
++drip: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">drip-devel at lists.sourceforge.net</A>
++libdscaler: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">vektor at dumbterm.net</A>
++xawdecode: <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">pingus77 at ifrance.com</A>
++EOF
++
++[rss]
++class = Youri::Upload::Action::RSS
++file = ${HOME}/www/changelog.rss
++title = PLF packages updates
++link = <A HREF="http://plf.zarb.org/">http://plf.zarb.org/</A>
++description = ChangeLog for PLF packages
++
++[cvs]
++class = Youri::Upload::Action::CVS
++
++[bugzilla]
++class = Youri::Upload::Action::Bugzilla
++host = localhost
++base = plf_bugs
++user = plf
++pass = s3kr3t
++contact = <A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">plf at zarb.org</A>
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Bugzilla.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Bugzilla.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Bugzilla.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,482 @@
++# $Id: Bugzilla.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Bugzilla;
++
++=head1 NAME
++
++Youri::Bugzilla - Youri Bugzilla interface
++
++=head1 SYNOPSIS
++
++ use Youri::Bugzilla;
++
++ my $bugzilla = Youri::Bugzilla-&gt;new($host, $base, $user, $pass);
++
++ print $bugzilla-&gt;get_maintainer('foobar');
++
++=head1 DESCRIPTION
++
++This module implement a database-level Bugzilla interface for managing packages.
++
++The legacy Bugzilla database model is mapped this way:
++
++=over
++
++=item *
++
++a maintainer is a user
++
++=item *
++
++a package is a product
++
++=item *
++
++each package has two pseudo components &quot;program&quot; and &quot;package&quot;, owned by the package maintainer
++
++=back
++
++=cut
++
++use DBI;
++use Carp;
++use strict;
++use warnings;
++
++my %queries = (
++ get_package_id =&gt; 'SELECT id FROM products WHERE name = ?',
++ get_maintainer_id =&gt; 'SELECT userid FROM profiles WHERE login_name = ?',
++ get_versions =&gt; 'SELECT value FROM versions WHERE product_id = ?',
++ get_components =&gt; 'SELECT name FROM components WHERE product_id = ?',
++ add_package =&gt; 'INSERT INTO products (name, description) VALUES (?, ?)',
++ add_maintainer =&gt; 'INSERT INTO profiles (login_name, cryptpassword, realname, emailflags, refreshed_when) VALUES (?, ENCRYPT(?), ?, ?, SYSDATE())',
++ add_component =&gt; 'INSERT INTO components (product_id, name, description,initialowner, initialqacontact) VALUES (?, ?, ?, ?, ?)',
++ add_version =&gt; 'INSERT INTO versions (product_id, value) VALUES (?, ?)',
++ del_package =&gt; 'DELETE FROM products WHERE product = ?',
++ del_maintainer =&gt; 'DELETE FROM profiles WHERE login_name = ?',
++ del_components =&gt; 'DELETE FROM components WHERE program = ?',
++ del_versions =&gt; 'DELETE FROM versions WHERE program = ?',
++ reset_password =&gt; 'UPDATE profiles SET cryptpassword = ENCRYPT(?) WHERE login_name = ?',
++ browse_packages =&gt; &lt;&lt;EOF,
++SELECT products.name, max(versions.value), login_name
++FROM products, versions, profiles, components
++WHERE versions.product_id = products.id
++ AND components.product_id = products.id
++ AND profiles.userid = components.initialowner
++ AND components.name = 'package'
++GROUP BY name
++EOF
++ get_maintainer =&gt; &lt;&lt;EOF
++SELECT login_name
++FROM profiles, components, products
++WHERE profiles.userid = components.initialowner
++ AND components.name = 'package'
++ AND components.product_id = products.id
++ AND products.name = ?
++EOF
++);
++
++my @default_flags = qw/
++ ExcludeSelf
++ FlagRequestee
++ FlagRequester
++ emailOwnerRemoveme
++ emailOwnerComments
++ emailOwnerAttachments
++ emailOwnerStatus
++ emailOwnerResolved
++ emailOwnerKeywords
++ emailOwnerCC
++ emailOwnerOther
++ emailOwnerUnconfirmed
++ emailReporterRemoveme
++ emailReporterComments
++ emailReporterAttachments
++ emailReporterStatus
++ emailReporterResolved
++ emailReporterKeywords
++ emailReporterCC
++ emailReporterOther
++ emailReporterUnconfirmed
++ emailQAcontactRemoveme
++ emailQAcontactComments
++ emailQAcontactAttachments
++ emailQAcontactStatus
++ emailQAcontactResolved
++ emailQAcontactKeywords
++ emailQAcontactCC
++ emailQAcontactOther
++ emailQAcontactUnconfirmed
++ emailCClistRemoveme
++ emailCClistComments
++ emailCClistAttachments
++ emailCClistStatus
++ emailCClistResolved
++ emailCClistKeywords
++ emailCClistCC
++ emailCClistOther
++ emailCClistUnconfirmed
++ emailVoterRemoveme
++ emailVoterComments
++ emailVoterAttachments
++ emailVoterStatus
++ emailVoterResolved
++ emailVoterKeywords
++ emailVoterCC
++ emailVoterOther
++ emailVoterUnconfirmed
++/;
++
++my $default_flags = join('~', map { &quot;$_~on&quot; } @default_flags);
++
++=head1 CLASS METHODS
++
++Except stated otherwise, maintainers are specified by their login, and packages
++are specified by their name.
++
++=head2 new($host, $base, $user, $password)
++
++Creates a new L&lt;Youri::Bugzilla&gt; object, wrapping bugzilla database I&lt;$base&gt;
++hosted on I&lt;$host&gt;, and accessed by user I&lt;$user&gt; with password I&lt;$password&gt;.
++
++=cut
++
++sub new {
++ my ($class, $host, $base, $user, $pass) = @_;
++
++ my $dbh = DBI-&gt;connect(&quot;DBI:mysql:database=$base;host=$host&quot;, $user, $pass) or croak &quot;Unable to connect: $DBI::errstr&quot;;
++
++ my $self = bless {
++ _dbh =&gt; $dbh
++ }, $class;
++
++ return $self;
++}
++
++=head1 INSTANCE METHODS
++
++=head2 has_package($package)
++
++Return true if bugzilla contains given package.
++
++=cut
++
++sub has_package {
++ my ($self, $package) = @_;
++ return $self-&gt;_get_package_id($package);
++}
++
++=head2 has_maintainer($maintainer)
++
++Return true if bugzilla contains given maintainer.
++
++=cut
++
++sub has_maintainer {
++ my ($self, $maintainer) = @_;
++ return $self-&gt;_get_maintainer_id($maintainer);
++}
++
++=head2 get_maintainer($package)
++
++Return maintainer of given package.
++
++=cut
++
++sub get_maintainer {
++ my ($self, $package) = @_;
++ return $self-&gt;_get_single('get_maintainer', $package);
++}
++
++=head2 get_versions($package)
++
++Return versions from given package.
++
++=cut
++
++sub get_versions {
++ my ($self, $package) = @_;
++ return $self-&gt;_get_multiple(
++ 'get_versions',
++ $self-&gt;_get_package_id($package)
++ );
++}
++
++=head2 get_components($package)
++
++Return components from given package.
++
++=cut
++
++sub get_components {
++ my ($self, $package) = @_;
++ return $self-&gt;_get_multiple(
++ 'get_components',
++ $self-&gt;_get_package_id($package)
++ );
++}
++
++=head2 get_packages()
++
++Return all packages from the database.
++
++=cut
++
++sub get_packages {
++ my ($self) = @_;
++ return $self-&gt;_get_multiple('get_packages');
++}
++
++sub _get_package_id {
++ my ($self, $package) = @_;
++ return $self-&gt;_get_single('get_package_id', $package);
++}
++
++sub _get_maintainer_id {
++ my ($self, $maintainer) = @_;
++ return $self-&gt;_get_single('get_maintainer_id', $maintainer);
++}
++
++sub _get_single {
++ my ($self, $type, $value) = @_;
++ return unless ref $self;
++
++ my $query = $self-&gt;{_queries}-&gt;{$type};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{$type});
++ $self-&gt;{_queries}-&gt;{$type} = $query;
++ }
++
++ $query-&gt;execute($value);
++
++ my @row = $query-&gt;fetchrow_array();
++ return @row ? $row[0]: undef;
++}
++
++sub _get_multiple {
++ my ($self, $type, $value) = @_;
++ return unless ref $self;
++
++ my $query = $self-&gt;{_queries}-&gt;{$type};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{$type});
++ $self-&gt;{_queries}-&gt;{$type} = $query;
++ }
++
++ $query-&gt;execute($value);
++
++ my @results;
++ while (my @row = $query-&gt;fetchrow_array()) {
++ push @results, $row[0];
++ }
++ return @results;
++}
++
++=head2 add_package($name, $summary, $version, $maintainer, $contact)
++
++Adds a new package in the database, with given name, summary, version,
++maintainer and initial QA contact.
++
++=cut
++
++sub add_package {
++ my ($self, $name, $summary, $version, $maintainer, $contact) = @_;
++ return unless ref $self;
++
++ my $maintainer_id = $self-&gt;_get_maintainer_id($maintainer);
++ unless ($maintainer_id) {
++ carp &quot;Unknown maintainer $maintainer, aborting&quot;;
++ return;
++ }
++
++ my $contact_id = $self-&gt;_get_maintainer_id($contact);
++ unless ($contact_id) {
++ carp &quot;Unknown QA contact $contact, aborting&quot;;
++ return;
++ }
++
++ my $query = $self-&gt;{_queries}-&gt;{add_package};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{add_package});
++ $self-&gt;{_queries}-&gt;{add_package} = $query;
++ }
++
++ $query-&gt;execute($name, $summary);
++
++ my $package_id = $self-&gt;_get_package_id($name);
++
++ $self-&gt;_add_version($package_id, $version);
++ $self-&gt;_add_component(
++ $package_id,
++ 'package',
++ 'problem related to the package',
++ $maintainer_id,
++ $contact_id
++ );
++ $self-&gt;_add_component(
++ $package_id,
++ 'program',
++ 'problem related to the program',
++ $maintainer_id,
++ $contact_id
++ );
++}
++
++=head2 add_version($package, $version)
++
++Adds a new version to given package.
++
++=cut
++
++sub add_version {
++ my ($self, $package, $version) = @_;
++ return unless ref $self;
++
++ my $package_id = $self-&gt;_get_package_id($package);
++ $self-&gt;_add_version($package_id, $version);
++}
++
++sub _add_version {
++ my ($self, $package_id, $version) = @_;
++ return unless ref $self;
++
++ my $query = $self-&gt;{_queries}-&gt;{add_version};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{add_version});
++ $self-&gt;{_queries}-&gt;{add_version} = $query;
++ }
++
++ $query-&gt;execute($package_id, $version);
++}
++
++
++=head2 add_maintainer($name, $login, $password)
++
++Adds a new maintainer in the database, with given name, login and password.
++
++=cut
++
++sub add_maintainer {
++ my ($self, $name, $login, $pass) = @_;
++ return unless ref $self;
++
++ my $query = $self-&gt;{_queries}-&gt;{add_maintainer};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{add_maintainer});
++ $self-&gt;{_queries}-&gt;{add_maintainer} = $query;
++ }
++
++ $query-&gt;execute($login, $pass, $name, $default_flags);
++}
++
++sub _add_component {
++ my ($self, $package_id, $name, $description, $maintainer_id, $contact_id) = @_;
++
++ my $query = $self-&gt;{_queries}-&gt;{add_component};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{add_component});
++ $self-&gt;{_queries}-&gt;{add_component} = $query;
++ }
++
++ $query-&gt;execute($package_id, $name, $description, $maintainer_id, $contact_id);
++}
++
++=head2 del_package($package)
++
++Delete given package from database.
++
++=cut
++
++sub del_package {
++ my ($self, $package) = @_;
++ $self-&gt;_delete('del_package', $package);
++ $self-&gt;_delete('del_versions', $package);
++ $self-&gt;_delete('del_components', $package);
++}
++
++=head2 del_maintainer($maintainer)
++
++Delete given maintainer from database.
++
++=cut
++
++sub del_maintainer {
++ my ($self, $maintainer) = @_;
++ $self-&gt;_delete('del_maintainer', $maintainer);
++}
++
++sub _delete {
++ my ($self, $type, $value) = @_;
++ return unless ref $self;
++
++ my $query = $self-&gt;{_queries}-&gt;{$type};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{$type});
++ $self-&gt;{_queries}-&gt;{$type} = $query;
++ }
++
++ $query-&gt;execute($value);
++}
++
++=head2 reset_password(I&lt;$maintainer&gt;, I&lt;$password&gt;)
++
++Reset password of a maintainer to given password.
++
++=cut
++
++sub reset_password {
++ my ($self, $login, $pass) = @_;
++ return unless ref $self;
++
++ my $query = $self-&gt;{_queries}-&gt;{reset_password};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{reset_password});
++ $self-&gt;{_queries}-&gt;{reset_password} = $query;
++ }
++
++ $query-&gt;execute($pass, $login);
++}
++
++=head2 browse_packages($callback)
++
++Browse all packages from bugzilla, and execute given callback with name and
++maintainer as argument for each of them.
++
++=cut
++
++sub browse_packages {
++ my ($self, $callback) = @_;
++ return unless ref $self;
++
++ my $query = $self-&gt;{_queries}-&gt;{browse_packages};
++ unless ($query) {
++ $query = $self-&gt;{_dbh}-&gt;prepare($queries{browse_packages});
++ $self-&gt;{_queries}-&gt;{browse_packages} = $query;
++ }
++
++ $query-&gt;execute();
++
++ while (my @row = $query-&gt;fetchrow_array()) {
++ $callback-&gt;(@row);
++ }
++}
++
++# close database connection
++sub DESTROY {
++ my ($self) = @_;
++
++ foreach my $query (values %{$self-&gt;{_queries}}) {
++ $query-&gt;finish();
++ }
++
++ $self-&gt;{_dbh}-&gt;disconnect();
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Age.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Age.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Age.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,110 @@
++# $Id: Age.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Age;
++
++=head1 NAME
++
++Youri::Check::Input::Age - Check maximum age
++
++=head1 DESCRIPTION
++
++This plugin checks packages age, and report the ones exceeding maximum limit.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use DateTime;
++use DateTime::Format::Duration;
++use base 'Youri::Check::Input';
++
++sub columns {
++ return qw/
++ arch
++ buildtime
++ /;
++}
++
++sub links {
++ return qw//;
++}
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Age object.
++
++Specific parameters:
++
++=over
++
++=item max_age $age
++
++Maximum age allowed (default: 1 year)
++
++=item pattern $pattern
++
++Pattern used to describe age (default: %Y year)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ max_age =&gt; '1 year',
++ pattern =&gt; '%Y year',
++ @_
++ );
++
++ $self-&gt;{_format} = DateTime::Format::Duration-&gt;new(
++ pattern =&gt; $options{pattern}
++ );
++
++ $self-&gt;{_now} = DateTime-&gt;from_epoch(
++ epoch =&gt; time()
++ );
++
++ $self-&gt;{_max_age} = $options{max_age};
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $max_age_string = $media-&gt;max_age() ?
++ $media-&gt;max_age() :
++ $self-&gt;{_max_age};
++
++ my $max_age = $self-&gt;{_format}-&gt;parse_duration($max_age_string);
++
++ my $check = sub {
++ my ($package) = @_;
++
++ my $buildtime = DateTime-&gt;from_epoch(
++ epoch =&gt; $package-&gt;get_age()
++ );
++
++ my $age = $self-&gt;{_now}-&gt;subtract_datetime($buildtime);
++
++ if (DateTime::Duration-&gt;compare($age, $max_age) &gt; 0) {
++ my $date = $buildtime-&gt;strftime(&quot;%a %d %b %G&quot;);
++
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $package-&gt;get_arch(),
++ buildtime =&gt; $date
++ });
++ }
++ };
++ $media-&gt;traverse_headers($check);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/Iurt.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/Iurt.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/Iurt.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,117 @@
++# $Id: LBD.pm 574 2005-12-27 14:31:16Z guillomovitch $
++package Youri::Check::Input::Build::Source::Iurt;
++
++=head1 NAME
++
++Youri::Check::Input::Build::Source::Iurt - Iurt build log source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Build&gt; collects build logs
++available from a iurt build bot.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use LWP::UserAgent;
++use HTML::TokeParser;
++use base 'Youri::Check::Input::Build::Source';
++
++my %status = (
++ install_deps =&gt; 0,
++ build =&gt; 1,
++ binary_test =&gt; 2
++);
++
++my $pattern = '^('
++ . join('|', keys %status)
++ . ')_\S+-[^-]+-[^-]+\.src\.rpm\.\d+\.log$';
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Build::LBD object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL of logs for this iurt instance (default:
++<A HREF="http://qa.mandriva.com/build/iurt/cooker">http://qa.mandriva.com/build/iurt/cooker</A>)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://qa.mandriva.com/build/iurt/cooker">http://qa.mandriva.com/build/iurt/cooker</A>',
++ @_
++ );
++
++ $self-&gt;{_agent} = LWP::UserAgent-&gt;new();
++
++ # try to connect to base URL directly, and abort if not available
++ my $response = $self-&gt;{_agent}-&gt;head($options{url});
++ die &quot;Unavailable URL $options{url}: &quot; . $response-&gt;status_line()
++ unless $response-&gt;is_success();
++
++ $self-&gt;{_url} = $options{url};
++}
++
++sub fails {
++ my ($self, $name, $version, $release, $arch) = @_;
++
++ my $result;
++ my $url = &quot;$self-&gt;{_url}/$arch/log/$name-$version-$release.src.rpm&quot;;
++ print &quot;Fetching URL $url: &quot; if $self-&gt;{_verbose} &gt; 1;
++ my $response = $self-&gt;{_agent}-&gt;get($url);
++ print $response-&gt;status_line() . &quot;\n&quot; if $self-&gt;{_verbose} &gt; 1;
++ if ($response-&gt;is_success()) {
++ my $parser = HTML::TokeParser-&gt;new(\$response-&gt;content());
++ while (my $token = $parser-&gt;get_tag('a')) {
++ my $href = $token-&gt;[1]-&gt;{href};
++ next unless $href =~ /$pattern/o;
++ my $status = $1;
++ if (
++ !$result-&gt;{status} ||
++ $status{$result-&gt;{status}} &lt; $status{$status}
++ ) {
++ $result-&gt;{status} = $status;
++ $result-&gt;{url} = $url . '/' . $href;
++ }
++ }
++ }
++
++ $self-&gt;{_results}-&gt;{$name}-&gt;{$version}-&gt;{$release}-&gt;{$arch} = $result;
++
++ return $result-&gt;{status} &amp;&amp; $result-&gt;{status} ne 'binary_test';
++}
++
++sub status {
++ my ($self, $name, $version, $release, $arch) = @_;
++ return
++ $self-&gt;{_results}-&gt;{$name}-&gt;{$version}-&gt;{$release}-&gt;{$arch}-&gt;{status};
++}
++
++sub url {
++ my ($self, $name, $version, $release, $arch) = @_;
++ return
++ $self-&gt;{_results}-&gt;{$name}-&gt;{$version}-&gt;{$release}-&gt;{$arch}-&gt;{url};
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/LBD.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/LBD.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source/LBD.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,135 @@
++# $Id: LBD.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Build::Source::LBD;
++
++=head1 NAME
++
++Youri::Check::Input::Build::Source::LBD - LBD build log source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Build&gt; collects build logs
++available from a LBD build bot.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use LWP::UserAgent;
++use HTML::TokeParser;
++use base 'Youri::Check::Input::Build::Source';
++
++my @status = qw/
++ OK
++ arch_excl
++ broken
++ cannot_be_installed
++ debug
++ dependency
++ file_not_found
++ multiarch
++ problem
++ unpackaged_files
++/;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Build::LBD object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL of logs for this LBD instance (default: <A HREF="http://eijk.homelinux.org/build">http://eijk.homelinux.org/build</A>)
++
++=item medias $medias
++
++List of medias monitored by this LBD instance
++
++=item archs $archs
++
++List of architectures monitored by this LBD instance
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://eijk.homelinux.org/build">http://eijk.homelinux.org/build</A>',
++ medias =&gt; undef,
++ archs =&gt; undef,
++ @_
++ );
++
++ my $agent = LWP::UserAgent-&gt;new();
++
++ # try to connect to base URL directly, and abort if not available
++ my $response = $agent-&gt;head($options{url});
++ die &quot;Unavailable URL $options{url}: &quot; . $response-&gt;status_line()
++ unless $response-&gt;is_success();
++
++ my $pattern = '^(\S+)-([^-]+)-([^-]+)(?:\.gz)?$';
++
++ foreach my $arch (@{$options{archs}}) {
++ foreach my $media (@{$options{medias}}) {
++ my $url_base = &quot;$options{url}/$arch/$media/BO&quot;;
++ foreach my $status (@status) {
++ my $url = &quot;$url_base/$status/&quot;;
++ print &quot;Fetching URL $url: &quot; if $self-&gt;{_verbose} &gt; 1;
++ my $response = $agent-&gt;get($url);
++ print $response-&gt;status_line() . &quot;\n&quot; if $self-&gt;{_verbose} &gt; 1;
++ if ($response-&gt;is_success()) {
++ my $parser = HTML::TokeParser-&gt;new(\$response-&gt;content());
++ while (my $token = $parser-&gt;get_tag('a')) {
++ my $href = $token-&gt;[1]-&gt;{href};
++ next unless $href =~ /$pattern/o;
++ my $name = $1;
++ my $version = $2;
++ my $release = $3;
++ my $result;
++ $result-&gt;{status} = $status;
++ $result-&gt;{url} = $url . '/' . $href;
++ $self-&gt;{_results}-&gt;{$name}-&gt;{$version}-&gt;{$release}-&gt;{$arch} = $result;
++ }
++ }
++ }
++ }
++ }
++}
++
++sub fails {
++ my ($self, $name, $version, $release, $arch) = @_;
++
++ my $status =
++ $self-&gt;{_results}-&gt;{$name}-&gt;{$version}-&gt;{$release}-&gt;{$arch}-&gt;{status};
++
++ return $status &amp;&amp; $status ne 'OK' &amp;&amp; $status ne 'arch_excl';
++}
++
++sub status {
++ my ($self, $name, $version, $release, $arch) = @_;
++ return
++ $self-&gt;{_results}-&gt;{$name}-&gt;{$version}-&gt;{$release}-&gt;{$arch}-&gt;{status};
++}
++
++sub url {
++ my ($self, $name, $version, $release, $arch) = @_;
++ return
++ $self-&gt;{_results}-&gt;{$name}-&gt;{$version}-&gt;{$release}-&gt;{$arch}-&gt;{url};
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build/Source.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,109 @@
++# $Id: Source.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Build::Source;
++
++=head1 NAME
++
++Youri::Check::Input::Build::Source - Abstract build log source
++
++=head1 DESCRIPTION
++
++This abstract class defines the updates source interface for
++L&lt;Youri::Check::Input::Build&gt;.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Build 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 &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ id =&gt; '', # object id
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ @_
++ );
++
++ my $self = bless {
++ _id =&gt; $options{id},
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head1 INSTANCE METHODS
++
++=head2 get_id()
++
++Returns source identity.
++
++=cut
++
++sub get_id {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_id};
++}
++
++=head2 fails($name, $version, $release, $arch)
++
++Returns true if build fails for package with given name, version and release on
++given architecture.
++
++=head2 status($name, $version, $release, $arch)
++
++Returns exact build status for package with given name, version and release on
++given architecture. It has to be called after fails().
++
++=head2 url($name, $version, $release, $arch)
++
++Returns URL of information source for package with given name, version and
++release on given architecture. It has to be called after fails().
++
++=head1 SUBCLASSING
++
++The following methods have to be implemented:
++
++=over
++
++=item fails
++
++=item status
++
++=item url
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Build.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,128 @@
++# $Id: Build.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Build;
++
++=head1 NAME
++
++Youri::Check::Input::Build - Check build outputs
++
++=head1 DESCRIPTION
++
++This plugin checks build outputs of packages, and report failures. Additional
++source plugins handle specific sources.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Utils;
++use base 'Youri::Check::Input';
++
++sub columns {
++ return qw/
++ arch
++ bot
++ status
++ /;
++}
++
++sub links {
++ return qw/
++ status url
++ /;
++}
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Build object.
++
++Specific parameters:
++
++=over
++
++=item sources $sources
++
++Hash of source plugins definitions
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ sources =&gt; undef,
++ @_
++ );
++
++ croak &quot;No source defined&quot; unless $options{sources};
++ croak &quot;sources should be an hashref&quot; unless ref $options{sources} eq 'HASH';
++
++ foreach my $id (keys %{$options{sources}}) {
++ print &quot;Creating source $id\n&quot; if $options{verbose};
++ eval {
++ push(
++ @{$self-&gt;{_sources}},
++ create_instance(
++ 'Youri::Check::Input::Build::Source',
++ id =&gt; $id,
++ test =&gt; $options{test},
++ verbose =&gt; $options{verbose},
++ %{$options{sources}-&gt;{$id}}
++ )
++ );
++ # register monitored archs
++ $self-&gt;{_archs}-&gt;{$_}-&gt;{$id} = 1
++ foreach @{$options{sources}-&gt;{$id}-&gt;{archs}};
++ };
++ print STDERR &quot;Failed to create source $id: $@\n&quot; if $@;
++ }
++
++ croak &quot;no sources created&quot; unless @{$self-&gt;{_sources}};
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # this is a source media check only
++ return unless $media-&gt;get_type() eq 'source';
++
++ my $callback = sub {
++ my ($package) = @_;
++
++ my $name = $package-&gt;get_name();
++ my $version = $package-&gt;get_version();
++ my $release = $package-&gt;get_release();
++
++ foreach my $source (@{$self-&gt;{_sources}}) {
++ my $id = $source-&gt;get_id();
++ foreach my $arch (keys %{$self-&gt;{_archs}}) {
++ next unless $self-&gt;{_archs}-&gt;{$arch}-&gt;{$id};
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ bot =&gt; $id,
++ status =&gt; $source-&gt;status($name, $version, $release, $arch),
++ url =&gt; $source-&gt;url($name, $version, $release, $arch),
++ }) if $source-&gt;fails(
++ $name,
++ $version,
++ $release,
++ $arch,
++ );
++ }
++ }
++ };
++
++ $media-&gt;traverse_headers($callback);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Conflicts.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Conflicts.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Conflicts.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,231 @@
++# $Id: Conflicts.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Conflicts;
++
++=head1 NAME
++
++Youri::Check::Input::Conflicts - Check file conflicts
++
++=head1 DESCRIPTION
++
++This plugin checks packages files, and report conflict and duplications.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use constant;
++use Youri::Package;
++use base 'Youri::Check::Input';
++
++use constant TYPE_MASK =&gt; 0170000;
++use constant TYPE_DIR =&gt; 0040000;
++
++use constant PACKAGE =&gt; 0;
++use constant MODE =&gt; 1;
++use constant MD5SUM =&gt; 2;
++
++my $compatibility = {
++ x86_64 =&gt; 'i586',
++ i586 =&gt; 'x86_64',
++ sparc64 =&gt; 'sparc',
++ sparc =&gt; 'sparc64',
++ ppc64 =&gt; 'ppc',
++ ppc =&gt; 'ppc64'
++};
++
++sub columns {
++ return qw/
++ arch
++ file
++ error
++ level
++ /;
++}
++
++sub links {
++ return qw//;
++}
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Conflicts object.
++
++No specific parameters.
++
++=cut
++
++sub prepare {
++ my ($self, @medias) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $index = sub {
++ my ($package) = @_;
++
++ # index files
++ foreach my $file ($package-&gt;get_files()) {
++ push(
++ @{$self-&gt;{_files}-&gt;{$file-&gt;[Youri::Package::FILE_NAME]}},
++ [ $package, $file-&gt;[Youri::Package::FILE_MODE], $file-&gt;[Youri::Package::FILE_MD5SUM] ]
++ );
++ }
++ };
++
++ foreach my $media (@medias) {
++ # don't index source media files
++ next unless $media-&gt;get_type() eq 'binary';
++
++ my $media_id = $media-&gt;get_id();
++ $self-&gt;{_medias}-&gt;{$media_id} = 1;
++ print STDERR &quot;Indexing media $media_id files\n&quot;
++ if $self-&gt;{_verbose};
++
++ $media-&gt;traverse_headers($index);
++ }
++}
++
++sub run {
++ my ($self, $media, $result) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # this is a binary media check only
++ return unless $media-&gt;get_type() eq 'binary';
++
++ my $check = sub {
++ my ($package) = @_;
++
++ return if $package-&gt;get_arch() eq 'src';
++
++ my $arch = $package-&gt;get_arch();
++ my $name = $package-&gt;get_name();
++
++ foreach my $file ($package-&gt;get_files()) {
++
++ my $found =
++ $self-&gt;{_files}-&gt;{$file-&gt;[Youri::Package::FILE_NAME]};
++
++ my @found = $found ? @$found : ();
++
++ foreach my $found (@found) {
++ next if $found-&gt;[PACKAGE] == $package;
++ next unless compatible($found-&gt;[PACKAGE], $package);
++ next if conflict($found-&gt;[PACKAGE], $package);
++ next if replace($found-&gt;[PACKAGE], $package);
++ if (
++ ($file-&gt;[Youri::Package::FILE_MODE] &amp; TYPE_MASK) == TYPE_DIR &amp;&amp;
++ ($found-&gt;[MODE] &amp; TYPE_MASK) == TYPE_DIR
++ ) {
++ $result-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;directory $file-&gt;[Youri::Package::FILE_NAME] duplicated with package &quot; . $found-&gt;[PACKAGE]-&gt;get_name(),
++ level =&gt; Youri::Check::Input::WARNING
++ }) unless $self-&gt;_directory_duplicate_exception(
++ $package,
++ $found-&gt;[PACKAGE],
++ $file
++ );
++ } else {
++ if ($found-&gt;[MD5SUM] eq $file-&gt;[Youri::Package::FILE_MD5SUM]) {
++ $result-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;file $file-&gt;[Youri::Package::FILE_NAME] duplicated with package &quot; . $found-&gt;[PACKAGE]-&gt;get_name(),
++ level =&gt; Youri::Check::Input::WARNING
++ }) unless $self-&gt;_file_duplicate_exception(
++ $package,
++ $found-&gt;[PACKAGE],
++ $file
++ );
++ } else {
++ $result-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;non-explicit conflict on file $file-&gt;[Youri::Package::FILE_NAME] with package &quot; . $found-&gt;[PACKAGE]-&gt;get_name(),
++ level =&gt; Youri::Check::Input::ERROR
++ }) unless $self-&gt;_file_conflict_exception(
++ $package,
++ $found-&gt;[PACKAGE],
++ $file
++ );
++ }
++ }
++ }
++ }
++ };
++
++ $media-&gt;traverse_headers($check);
++}
++
++# return true if $package1 is arch-compatible with $package2
++sub compatible {
++ my ($package1, $package2) = @_;
++
++ my $arch1 = $package1-&gt;get_arch();
++ my $arch2 = $package2-&gt;get_arch();
++
++ return 1 if $arch1 eq $arch2;
++
++ return 1 if $compatibility-&gt;{$arch1} &amp;&amp; $compatibility-&gt;{$arch1} eq $arch2;
++
++ return 0;
++}
++
++# return true if $package1 conflict with $package2
++# or the other way around
++sub conflict {
++ my ($package1, $package2) = @_;
++
++ my $name2 = $package2-&gt;get_name();
++
++ foreach my $conflict ($package1-&gt;get_conflicts()) {
++ return 1 if $conflict eq $name2;
++ }
++
++ my $name1 = $package1-&gt;get_name();
++
++ foreach my $conflict ($package2-&gt;get_conflicts()) {
++ return 1 if $conflict eq $name1;
++ }
++
++ return 0;
++}
++
++# return true if $package1 replace $package2
++sub replace {
++ my ($package1, $package2) = @_;
++
++
++ my $name1 = $package1-&gt;get_name();
++ my $name2 = $package2-&gt;get_name();
++
++ return 1 if $name1 eq $name2;
++
++ foreach my $obsolete ($package1-&gt;get_obsoletes()) {
++ return 1 if $obsolete-&gt;[Youri::Package::DEPENDENCY_NAME] eq $name2;
++ }
++
++ return 0;
++}
++
++sub _directory_duplicate_exception {
++ return 0;
++}
++
++sub _file_duplicate_exception {
++ return 0;
++}
++
++sub _file_conflict_exception {
++ return 0;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Dependencies.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Dependencies.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Dependencies.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,162 @@
++# $Id: Dependencies.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Dependencies;
++
++=head1 NAME
++
++Youri::Check::Input::Dependencies - Check dependencies consistency
++
++=head1 DESCRIPTION
++
++This class checks dependencies consistency.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Package;
++use base 'Youri::Check::Input';
++
++use constant MEDIA =&gt; 0;
++use constant RANGE =&gt; 1;
++
++sub columns {
++ return qw/
++ arch
++ file
++ error
++ level
++ /;
++}
++
++sub links {
++ return qw//;
++}
++
++sub prepare {
++ my ($self, @medias) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ foreach my $media (@medias) {
++ my $media_id = $media-&gt;get_id();
++ $self-&gt;{_medias}-&gt;{$media_id} = 1;
++ print STDERR &quot;Indexing media $media_id dependencies\n&quot;
++ if $self-&gt;{_verbose};
++
++ my $index = sub {
++ my ($package) = @_;
++
++ # index provides
++ foreach my $provide ($package-&gt;get_provides()) {
++ push(
++ @{$self-&gt;{_provides}-&gt;{$provide-&gt;[Youri::Package::DEPENDENCY_NAME]}},
++ [ $media_id, $provide-&gt;[Youri::Package::DEPENDENCY_RANGE] ]
++ );
++ }
++
++ # index files
++ foreach my $file ($package-&gt;get_files()) {
++ push(
++ @{$self-&gt;{_files}-&gt;{$file-&gt;[Youri::Package::FILE_NAME]}},
++ [ $media_id, undef ]
++ );
++ }
++ };
++ $media-&gt;traverse_headers($index);
++ }
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my @allowed_ids = $media-&gt;allow_deps();
++
++ # abort unless all allowed medias are present
++ foreach my $id (@allowed_ids) {
++ unless ($self-&gt;{_medias}-&gt;{$id}) {
++ carp &quot;Missing media $id, aborting&quot;;
++ return;
++ }
++ }
++
++ # index allowed medias
++ my %allowed_ids = map { $_ =&gt; 1 } @allowed_ids;
++ my $allowed_ids = join(&quot;,&quot;, @allowed_ids);
++
++ my $class = $media-&gt;get_package_class();
++
++ my $check = sub {
++ my ($package) = @_;
++
++ my $arch = $package-&gt;get_arch();
++ my $name = $package-&gt;get_name();
++
++ foreach my $require ($package-&gt;get_requires()) {
++
++ my $found =
++ substr($require-&gt;[Youri::Package::DEPENDENCY_NAME], 0, 1) eq '/' ?
++ $self-&gt;{_files}-&gt;{$require-&gt;[Youri::Package::DEPENDENCY_NAME]} :
++ $self-&gt;{_provides}-&gt;{$require-&gt;[Youri::Package::DEPENDENCY_NAME]};
++
++ my @found = $found ? @$found : ();
++
++ if (!@found) {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;$require-&gt;[Youri::Package::DEPENDENCY_NAME] not found&quot;,
++ level =&gt; Youri::Check::Input::ERROR
++ });
++ next;
++ }
++
++ my @found_in_media =
++ grep { $allowed_ids{$_-&gt;[MEDIA]} }
++ @found;
++
++ if (!@found_in_media) {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;$require-&gt;[Youri::Package::DEPENDENCY_NAME] found in incorrect media $_-&gt;[MEDIA] (allowed $allowed_ids)&quot;,
++ level =&gt; Youri::Check::Input::ERROR
++ }) foreach @found;
++ next;
++ }
++
++ next unless $require-&gt;[Youri::Package::DEPENDENCY_RANGE];
++
++ my @found_in_range =
++ grep {
++ !$_-&gt;[RANGE] ||
++ $class-&gt;compare_ranges(
++ $require-&gt;[Youri::Package::DEPENDENCY_RANGE],
++ $_-&gt;[RANGE]
++ )
++ } @found_in_media;
++
++ if (!@found_in_range) {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;$require-&gt;[Youri::Package::DEPENDENCY_NAME] found with incorrect range $_-&gt;[RANGE] (needed $require-&gt;[Youri::Package::DEPENDENCY_RANGE])&quot;,
++ level =&gt; Youri::Check::Input::ERROR
++ }) foreach @found_in_media;
++ next;
++ }
++ }
++ };
++
++ $media-&gt;traverse_headers($check);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/MandrivaConflicts.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/MandrivaConflicts.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/MandrivaConflicts.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,63 @@
++# $Id: Conflicts.pm 533 2005-10-20 07:08:03Z guillomovitch $
++package Youri::Check::Input::MandrivaConflicts;
++
++=head1 NAME
++
++Youri::Check::Input::MandrivaConflicts - Check file conflicts on Mandriva
++
++=head1 DESCRIPTION
++
++This class checks file conflicts between packages, taking care of Mandriva
++packaging policy.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Package;
++use base 'Youri::Check::Input::Conflicts';
++
++sub _directory_duplicate_exception {
++ my ($self, $package1, $package2, $file) = @_;
++
++ # allow shared directories between devel packages of different arch
++ return 1 if _multiarch_exception($package1, $package2);
++
++ # allow shared modules directories between perl packages
++ return 1 if
++ $file-&gt;[Youri::Package::FILE_NAME] =~ /^\/usr\/lib\/perl5\/vendor_perl\// &amp;&amp;
++ $file-&gt;[Youri::Package::FILE_NAME] !~ /^(auto|[^\/]+-linux)$/;
++
++ return 0;
++}
++
++sub _file_duplicate_exception {
++ my ($self, $package1, $package2, $file) = @_;
++
++ # allow shared files between devel packages of different arch
++ return 1 if _multiarch_exception($package1, $package2);
++
++ return 0;
++}
++
++sub _multiarch_exception {
++ my ($package1, $package2) = @_;
++
++ return 1 if
++ $package1-&gt;get_canonical_name() eq $package2-&gt;get_canonical_name()
++ &amp;&amp; $package1-&gt;get_name() =~ /-devel$/
++ &amp;&amp; $package2-&gt;get_name() =~ /-devel$/;
++
++ return 0;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Missing.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Missing.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Missing.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,138 @@
++package Youri::Check::Input::Missing;
++
++=head1 NAME
++
++Youri::Check::Input::Missing - Check components consistency
++
++=head1 DESCRIPTION
++
++This plugin checks consistency between package components, and report outdated
++ones.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use List::MoreUtils qw/all any/;
++use base 'Youri::Check::Input';
++
++sub columns {
++ return qw/
++ component
++ arch
++ revision
++ error
++ /;
++}
++
++sub links {
++ return qw//;
++}
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Missing object.
++
++No specific parameters.
++
++=cut
++
++sub prepare {
++ my ($self, @medias) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ $self-&gt;{_srcs} = ();
++ foreach my $media (@medias) {
++ # only index source media
++ next unless $media-&gt;get_type() eq 'source';
++
++ my $media_id = $media-&gt;get_id();
++ $self-&gt;{_medias}-&gt;{$media_id} = 1;
++ print STDERR &quot;Indexing media $media_id packages\n&quot; if $self-&gt;{_verbose};
++
++ my $index = sub {
++ my ($package) = @_;
++ $self-&gt;{_srcs}-&gt;{$media_id}-&gt;{$package-&gt;get_name()} =
++ $package-&gt;get_version() . '-' . $package-&gt;get_release();
++ };
++
++ $media-&gt;traverse_headers($index);
++ }
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # this is a binary media check only
++ return unless $media-&gt;get_type() eq 'binary';
++
++ my @allowed_ids = $media-&gt;allow_srcs();
++
++ # abort unless all allowed medias are present
++ foreach my $id (@allowed_ids) {
++ unless ($self-&gt;{_medias}-&gt;{$id}) {
++ carp &quot;Missing media $id, aborting&quot;;
++ return;
++ }
++ }
++
++ my $class = $media-&gt;get_package_class();
++
++ my $check_package = sub {
++ my ($package) = @_;
++ my $canonical_name = $package-&gt;get_canonical_name();
++
++ my $bin_revision =
++ $package-&gt;get_version() . '-' . $package-&gt;get_release();
++
++ my $src_revision;
++ foreach my $id (@allowed_ids) {
++ $src_revision = $self-&gt;{_srcs}-&gt;{$id}-&gt;{$canonical_name};
++ last if $src_revision;
++ }
++
++ if ($src_revision) {
++ # check if revision match
++ unless ($src_revision eq $bin_revision) {
++ if ($class-&gt;compare_versions($src_revision, $bin_revision) &gt; 0) {
++ # binary package is obsolete
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ component =&gt; $package-&gt;get_name(),
++ arch =&gt; $package-&gt;get_arch(),
++ revision =&gt; $bin_revision,
++ error =&gt; &quot;Obsolete binaries (source $src_revision found)&quot;,
++ });
++ } else {
++ # source package is obsolete
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ component =&gt; $package-&gt;get_canonical_name(),
++ arch =&gt; 'src',
++ revision =&gt; $src_revision,
++ error =&gt; &quot;Obsolete source (binaries $bin_revision found)&quot;,
++ });
++ }
++ }
++ } else {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ component =&gt; $package-&gt;get_name(),
++ arch =&gt; $package-&gt;get_arch(),
++ revision =&gt; $bin_revision,
++ error =&gt; &quot;Missing source package&quot;,
++ });
++ }
++ };
++
++ $media-&gt;traverse_headers($check_package);
++}
++
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Orphans.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Orphans.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Orphans.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,74 @@
++package Youri::Check::Input::Orphans;
++
++=head1 NAME
++
++Youri::Check::Input::Orphans - Check maintainance
++
++=head1 DESCRIPTION
++
++This plugin checks maintainance status of packages, and reports unmaintained
++ones.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Input';
++
++sub columns {
++ return qw/
++ error
++ /;
++}
++
++sub links {
++ return qw//;
++}
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Orphans object.
++
++No specific parameters.
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ resolver =&gt; undef,
++ @_
++ );
++
++ croak &quot;No resolver defined&quot; unless $options{resolver};
++
++ $self-&gt;{_resolver} = $options{resolver};
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # this is a source media check only
++ return unless $media-&gt;get_type() eq 'source';
++
++ my $check = sub {
++ my ($package) = @_;
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ error =&gt; &quot;unmaintained package&quot;
++ }) unless $self-&gt;{_resolver}-&gt;get_maintainer($package);
++ };
++
++ $media-&gt;traverse_headers($check);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Rpmlint.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Rpmlint.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Rpmlint.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,113 @@
++# $Id: Rpmlint.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Rpmlint;
++
++=head1 NAME
++
++Youri::Check::Input::Rpmlint - Check packages with rpmlint
++
++=head1 DESCRIPTION
++
++This plugins checks packages with rpmlint, and reports output.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Input';
++
++sub columns {
++ return qw/
++ arch
++ file
++ error
++ level
++ /;
++}
++
++sub links {
++ return qw//;
++}
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Rpmlint object.
++
++Specific parameters:
++
++=over
++
++=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 = (
++ path =&gt; '/usr/bin/rpmlint', # path to rpmlint
++ config =&gt; '', # default rpmlint configuration
++ @_
++ );
++
++ $self-&gt;{_path} = $options{path};
++ $self-&gt;{_config} = $options{config};
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $config = $media-&gt;rpmlint_config() ?
++ $media-&gt;rpmlint_config() :
++ $self-&gt;{_config};
++
++ my $check = sub {
++ my ($file, $package) = @_;
++
++ my $arch = $package-&gt;get_arch();
++ my $name = $package-&gt;get_name();
++
++ my $command = &quot;$self-&gt;{_path} -f $config $file&quot;;
++ open(RPMLINT, &quot;$command |&quot;) or die &quot;Can't run $command: $!&quot;;
++ while (&lt;RPMLINT&gt;) {
++ chomp;
++ if (/^E: \Q$name\E (.+)/) {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; $1,
++ level =&gt; Youri::Check::Input::ERROR
++ });
++ } elsif (/^W: \Q$name\E (.+)/) {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; $1,
++ level =&gt; Youri::Check::Input::WARNING
++ });
++ }
++ }
++ close(RPMLINT);
++ };
++
++ $media-&gt;traverse_files($check);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Signature.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Signature.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Signature.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,96 @@
++# $Id: Rpmlint.pm 567 2005-12-12 21:24:56Z guillomovitch $
++package Youri::Check::Input::Signature;
++
++=head1 NAME
++
++Youri::Check::Input::Signature - Check signature
++
++=head1 DESCRIPTION
++
++This plugin checks packages signature, and report unsigned ones.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Input';
++
++sub columns {
++ return qw/
++ arch
++ file
++ error
++ /;
++}
++
++sub links {
++ return qw//;
++}
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Signature object.
++
++Specific parameters:
++
++=over
++
++=item key $key
++
++Expected GPG key identity
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ key =&gt; '',
++ @_
++ );
++
++ $self-&gt;{_key} = $options{key};
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $check = sub {
++ my ($package) = @_;
++
++ my $arch = $package-&gt;get_arch();
++ my $name = $package-&gt;get_name();
++
++ my $key = $package-&gt;get_gpg_key();
++
++ if (!$key) {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;unsigned package $name&quot;
++ });
++ } elsif ($key ne $self-&gt;{_key}) {
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ arch =&gt; $arch,
++ file =&gt; $name,
++ error =&gt; &quot;invalid key id $key for package $name (allowed $self-&gt;{_key})&quot;
++ });
++ }
++
++ };
++
++ $media-&gt;traverse_headers($check);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/CPAN.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/CPAN.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/CPAN.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,75 @@
++# $Id: CPAN.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source::CPAN;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::CPAN - CPAN updates source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++available from CPAN.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::CPAN object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL to CPAN full modules list (default:
++<A HREF="http://www.cpan.org/modules/01modules.index.html">http://www.cpan.org/modules/01modules.index.html</A>)
++
++=back
++
++=cut
++
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://www.cpan.org/modules/01modules.index.html">http://www.cpan.org/modules/01modules.index.html</A>',
++ @_
++ );
++
++ my $versions;
++ open(INPUT, &quot;GET $options{url} |&quot;) or croak &quot;Can't fetch $options{url}: $!&quot;;
++ while (&lt;INPUT&gt;) {
++ next unless $_ =~ /&gt;([\w-]+)-([\d\.]+)\.tar\.gz&lt;\/a&gt;/;
++ $versions-&gt;{$1} = $2;
++ }
++ close(INPUT);
++
++ $self-&gt;{_versions} = $versions;
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return &quot;<A HREF="http://search.cpan.org/dist/$name">http://search.cpan.org/dist/$name</A>&quot;;
++}
++
++sub _name {
++ my ($self, $name) = @_;
++ $name =~ s/^perl-//g;
++ return $name;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Debian.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Debian.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Debian.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,82 @@
++# $Id: Debian.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source::Debian;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::Debian - Debian source for updates
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++ available from Debian.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::Debian object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL to Debian mirror content file (default: <A HREF="http://ftp.debian.org/ls-lR.gz">http://ftp.debian.org/ls-lR.gz</A>)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://ftp.debian.org/ls-lR.gz">http://ftp.debian.org/ls-lR.gz</A>',
++ @_
++ );
++
++ my $versions;
++ open(INPUT, &quot;GET $options{url} | zcat |&quot;) or croak &quot;Can't fetch $options{url}: $!&quot;;
++ while (my $line = &lt;INPUT&gt;) {
++ next unless $line =~ /([\w\.-]+)_([\d\.]+)\.orig\.tar\.gz$/;
++ my $name = $1;
++ my $version = $2;
++ $versions-&gt;{$name} = $version;
++ }
++ close(INPUT);
++
++ $self-&gt;{_versions} = $versions;
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return &quot;<A HREF="http://packages.debian.org/$name">http://packages.debian.org/$name</A>&quot;;
++}
++
++sub _name {
++ my ($self, $name) = @_;
++
++ if ($name =~ /^(perl|ruby)-([-\w]+)$/) {
++ $name = lc(&quot;lib$2-$1&quot;);
++ } elsif ($name =~ /^apache-([-\w]+)$/) {
++ $name = &quot;libapache-$1&quot;;
++ $name =~ s/_/-/g;
++ }
++
++ return $name;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Fedora.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Fedora.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Fedora.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,63 @@
++# $Id: Fedora.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source::Fedora;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::Fedora - Fedora updates source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++available from Fedora.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::Fedora object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL to Fedora development SRPMS directory (default:
++<A HREF="http://fr.rpmfind.net/linux/fedora/core/development/SRPMS">http://fr.rpmfind.net/linux/fedora/core/development/SRPMS</A>)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://fr.rpmfind.net/linux/fedora/core/development/SRPMS">http://fr.rpmfind.net/linux/fedora/core/development/SRPMS</A>',
++ @_
++ );
++
++ my $versions;
++ open(INPUT, &quot;GET $options{url} |&quot;) or die &quot;Can't fetch $options{url}: $!\n&quot;;
++ while (&lt;INPUT&gt;) {
++ next unless $_ =~ /&gt;([\w-]+)-([\w\.]+)-[\w\.]+\.src\.rpm&lt;\/a&gt;/;
++ $versions-&gt;{$1} = $2;
++ }
++ close(INPUT);
++
++ $self-&gt;{_versions} = $versions;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Freshmeat.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Freshmeat.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Freshmeat.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,111 @@
++# $Id: Freshmeat.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source::Freshmeat;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::Freshmeat - Freshmeat source for updates
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++available from Freshmeat.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use XML::Twig;
++use LWP::UserAgent;
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::Freshmeat
++object.
++
++Specific parameters:
++
++=over
++
++=item preload true/false
++
++Allows to load full Freshmeat catalogue at once instead of checking each software independantly (default: false)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ preload =&gt; 0,
++ @_
++ );
++
++ if ($options{preload}) {
++ my $versions;
++
++ my $project = sub {
++ my ($twig, $project) = @_;
++ my $name = $project-&gt;first_child('projectname_short')-&gt;text();
++ my $version = $project-&gt;first_child('latest_release')-&gt;first_child('latest_release_version')-&gt;text();
++ $versions-&gt;{$name} = $version;
++ $twig-&gt;purge();
++ };
++
++ my $twig = XML::Twig-&gt;new(
++ TwigRoots =&gt; { project =&gt; $project }
++ );
++
++ my $url = '<A HREF="http://download.freshmeat.net/backend/fm-projects.rdf.bz2">http://download.freshmeat.net/backend/fm-projects.rdf.bz2</A>';
++
++ open(INPUT, &quot;GET $url | bzcat |&quot;) or die &quot;Can't fetch $url: $!\n&quot;;
++ $twig-&gt;parse(\*INPUT);
++ close(INPUT);
++
++ $self-&gt;{_versions} = $versions;
++ }
++}
++
++sub _version {
++ my ($self, $name) = @_;
++
++ if ($self-&gt;{_versions}) {
++ return $self-&gt;{_versions}-&gt;{$name};
++ } else {
++ my $version;
++
++ my $latest_release_version = sub {
++ $version = $_[1]-&gt;text();
++ };
++
++ my $twig = XML::Twig-&gt;new(
++ TwigRoots =&gt; { latest_release_version =&gt; $latest_release_version }
++ );
++
++ my $url = &quot;<A HREF="http://freshmeat.net/projects-xml/$name">http://freshmeat.net/projects-xml/$name</A>&quot;;
++
++ open(INPUT, &quot;GET $url |&quot;) or die &quot;Can't fetch $url: $!\n&quot;;
++ # freshmeat answer with an HTML page when project doesn't exist
++ $twig-&gt;safe_parse(\*INPUT);
++ close(INPUT);
++
++ return $version;
++ }
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return &quot;<A HREF="http://freshmeat.net/projects/$name">http://freshmeat.net/projects/$name</A>&quot;;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/GNOME.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/GNOME.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/GNOME.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,104 @@
++# $Id$
++package Youri::Check::Input::Updates::Source::GNOME;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::GNOME - GNOME updates source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++available from GNOME.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use LWP::UserAgent;
++use HTML::TokeParser;
++use List::MoreUtils 'any';
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::Gnome object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL to GNOME sources directory (default:
++<A HREF="http://fr2.rpmfind.net/linux/gnome.org/sources">http://fr2.rpmfind.net/linux/gnome.org/sources</A>)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://fr2.rpmfind.net/linux/gnome.org/sources/">http://fr2.rpmfind.net/linux/gnome.org/sources/</A>', # default url
++ # We use HTTP as it offers a better sorting (1.2 &lt; 1.10)
++ @_
++ );
++
++ $self-&gt;{_agent} = LWP::UserAgent-&gt;new();
++ my $response = $self-&gt;{_agent}-&gt;get($options{url});
++ if($response-&gt;is_success()) {
++ my $parser = HTML::TokeParser-&gt;new(\$response-&gt;content());
++ while (my $token = $parser-&gt;get_tag('a')) {
++ my $href = $token-&gt;[1]-&gt;{href};
++ next unless $href =~ /^([-\w]+)\/$/o;
++ $self-&gt;{_names}-&gt;{$1} = 1;
++ }
++ }
++
++ $self-&gt;{_url} = $options{url};
++}
++
++sub _version {
++ my ($self, $name) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return unless $self-&gt;{_names}-&gt;{$name};
++
++ my $response = $self-&gt;{_agent}-&gt;get(&quot;$self-&gt;{_url}/$name/&quot;);
++ if($response-&gt;is_success()) {
++ my $major;
++ my $parser = HTML::TokeParser-&gt;new(\$response-&gt;content());
++ while (my $token = $parser-&gt;get_tag('a')) {
++ my $href = $token-&gt;[1]-&gt;{href};
++ next unless $href =~ /^([.\d]+)\/$/o;
++ $major = $1;
++ }
++ return unless $major;
++
++ $response = $self-&gt;{_agent}-&gt;get(&quot;$self-&gt;{_url}/$name/$major/&quot;);
++ if($response-&gt;is_success()) {
++ $parser = HTML::TokeParser-&gt;new(\$response-&gt;content());
++ while (my $token = $parser-&gt;get_tag('a')) {
++ my $href = $token-&gt;[1]-&gt;{href};
++ next unless $href =~ /^LATEST-IS-([.\d]+)$/o;
++ return $1;
++ }
++ }
++ }
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return $self-&gt;{_url}.&quot;$name/&quot;;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Gentoo.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Gentoo.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Gentoo.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,75 @@
++# $Id: Gentoo.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source::Gentoo;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::Gentoo - Gentoo updates source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++available from Gentoo.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use LWP::Simple;
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::Gentoo object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL to Gentoo snapshots directory (default:
++<A HREF="http://gentoo.mirror.sdv.fr/snapshots">http://gentoo.mirror.sdv.fr/snapshots</A>)
++
++=back
++
++=cut
++
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://gentoo.mirror.sdv.fr/snapshots">http://gentoo.mirror.sdv.fr/snapshots</A>', # default URL
++ @_
++ );
++
++ my $versions;
++ my $content = get($options{url});
++ my $file;
++ while ($content =~ /&lt;A HREF=&quot;(portage-\d{8}.tar.bz2)&quot;&gt;/g) {
++ $file = $1;
++ }
++ open(INPUT, &quot;GET $options{url}/$file | tar tjf - |&quot;) or croak &quot;Can't fetch $options{url}/$file: $!&quot;;
++ while (my $line = &lt;INPUT&gt;) {
++ next unless $line =~ /.*\/([\w-]+)-([\d\.]+)(:?-r\d)?\.ebuild$/;
++ $versions-&gt;{$1} = $2;
++ }
++ close(INPUT);
++
++ $self-&gt;{_versions} = $versions;
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return &quot;<A HREF="http://packages.gentoo.org/search/?sstring=$name">http://packages.gentoo.org/search/?sstring=$name</A>&quot;;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/NetBSD.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/NetBSD.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/NetBSD.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,75 @@
++# $Id$
++package Youri::Check::Input::Updates::Source::NetBSD;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::NetBSD - NetBSD source for updates
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++ available from NetBSD.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Input::Updates::Source';
++use IO::Ftp;
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::NetBSD object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL to NetBSD mirror content file, without ftp: (default: //ftp.free.fr/mirrors/ftp.netbsd.org/NetBSD-current/pkgsrc/README-all.html)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '//ftp.free.fr/mirrors/ftp.netbsd.org/NetBSD-current/pkgsrc/README-all.html',
++ @_
++ );
++
++ my $versions;
++ my $urls;
++
++ my $in = IO::Ftp-&gt;new('&lt;',$options{url}) or croak &quot;Can't fetch $options{url}: $!&quot;;
++ while (my $line = &lt;$in&gt;) {
++ next unless $line =~ /&lt;!-- (.+)-([^-]*?)(nb\d*)? \(for sorting\).*?href=&quot;([^&quot;]+)&quot;/;
++ my $name = $1;
++ my $version = $2;
++ $versions-&gt;{$name} = $version;
++ $urls-&gt;{$name} = $4;
++ }
++ close($in);
++
++ $self-&gt;{_versions} = $versions;
++ $self-&gt;{_urls} = $urls;
++ $self-&gt;{_url} = $options{url};
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return $self-&gt;{_urls}-&gt;{$name};
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/RAA.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/RAA.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/RAA.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,121 @@
++# $Id: RAA.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source::RAA;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::RAA - RAA updates source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++available from RAA.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use SOAP::Lite;
++use List::MoreUtils 'any';
++use Youri::Package;
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::RAA object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++URL to RAA SOAP interface (default:
++<A HREF="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.4">http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.4</A>)
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '<A HREF="http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.4/">http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.4/</A>',
++ @_
++ );
++
++ my $raa = SOAP::Lite-&gt;service($options{url})
++ or croak &quot;Can't connect to $options{url}&quot;;
++
++ $self-&gt;{_raa} = $raa;
++ $self-&gt;{_names} = $raa-&gt;names();
++}
++
++sub get_version {
++ my ($self, $package) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $name;
++ if (ref $package &amp;&amp; $package-&gt;isa('Youri::Package')) {
++ # don't bother checking for non-ruby packages
++ if (
++ any { $_-&gt;[Youri::Package::DEPENDENCY_NAME] =~ /ruby/ }
++ $package-&gt;get_requires()
++ ) {
++ $name = $package-&gt;get_canonical_name();
++ } else {
++ return;
++ }
++ } else {
++ $name = $package;
++ }
++
++ # translate in grabber namespace
++ $name = $self-&gt;get_name($name);
++
++ # return if aliased to null
++ return unless $name;
++
++ # susceptible to throw exception for timeout
++ eval {
++ my $gem = $self-&gt;{_raa}-&gt;gem($name);
++ return $gem-&gt;{project}-&gt;{version} if $gem;
++ };
++
++ return;
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return &quot;<A HREF="http://raa.ruby-lang.org/project/$name/">http://raa.ruby-lang.org/project/$name/</A>&quot;;
++}
++
++sub _name {
++ my ($self, $name) = @_;
++
++ if (ref $self) {
++ my $match = $name;
++ $match =~ s/^ruby[-_]//;
++ $match =~ s/[-_]ruby$//;
++ my @results =
++ grep { /^(ruby[-_])?\Q$match\E([-_]ruby)$/ }
++ @{$self-&gt;{_names}};
++ if (@results) {
++ return $results[0];
++ } else {
++ return $name;
++ }
++ } else {
++ return $name;
++ }
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Sourceforge.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Sourceforge.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source/Sourceforge.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,103 @@
++# $Id: Sourceforge.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source::Sourceforge;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source::Sourceforge - Sourceforge updates source
++
++=head1 DESCRIPTION
++
++This source plugin for L&lt;Youri::Check::Input::Updates&gt; collects updates
++available from Sourceforge.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use LWP::UserAgent;
++use HTML::TokeParser;
++use Youri::Check::Input::Updates;
++use base 'Youri::Check::Input::Updates::Source';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates::Source::Sourceforge
++object.
++
++No specific parameters.
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ @_
++ );
++
++ $self-&gt;{_agent} = LWP::UserAgent-&gt;new();
++}
++
++sub get_version {
++ my ($self, $package) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $name;
++ if (ref $package &amp;&amp; $package-&gt;isa('Youri::Package')) {
++ # don't bother checking for packages without sf.net URL
++ my $url = $package-&gt;get_url();
++ if (
++ $url =~ /http:\/\/(.*)\.sourceforge\.net/ ||
++ $url =~ /http:\/\/.*sourceforge\.net\/projects\/([^\/]+)/
++ ) {
++ $name = $package-&gt;get_canonical_name();
++ } else {
++ return;
++ }
++ } else {
++ $name = $package;
++ }
++
++ # translate in grabber namespace
++ $name = $self-&gt;get_name($name);
++
++ # return if aliased to null
++ return unless $name;
++
++ my $response = $self-&gt;{_agent}-&gt;get($self-&gt;_url($name));
++ if($response-&gt;is_success()) {
++ my $max = 0;
++ my $parser = HTML::TokeParser-&gt;new(\$response-&gt;content());
++ while (my $token = $parser-&gt;get_tag('a')) {
++ my $text = $parser-&gt;get_trimmed_text(&quot;/$token-&gt;[0]&quot;);
++ next unless $text;
++ next unless $text =~ /^
++ \Q$name\E
++ [._-]?($Youri::Check::Input::Updates::VERSION_REGEXP)
++ [._-]?(w(?:in)?(?:32)?|mips|sparc|bin|ppc|i\d86|src|sources?)?
++ \.(?:tar\.(?:gz|bz2)|tgz|zip)
++ $/iox;
++ my $version = $1;
++ my $arch = $2;
++ next if $arch &amp;&amp; $arch !~ /(src|sources?)/;
++ $max = $version if Youri::Check::Input::Updates::is_newer($version, $max);
++ }
++ return $max if $max;
++ }
++ return;
++}
++
++sub _url {
++ my ($self, $name) = @_;
++ return &quot;<A HREF="http://prdownloads.sourceforge.net/$name/">http://prdownloads.sourceforge.net/$name/</A>&quot;;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates/Source.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,240 @@
++# $Id: Source.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates::Source;
++
++=head1 NAME
++
++Youri::Check::Input::Updates::Source - Abstract updates source
++
++=head1 DESCRIPTION
++
++This abstract class defines the updates source interface for
++L&lt;Youri::Check::Input::Updates&gt;.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates object.
++
++Generic parameters (subclasses may define additional ones):
++
++=over
++
++=item aliases $aliases
++
++Hash of package aliases.
++
++=back
++
++Warning: do not call directly, call subclass constructor instead.
++
++=cut
++
++sub new {
++ my $class = shift;
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ id =&gt; '', # object id
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ aliases =&gt; undef, # aliases
++ resolver =&gt; undef, # maintainer resolver
++ preferences =&gt; undef, # maintainer preferences
++ check_id =&gt; '', # parent check id
++ @_
++ );
++
++ if ($options{aliases}) {
++ croak &quot;aliases should be an hashref&quot; unless ref $options{aliases} eq 'HASH';
++ }
++ if ($options{resolver}) {
++ croak &quot;resolver should be a Youri::Check::Maintainer::Resolver object&quot; unless $options{resolver}-&gt;isa(&quot;Youri::Check::Maintainer::Resolver&quot;);
++ }
++ if ($options{preferences}) {
++ croak &quot;preferences should be a Youri::Check::Maintainer::Preferences object&quot; unless $options{preferences}-&gt;isa(&quot;Youri::Check::Maintainer::Preferences&quot;);
++ }
++
++ my $self = bless {
++ _id =&gt; $options{id},
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ _aliases =&gt; $options{aliases},
++ _resolver =&gt; $options{resolver},
++ _preferences =&gt; $options{preferences},
++ _check_id =&gt; $options{check_id},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head1 INSTANCE METHODS
++
++Excepted explicit statement, package name is expressed with Mandriva naming
++conventions.
++
++=head2 get_id()
++
++Returns source identity.
++
++=cut
++
++sub get_id {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_id};
++}
++
++=head2 get_version($package)
++
++Returns available version for given package, which can be either a full
++L&lt;Youri::Package&gt; object or just a package name.
++
++=cut
++
++sub get_version {
++ my ($self, $package) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $name = ref $package &amp;&amp; $package-&gt;isa('Youri::Package') ?
++ $package-&gt;get_canonical_name() :
++ $package;
++
++ # translate in grabber namespace
++ $name = $self-&gt;get_name($name);
++
++ # return if aliased to null
++ return unless $name;
++
++ # return subclass computation
++ return $self-&gt;_version($name);
++}
++
++=head2 get_url($name)
++
++Returns the URL of information source for package with given name.
++
++=cut
++
++sub get_url {
++ my ($self, $name) = @_;
++
++ # retun subclass computation
++ return $self-&gt;_url($self-&gt;get_name($name));
++}
++
++=head2 name($name)
++
++Returns name converted to specific source naming conventions for package with given name.
++
++=cut
++
++sub get_name {
++ my ($self, $name) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # return config aliases if it exists
++ if ($self-&gt;{_aliases} ) {
++ return $self-&gt;{_aliases}-&gt;{$name} if exists $self-&gt;{_aliases}-&gt;{$name};
++ }
++
++ # return maintainer aliases if it exists
++ if ($self-&gt;{_resolver} &amp;&amp; $self-&gt;{_preferences}) {
++ my $maintainer = $self-&gt;{_resolver}-&gt;get_maintainer($name);
++ if ($maintainer) {
++ my $aliases = $self-&gt;{_preferences}-&gt;get_preference(
++ $maintainer,
++ $self-&gt;{_check_id},
++ 'aliases'
++ );
++ if ($aliases) {
++ if ($aliases-&gt;{all}) {
++ return $aliases-&gt;{all}-&gt;{$name} if exists $aliases-&gt;{all}-&gt;{$name};
++ }
++ if ($aliases-&gt;{$self-&gt;{_id}}) {
++ return $aliases-&gt;{$self-&gt;{_id}}-&gt;{$name} if exists $aliases-&gt;{$self-&gt;{_id}}-&gt;{$name};
++ }
++ }
++ }
++ }
++
++ # return return subclass computation
++ return $self-&gt;_name($name);
++}
++
++=head2 _version($name)
++
++Hook called by default B&lt;version()&gt; implementation after name translation.
++
++=cut
++
++sub _version {
++ my ($self, $name) = @_;
++ return $self-&gt;{_versions}-&gt;{$name};
++}
++
++=head2 _url($name)
++
++Hook called by default B&lt;url()&gt; implementation after name translation.
++
++=cut
++
++sub _url {
++ my ($self, $name) = @_;
++ return undef;
++}
++
++=head2 _name($name)
++
++Hook called by default B&lt;name()&gt; implementation if given name was not found in
++the aliases.
++
++=cut
++
++sub _name {
++ my ($self, $name) = @_;
++ return $name;
++}
++
++=head1 SUBCLASSING
++
++The following methods have to be implemented:
++
++=over
++
++=item version
++
++As an alternative, the B&lt;_version()&gt; hook can be implemented.
++
++=item url
++
++As an alternative, the &lt;_url()&gt; hook can be implemented.
++
++=item name
++
++As an alternative, the B&lt;_name()&gt; hook can be implemented.
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input/Updates.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,275 @@
++# $Id: Updates.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input::Updates;
++
++=head1 NAME
++
++Youri::Check::Input::Updates - Check available updates
++
++=head1 DESCRIPTION
++
++This plugin checks available updates for packages, and report existing ones.
++Additional source plugins handle specific sources.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Memoize;
++use Youri::Utils;
++use base 'Youri::Check::Input';
++
++sub columns {
++ return qw/
++ current
++ available
++ source
++ /;
++}
++
++sub links {
++ return qw/
++ source url
++ /;
++}
++
++memoize('is_newer');
++
++our $VERSION_REGEXP = 'v?([\d._-]*\d)[._ -]*(?:(alpha|beta|pre|rc|pl|rev|cvs|svn|[a-z])[_ -.]*([\d.]*))?([_ -.]*.*)';
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input::Updates object.
++
++Specific parameters:
++
++=over
++
++=item aliases $aliases
++
++Hash of global aliases definitions
++
++=item sources $sources
++
++Hash of source plugins definitions
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ aliases =&gt; undef,
++ sources =&gt; undef,
++ @_
++ );
++
++ croak &quot;No source defined&quot; unless $options{sources};
++ croak &quot;sources should be an hashref&quot; unless ref $options{sources} eq 'HASH';
++ if ($options{aliases}) {
++ croak &quot;aliases should be an hashref&quot; unless ref $options{aliases} eq 'HASH';
++ }
++
++ foreach my $id (keys %{$options{sources}}) {
++ print &quot;Creating source $id\n&quot; if $options{verbose};
++ eval {
++ # add global aliases if defined
++ if ($options{aliases}) {
++ foreach my $alias (keys %{$options{aliases}}) {
++ $options{sources}-&gt;{$id}-&gt;{aliases}-&gt;{$alias} =
++ $options{aliases}-&gt;{$alias}
++ }
++ }
++
++ push(
++ @{$self-&gt;{_sources}},
++ create_instance(
++ 'Youri::Check::Input::Updates::Source',
++ id =&gt; $id,
++ test =&gt; $options{test},
++ verbose =&gt; $options{verbose},
++ check_id =&gt; $options{id},
++ resolver =&gt; $options{resolver},
++ preferences =&gt; $options{preferences},
++ %{$options{sources}-&gt;{$id}}
++ )
++ );
++ };
++ print STDERR &quot;Failed to create source $id: $@\n&quot; if $@;
++ }
++
++ croak &quot;no sources created&quot; unless @{$self-&gt;{_sources}};
++}
++
++sub run {
++ my ($self, $media, $resultset) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # this is a source media check only
++ return unless $media-&gt;get_type() eq 'source';
++
++ my $callback = sub {
++ my ($package) = @_;
++
++ my $name = $package-&gt;get_name();
++ my $version = $package-&gt;get_version();
++ my $release = $package-&gt;get_release();
++
++ # compute version with rpm subtilities related to preversions
++ my $current_version = ($release =~ /^0\.(\w+)\.\w+$/) ?
++ $version . $1 :
++ $version;
++ my $current_stable = is_stable($current_version);
++
++ my ($max_version, $max_source, $max_url);
++ $max_version = $current_version;
++
++ foreach my $source (@{$self-&gt;{_sources}}) {
++ my $available_version = $source-&gt;get_version($package);
++ if (
++ $available_version &amp;&amp;
++ (! $current_stable || is_stable($available_version)) &amp;&amp;
++ is_newer($available_version, $max_version)
++ ) {
++ $max_version = $available_version;
++ $max_source = $source-&gt;get_id();
++ $max_url = $source-&gt;get_url($name);
++ }
++ }
++ $resultset-&gt;add_result($self-&gt;{_id}, $media, $package, {
++ current =&gt; $current_version,
++ available =&gt; $max_version,
++ source =&gt; $max_source,
++ url =&gt; $max_url
++ }) if $max_version ne $current_version;
++ };
++
++ $media-&gt;traverse_headers($callback);
++}
++
++=head2 is_stable($version)
++
++Checks if given version is stable.
++
++=cut
++
++sub is_stable {
++ my ($version) = @_;
++ return $version !~ /alpha|beta|pre|rc|cvs|svn/i;
++
++}
++
++=head2 is_newer($v1, $v2)
++
++Checks if $v1 is newer than $v2.
++
++This function will return true only if we are sure this is newer (and not equal).
++If we can't compare the versions, a warning will be displayed.
++
++=cut
++
++sub is_newer {
++ my ($v1, $v2) = @_;
++ return 0 if $v1 eq $v2;
++
++ # Reject strange cases
++ # One is a large number (like date or revision) and the other one not, or
++ # has different length
++ if (($v1 =~ /^\d{3,}$/ || $v2 =~ /^\d{3,}$/)
++ &amp;&amp; (join('0',split(/\d/, $v1.&quot;X&quot;)) ne join('0',split(/\d/, $v2.&quot;X&quot;)))) {
++ carp &quot;strange : $v1 vs $v2&quot;;
++ return 0;
++ }
++
++ my %states = (alpha=&gt;-4,beta=&gt;-3,pre=&gt;-2,rc=&gt;-1);
++ my $i; $states{$_} = ++$i foreach 'a'..'z';
++
++ if ($v1 =~ /^[\d._-]+$/ &amp;&amp; $v2 =~ /^[\d._-]+$/) {
++ my @v1 = split(/[._-]/, $v1);
++ my @v2 = split(/[._-]/, $v2);
++ if (join(''<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">, at v1</A>) eq (join ''<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">, at v2</A>)) {
++ # Might be something like 1.2.0 vs 1.20, usual false positive
++ carp &quot;strange : $v1 vs $v2&quot;;
++ return 0;
++ }
++ for my $i (0 .. $#v1) {
++ $v1[$i] ||= 0;
++ $v2[$i] ||= 0;
++ return 1 if $v1[$i] &gt; $v2[$i];
++ return 0 if $v1[$i] &lt; $v2[$i];
++ }
++ # When v2 is longer than v1 but start the same, v1 &lt;= v2
++ return 0;
++ } else {
++ my ($num1, $state1, $statenum1, $other1, $num2, $state2, $statenum2, $other2);
++
++ if ($v1 =~ /^$VERSION_REGEXP$/io) {
++ ($num1, $state1, $statenum1, $other1) = ($1, &quot;\L$2&quot;, $3, $4);
++ } else {
++ carp &quot;unknown version format $v1&quot;;
++ return 0;
++ }
++
++ if ($v2 =~ /^$VERSION_REGEXP$/io) {
++ ($num2, $state2, $statenum2, $other2) = ($1, &quot;\L$2&quot;, $3, $4);
++ } else {
++ carp &quot;unknown version format $v2&quot;;
++ return 0;
++ }
++
++ # If we know the format of only one, there might be an issue, do nothing
++
++ if (($other1 &amp;&amp; ! $other2 )||(!$other1 &amp;&amp; $other2 )) {
++ carp &quot;can't compare $v1 vs $v2&quot;;
++ return 0;
++ }
++
++ return 1 if is_newer($num1, $num2);
++ return 0 unless $num1 eq $num2;
++
++ # The numeric part is the same but not the end
++
++ if ($state1 eq '') {
++ return 1 if $state2 =~ /^(alpha|beta|pre|rc)/;
++ return 0 if $state2 =~ /^([a-z]|pl)$/;
++ carp &quot;unknown state format $state2&quot;;
++ return 0;
++ }
++
++ if ($state2 eq '') {
++ return 0 if $state1 =~ /^(alpha|beta|pre|rc)/;
++ return 1 if $state1 =~ /^([a-z]|pl)$/;
++ carp &quot;unknown state format $state1&quot;;
++ return 0;
++ }
++
++ if ($state1 eq $state2) {
++ return 1 if is_newer($statenum1, $statenum2);
++ return 0 unless $statenum1 eq $statenum2;
++ # If everything is the same except this, just compare it
++ # as we have no idea on the format
++ return &quot;$other1&quot; gt &quot;$other2&quot;;
++ }
++
++ my $s1 = 0;
++ my $s2 = 0;
++ $s1=$states{$state1} if exists $states{$state1};
++ $s2=$states{$state2} if exists $states{$state2};
++ return $s1&gt;$s2 if ($s1 != 0 &amp;&amp; $s2 != 0);
++ return 1 if $s1&lt;0 &amp;&amp; $state2 =~ /^([a-z]|pl)$/;
++ return 0 if $s2&lt;0 &amp;&amp; $state1 =~ /^([a-z]|pl)$/;
++ carp &quot;unknown case $v1, $v2&quot;;
++ return 0;
++ }
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Input.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Input.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Input.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,120 @@
++# $Id: Input.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Input;
++
++=head1 NAME
++
++Youri::Check::Input - Abstract input plugin
++
++=head1 DESCRIPTION
++
++This abstract class defines input plugin interface.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Utils;
++
++use constant WARNING =&gt; 'warning';
++use constant ERROR =&gt; 'error';
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Input 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 &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ id =&gt; '', # object id
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ resolver =&gt; undef, # maintainer resolver
++ preferences =&gt; undef, # maintainer preferences
++ @_
++ );
++
++ if ($options{resolver}) {
++ croak &quot;resolver should be a Youri::Check::Maintainer::Resolver object&quot; unless $options{resolver}-&gt;isa(&quot;Youri::Check::Maintainer::Resolver&quot;);
++ }
++ if ($options{preferences}) {
++ croak &quot;preferences should be a Youri::Check::Maintainer::Preferences object&quot; unless $options{preferences}-&gt;isa(&quot;Youri::Check::Maintainer::Preferences&quot;);
++ }
++
++ my $self = bless {
++ _id =&gt; $options{id},
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ _resolver =&gt; $options{resolver},
++ _preferences =&gt; $options{preferences},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head1 INSTANCE METHODS
++
++=head2 get_id()
++
++Returns plugin identity.
++
++=cut
++
++sub get_id {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_id};
++}
++
++=head2 prepare(@medias)
++
++Perform optional preliminary initialisation, using given list of
++&lt;Youri::Media&gt; objects.
++
++=cut
++
++sub prepare {
++ # do nothing
++}
++
++=head2 run($media, $resultset)
++
++Check the packages from given L&lt;Youri::Media&gt; object, and store the
++result in given L&lt;Youri::Check::Resultset&gt; 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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences/File.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences/File.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences/File.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,87 @@
++# $Id: File.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Maintainer::Preferences::File;
++
++=head1 NAME
++
++Youri::Check::Maintainer::Preferences::File - File-based maintainer preferences implementation
++
++=head1 DESCRIPTION
++
++This is a file-based L&lt;Youri::Check::Maintainer::Preferences&gt; implementation.
++
++It uses files in maintainer home directories.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Config;
++use base 'Youri::Check::Maintainer::Preferences';
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Maintainer::Preferences::File object.
++
++No specific parameters.
++
++=cut
++
++sub get_preference {
++ my ($self, $maintainer, $plugin, $value) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ return unless $maintainer &amp;&amp; $plugin &amp;&amp; $value;
++
++ print &quot;Retrieving maintainer $maintainer preferences\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ $self-&gt;_load_config($maintainer)
++ unless exists $self-&gt;{_config}-&gt;{$maintainer};
++
++ return $self-&gt;{_config}-&gt;{$maintainer} ?
++ $self-&gt;{_config}-&gt;{$maintainer}-&gt;get($plugin . '_' . $value) :
++ undef;
++}
++
++sub _load_config {
++ my ($self, $maintainer) = @_;
++
++ print &quot;Attempting to load maintainers preferences for $maintainer\n&quot; if $self-&gt;{_verbose} &gt; 1;
++
++
++ my ($login) = $maintainer =~ /^(\S+)\@\S+$/;
++ my $home = (getpwnam($login))[7];
++ my $file = &quot;$home/.youri/check.prefs&quot;;
++
++ if (-f $file &amp;&amp; -r $file) {
++ print &quot;Found, loading\n&quot; if $self-&gt;{_verbose} &gt; 1;
++ my $config = Youri::Config-&gt;new(
++ {
++ CREATE =&gt; 1,
++ GLOBAL =&gt; {
++ DEFAULT =&gt; undef,
++ EXPAND =&gt; EXPAND_VAR | EXPAND_ENV,
++ ARGCOUNT =&gt; ARGCOUNT_ONE,
++ }
++ }
++ );
++ $config-&gt;file($file);
++ $self-&gt;{_config}-&gt;{$maintainer} = $config;
++ } else {
++ print &quot;Not found, aborting\n&quot; if $self-&gt;{_verbose} &gt; 1;
++ $self-&gt;{_config}-&gt;{$maintainer} = undef;
++ }
++
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Preferences.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,80 @@
++# $Id: Preferences.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Maintainer::Preferences;
++
++=head1 NAME
++
++Youri::Check::Maintainer::Preferences - Abstract maintainer preferences
++
++=head1 DESCRIPTION
++
++This abstract class defines Youri::Check::Maintainer::Preferences interface.
++
++=head1 SYNOPSIS
++
++ use Youri::Check::Maintainer::Preferences::Foo;
++
++ my $preferences = Youri::Check::Maintainer::Preferences::Foo-&gt;new();
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Maintainer::Preferences object.
++
++Warning: do not call directly, call subclass constructor instead.
++
++=cut
++
++sub new {
++ my $class = shift;
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ @_
++ );
++
++ my $self = bless {
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head2 get_preference($maintainer, $plugin, $item)
++
++Returns preference of given maintainer for given plugin and configuration item.
++
++=head1 SUBCLASSING
++
++The following methods have to be implemented:
++
++=over
++
++=item get
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/Bugzilla.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/Bugzilla.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/Bugzilla.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,100 @@
++# $Id: Bugzilla.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Maintainer::Resolver::Bugzilla;
++
++=head1 NAME
++
++Youri::Check::Maintainer::Resolver::Bugzilla - Bugzilla-based maintainer resolver
++
++=head1 DESCRIPTION
++
++This is a Bugzilla-based L&lt;Youri::Check::Maintainer::Resolver&gt; implementation.
++
++It uses Bugzilla SQL database for resolving maintainers.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Bugzilla;
++use base 'Youri::Check::Maintainer::Resolver';
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Maintainer::Resolver::Bugzilla object.
++
++Specific parameters:
++
++=over
++
++=item host $host
++
++Bugzilla database host.
++
++=item base $base
++
++Bugzilla database name.
++
++=item user $user
++
++Bugzilla database user.
++
++=item pass $pass
++
++Bugzilla database password.
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ host =&gt; '', # host of the bug database
++ base =&gt; '', # name of the bug database
++ user =&gt; '', # user of the bug database
++ pass =&gt; '', # pass of the bug database
++ @_
++ );
++
++ croak &quot;No host given&quot; unless $options{host};
++ croak &quot;No base given&quot; unless $options{base};
++ croak &quot;No user given&quot; unless $options{user};
++ croak &quot;No pass given&quot; unless $options{pass};
++
++ my $bugzilla = Youri::Bugzilla-&gt;new(
++ $options{host},
++ $options{base},
++ $options{user},
++ $options{pass}
++ );
++
++ $self-&gt;{_bugzilla} = $bugzilla;
++}
++
++sub get_maintainer {
++ my ($self, $package) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $name = ref $package &amp;&amp; $package-&gt;isa('Youri::Package') ?
++ $package-&gt;get_canonical_name() :
++ $package;
++
++ $self-&gt;{_maintainers}-&gt;{$name} =
++ $self-&gt;{_bugzilla}-&gt;get_maintainer($name)
++ unless exists $self-&gt;{_maintainers}-&gt;{$name};
++
++ return $self-&gt;{_maintainers}-&gt;{$name};
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/CGI.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/CGI.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver/CGI.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,79 @@
++# $Id: CGI.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Maintainer::Resolver::CGI;
++
++=head1 NAME
++
++Youri::Check::Maintainer::Resolver::CGI - CGI-based maintainer resolver
++
++=head1 DESCRIPTION
++
++This is a CGI-based L&lt;Youri::Check::Maintainer::Resolver&gt; implementation.
++
++It uses a remote CGI to resolve maintainers.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Maintainer::Resolver';
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Maintainer::Resolver::CGI object.
++
++Specific parameters:
++
++=over
++
++=item url $url
++
++CGI's URL.
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ url =&gt; '', # url to fetch maintainers
++ @_
++ );
++
++ croak &quot;No URL given&quot; unless $options{url};
++
++ open (INPUT, &quot;GET $options{url} |&quot;);
++ while (&lt;INPUT&gt;) {
++ chomp;
++ my ($package, $maintainer) = split(/\t/, $_);
++ $self-&gt;{_maintainers}-&gt;{$package} = $maintainer if $maintainer;
++ }
++ close(INPUT);
++}
++
++sub get_maintainer {
++ my ($self, $package) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ print &quot;Retrieving package $package maintainer\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ my $name = ref $package &amp;&amp; $package-&gt;isa('Youri::Package') ?
++ $package-&gt;get_canonical_name() :
++ $package;
++
++ return $self-&gt;{_maintainers}-&gt;{$name};
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Maintainer/Resolver.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,86 @@
++# $Id: Resolver.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Maintainer::Resolver;
++
++=head1 NAME
++
++Youri::Check::Maintainer::Resolver - Abstract maintainer resolver
++
++=head1 DESCRIPTION
++
++This abstract class defines Youri::Check::Maintainer::Resolver interface.
++
++=head1 SYNOPSIS
++
++ use Youri::Check::Maintainer::Resolver::Foo;
++
++ my $resolver = Youri::Check::Maintainer::Resolver::Foo-&gt;new();
++
++ print $resolver-&gt;get_maintainer('foo');
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Utils;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Maintainer::Resolver 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 &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ @_
++ );
++
++ my $self = bless {
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose}
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head2 get_maintainer($package)
++
++Returns maintainer for given package, which can be either a full
++L&lt;Youri::Package&gt; object or just a package name.
++
++=head1 SUBCLASSING
++
++The following methods have to be implemented:
++
++=over
++
++=item get_maintainer
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/HTML.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/HTML.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/HTML.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,222 @@
++# $Id: HTML.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Output::File::Format::HTML;
++
++=head1 NAME
++
++Youri::Check::Output::File::Format::HTML - File HTML format support
++
++=head1 DESCRIPTION
++
++This format plugin for L&lt;Youri::Check::Output::File&gt; provides HTML format
++support.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use CGI;
++use base 'Youri::Check::Output::File::Format';
++
++sub extension {
++ return 'html';
++}
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ style =&gt; &lt;&lt;EOF, # css style
++h1 {
++ text-align:center;
++}
++table {
++ border-style:solid;
++ border-width:1px;
++ border-color:black;
++ width:100%;
++}
++tr.odd {
++ background-color:white;
++}
++tr.even {
++ background-color:silver;
++}
++p.footer {
++ font-size:smaller;
++ text-align:center;
++}
++EOF
++ @_
++ );
++
++ $self-&gt;{_style} = $options{style};
++ $self-&gt;{_cgi} = CGI-&gt;new();
++}
++
++sub get_report {
++ my ($self, $time, $title, $iterator, $type, $columns, $links, $maintainer) = @_;
++
++ my $content;
++ my $lead_columns = [
++ $maintainer ?
++ qw/package media/ :
++ qw/package media maintainer/
++ ];
++ my $line;
++ my @results;
++ $content .= $self-&gt;{_cgi}-&gt;start_table();
++ $content .= $self-&gt;{_cgi}-&gt;Tr([
++ $self-&gt;{_cgi}-&gt;th([
++ @$lead_columns,
++ @$columns
++ ])
++ ]);
++ while (my $result = $iterator-&gt;get_result()) {
++ if (@results &amp;&amp; $result-&gt;{package} ne $results[0]-&gt;{package}) {
++ $content .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ $links,
++ $line++ % 2 ? 'odd' : 'even',
++ \@results
++ );
++ @results = ();
++ }
++ push(@results, $result);
++ }
++ $content .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ $links,
++ $line++ % 2 ? 'odd' : 'even',
++ \@results
++ );
++ $content .= $self-&gt;{_cgi}-&gt;end_table();
++
++ return $self-&gt;_get_html_page($time, $title, \$content);
++}
++
++sub get_index {
++ my ($self, $time, $title, $reports, $maintainers) = @_;
++
++ my $content;
++
++ if ($reports) {
++ $content .= $self-&gt;{_cgi}-&gt;h2(&quot;Reports&quot;);
++ my @types = keys %{$reports};
++
++ $content .= $self-&gt;{_cgi}-&gt;start_ul();
++ foreach my $type (sort @types) {
++ my $item;
++ $item = $self-&gt;{_cgi}-&gt;a(
++ { href =&gt; &quot;$type.html&quot; },
++ $type
++ );
++ foreach my $extension (@{$reports-&gt;{$type}}) {
++ next if ($extension eq extension());
++ $item .= &quot; &quot;.$self-&gt;{_cgi}-&gt;a(
++ { href =&gt; &quot;$type.$extension&quot; },
++ &quot;[$extension]&quot;
++ );
++ }
++ $content .= $self-&gt;{_cgi}-&gt;li($item);
++ }
++ $content .= $self-&gt;{_cgi}-&gt;end_ul();
++ }
++
++ if ($maintainers) {
++ $content .= $self-&gt;{_cgi}-&gt;h2(&quot;Individual reports&quot;);
++
++ $content .= $self-&gt;{_cgi}-&gt;start_ul();
++ foreach my $maintainer (sort @{$maintainers}) {
++ $content .= $self-&gt;{_cgi}-&gt;li(
++ $self-&gt;{_cgi}-&gt;a(
++ { href =&gt; &quot;$maintainer/index.html&quot; },
++ _obfuscate($maintainer)
++ )
++ );
++ }
++ $content .= $self-&gt;{_cgi}-&gt;end_ul();
++ }
++
++ return $self-&gt;_get_html_page($time, $title, \$content);
++}
++
++sub _get_formated_results {
++ my ($self, $lead_columns, $columns, $links, $class, $results) = @_;
++
++ my $content;
++ $content .= $self-&gt;{_cgi}-&gt;end_Tr();
++ for my $i (0 .. $#$results) {
++ $content .= $self-&gt;{_cgi}-&gt;start_Tr(
++ { class =&gt; $class }
++ );
++ if ($i == 0) {
++ # first line contains spanned cells
++ $content .= $self-&gt;{_cgi}-&gt;td(
++ { rowspan =&gt; scalar @$results },
++ [
++ map { $results-&gt;[$i]-&gt;{$_} }
++ @$lead_columns
++ ]
++ );
++ }
++ $content .= $self-&gt;{_cgi}-&gt;td(
++ [
++ map {
++ $links-&gt;{$_} &amp;&amp; $results-&gt;[$i]-&gt;{$links-&gt;{$_}} ?
++ $self-&gt;{_cgi}-&gt;a(
++ { href =&gt; $results-&gt;[$i]-&gt;{$links-&gt;{$_}} },
++ $self-&gt;{_cgi}-&gt;escapeHTML($results-&gt;[$i]-&gt;{$_})
++ ) :
++ $self-&gt;{_cgi}-&gt;escapeHTML($results-&gt;[$i]-&gt;{$_})
++ } @$columns
++ ]
++ );
++ $content .= $self-&gt;{_cgi}-&gt;end_Tr();
++ }
++
++ return $content;
++}
++
++
++sub _get_html_page {
++ my ($self, $time, $title, $body) = @_;
++
++ my $content;
++ $content .= $self-&gt;{_cgi}-&gt;start_html(
++ -title =&gt; $title,
++ -style =&gt; { code =&gt; $self-&gt;{_style} }
++ );
++ $content .= $self-&gt;{_cgi}-&gt;h1($title);
++ $content .= $$body;
++ $content .= $self-&gt;{_cgi}-&gt;hr();
++ $content .= $self-&gt;{_cgi}-&gt;p(
++ { class =&gt; 'footer' },
++ &quot;Page generated $time&quot;
++ );
++ $content .= $self-&gt;{_cgi}-&gt;end_html();
++
++ return \$content;
++}
++
++sub _obfuscate {
++ my ($email) = @_;
++
++ return unless $email;
++
++ $email =~ s/\@/ at /;
++ $email =~ s/\./ dot /;
++
++ return $email;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/RSS.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/RSS.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/RSS.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,68 @@
++# $Id$
++package Youri::Check::Output::File::Format::RSS;
++
++=head1 NAME
++
++Youri::Check::Output::File::Format::RSS - File RSS format support
++
++=head1 DESCRIPTION
++
++This format plugin for L&lt;Youri::Check::Output::File&gt; provides RSS format
++support.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use XML::RSS;
++use base 'Youri::Check::Output::File::Format';
++
++sub extension {
++ return 'rss';
++}
++
++sub get_report {
++ my ($self, $time, $title, $iterator, $type, $columns, $links, $maintainer) = @_;
++
++ return unless $maintainer;
++
++ my $rss = new XML::RSS (version =&gt; '2.0');
++ $rss-&gt;channel(
++ title =&gt; $title,
++ description =&gt; $title,
++ language =&gt; 'en',
++ ttl =&gt; 1440
++ );
++
++ while (my $result = $iterator-&gt;get_result()) {
++ if ($type eq 'updates') {
++ $rss-&gt;add_item(
++ title =&gt; &quot;$result-&gt;{package} $result-&gt;{available} is available&quot;,
++ description =&gt; &quot;Current version is $result-&gt;{current}&quot;,
++ link =&gt; $result-&gt;{url} ?
++ $result-&gt;{url} : $result-&gt;{source},
++ guid =&gt; &quot;$result-&gt;{package}-$result-&gt;{available}&quot;
++ );
++ } else {
++ $rss-&gt;add_item(
++ title =&gt; &quot;[$type] $result-&gt;{package}&quot;,
++ description =&gt; join(&quot;\n&quot;, (map { $result-&gt;{$_} || '' } @$columns)),
++ link =&gt; $result-&gt;{url},
++ guid =&gt; &quot;$type-$result-&gt;{package}&quot;
++ );
++ }
++ }
++
++ return \$rss-&gt;as_string();
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/Text.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/Text.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format/Text.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,88 @@
++# $Id: Text.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Output::File::Format::Text;
++
++=head1 NAME
++
++Youri::Check::Output::File::Format::Text - File text format support
++
++=head1 DESCRIPTION
++
++This format plugin for L&lt;Youri::Check::Output::File&gt; provides text format
++support.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Output::File::Format';
++
++sub extension {
++ return 'txt';
++}
++
++sub get_report {
++ my ($self, $time, $title, $iterator, $type, $columns, $links, $maintainer) = @_;
++
++ my $content;
++ $content .= $title;
++ $content .= &quot;\n&quot;;
++
++ my $lead_columns = [
++ $maintainer ?
++ qw/package media/ :
++ qw/package media maintainer/
++ ];
++ my @results;
++ $content .= join(&quot;\t&quot;, @$lead_columns, @$columns) . &quot;\n&quot;;
++ while (my $result = $iterator-&gt;get_result()) {
++ if (@results &amp;&amp; $result-&gt;{package} ne $results[0]-&gt;{package}) {
++ $content .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ \@results
++ );
++ @results = ();
++ }
++ push(@results, $result);
++ }
++ $content .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ \@results
++ );
++
++ $content .= &quot;\n&quot;;
++ $content .= &quot;Page generated $time\n&quot;;
++
++ return \$content;
++}
++
++sub _get_formated_results {
++ my ($self, $lead_columns, $columns, $results) = @_;
++
++ my $content;
++ $content .= join(
++ &quot;\t&quot;,
++ (map { $results-&gt;[0]-&gt;{$_} || '' } @$lead_columns),
++ (map { $results-&gt;[0]-&gt;{$_} || '' } @$columns)
++ ) . &quot;\n&quot;;
++ for my $i (1 .. $#$results) {
++ $content .= join(
++ &quot;\t&quot;,
++ (map { '' } @$lead_columns),
++ (map { $results-&gt;[$i]-&gt;{$_} || '' } @$columns)
++ ) . &quot;\n&quot;;
++ }
++ return $content;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File/Format.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,66 @@
++# $Id: Base.pm 579 2006-01-09 21:17:54Z guillomovitch $
++package Youri::Check::Output::File::Format;
++
++=head1 NAME
++
++Youri::Check::Output::File::Format - Abstract file format support
++
++=head1 DESCRIPTION
++
++This abstract class defines the format support interface for
++L&lt;Youri::Check::Output::File&gt;.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++
++sub new {
++ my $class = shift;
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ id =&gt; '',
++ test =&gt; 0,
++ verbose =&gt; 0,
++ @_
++ );
++
++ my $self = bless {
++ _id =&gt; $options{id},
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head2 get_id()
++
++Returns format handler identity.
++
++=cut
++
++sub get_id {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_id};
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/File.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,203 @@
++# $Id: Text.pm 523 2005-10-11 08:36:49Z misc $
++package Youri::Check::Output::File;
++
++=head1 NAME
++
++Youri::Check::Output::File - Report results in files
++
++=head1 DESCRIPTION
++
++This plugin reports results in files. Additional subplugins handle specific
++formats.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use File::Basename;
++use File::Path;
++use DateTime;
++use Youri::Utils;
++use base 'Youri::Check::Output';
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ to =&gt; '', # target directory
++ noclean =&gt; 0, # don't clean up target directory
++ noempty =&gt; 0, # don't generate empty reports
++ formats =&gt; undef,
++ @_
++ );
++
++ croak &quot;no format defined&quot; unless $options{formats};
++ croak &quot;formats should be an hashref&quot; unless ref $options{formats} eq 'HASH';
++
++ my $now = DateTime-&gt;now(time_zone =&gt; 'local');
++ my $time = &quot;the &quot; . $now-&gt;ymd() . &quot; at &quot; . $now-&gt;hms();
++
++ $self-&gt;{_to} = $options{to};
++ $self-&gt;{_noclean} = $options{noclean};
++ $self-&gt;{_noempty} = $options{noempty};
++ $self-&gt;{_time} = $time;
++
++ foreach my $id (keys %{$options{formats}}) {
++ print &quot;Creating format $id\n&quot; if $options{verbose};
++ eval {
++ push(
++ @{$self-&gt;{_formats}},
++ create_instance(
++ 'Youri::Check::Output::File::Format',
++ id =&gt; $id,
++ test =&gt; $options{test},
++ verbose =&gt; $options{verbose},
++ %{$options{formats}-&gt;{$id}}
++ )
++ );
++ };
++ print STDERR &quot;Failed to create format $id: $@\n&quot; if $@;
++ }
++
++ croak &quot;no formats created&quot; unless @{$self-&gt;{_formats}};
++}
++
++sub _init_report {
++ my ($self) = @_;
++
++ # clean up output directory
++ unless ($self-&gt;{_test} || $self-&gt;{_noclean} || !$self-&gt;{_to}) {
++ my @files = glob($self-&gt;{_to} . '/*');
++ rmtree(\@files) if @files;
++ }
++}
++
++sub _global_report {
++ my ($self, $resultset, $type, $columns, $links) = @_;
++
++ foreach my $format (@{$self-&gt;{_formats}}) {
++ my $iterator = $resultset-&gt;get_iterator(
++ $type,
++ [ 'package' ]
++ );
++
++ return if $self-&gt;{_noempty} &amp;&amp; ! $iterator-&gt;has_results();
++
++ my $content = $format-&gt;get_report(
++ $self-&gt;{_time},
++ &quot;$type global report&quot;,
++ $iterator,
++ $type,
++ $columns,
++ $links,
++ undef
++ );
++
++ # create and register file
++ my $extension = $format-&gt;extension();
++ $self-&gt;_write_file(
++ &quot;$self-&gt;{_to}/$type.$extension&quot;,
++ $content
++ );
++ push(
++ @{$self-&gt;{_files}-&gt;{global}-&gt;{$type}},
++ $extension
++ );
++ }
++}
++
++sub _individual_report {
++ my ($self, $resultset, $type, $columns, $links, $maintainer) = @_;
++
++ foreach my $format (@{$self-&gt;{_formats}}) {
++ my $iterator = $resultset-&gt;get_iterator(
++ $type,
++ [ 'package' ],
++ { maintainer =&gt; [ $maintainer ] }
++ );
++
++ return if $self-&gt;{_noempty} &amp;&amp; ! $iterator-&gt;has_results();
++
++ my $content = $format-&gt;get_report(
++ $self-&gt;{_time},
++ &quot;$type individual report for $maintainer&quot;,
++ $iterator,
++ $type,
++ $columns,
++ $links,
++ $maintainer
++ );
++
++ # create and register file
++ my $extension = $format-&gt;extension();
++ $self-&gt;_write_file(
++ &quot;$self-&gt;{_to}/$maintainer/$type.$extension&quot;,
++ $content
++ );
++ push(
++ @{$self-&gt;{_files}-&gt;{maintainers}-&gt;{$maintainer}-&gt;{$type}},
++ $extension
++ );
++ }
++}
++
++sub _finish_report {
++ my ($self, $types, $maintainers) = @_;
++
++ foreach my $format (@{$self-&gt;{_formats}}) {
++ next unless $format-&gt;can('get_index');
++ my $extension = $format-&gt;extension();
++ print STDERR &quot;writing global index page\n&quot; if $self-&gt;{_verbose};
++ $self-&gt;_write_file(
++ &quot;$self-&gt;{_to}/index.$extension&quot;,
++ $format-&gt;get_index(
++ $self-&gt;{_time},
++ &quot;QA global report&quot;,
++ $self-&gt;{_files}-&gt;{global},
++ [ keys %{$self-&gt;{_files}-&gt;{maintainers}} ],
++ )
++ );
++ foreach my $maintainer (@$maintainers) {
++ print STDERR &quot;writing index page for $maintainer\n&quot; if $self-&gt;{_verbose};
++
++ $self-&gt;_write_file(
++ &quot;$self-&gt;{_to}/$maintainer/index.$extension&quot;,
++ $format-&gt;get_index(
++ $self-&gt;{_time},
++ &quot;QA report for $maintainer&quot;,
++ $self-&gt;{_files}-&gt;{maintainers}-&gt;{$maintainer},
++ undef,
++ )
++ );
++ }
++ }
++}
++
++sub _write_file {
++ my ($self, $file, $content) = @_;
++
++ return unless $content;
++
++ my $dirname = dirname($file);
++ mkpath($dirname) unless -d $dirname;
++
++ if ($self-&gt;{_test}) {
++ *OUT = *STDOUT;
++ } else {
++ open(OUT, &quot;&gt;$file&quot;) or die &quot;Can't open file $file: $!&quot;;
++ }
++
++ print OUT $$content;
++
++ close(OUT) unless $self-&gt;{_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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/HTML.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/HTML.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/HTML.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,158 @@
++# $Id: Mail.pm 580 2006-01-11 22:59:36Z guillomovitch $
++package Youri::Check::Output::Mail::Format::HTML;
++
++=head1 NAME
++
++Youri::Check::Output::Mail::Format::HTML - Mail HTML format support
++
++=head1 DESCRIPTION
++
++This format plugin for L&lt;Youri::Check::Output::Mail&gt; provides HTML format
++support.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use CGI;
++use base 'Youri::Check::Output::Mail::Format';
++
++sub type {
++ return 'text/html';
++}
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ style =&gt; &lt;&lt;EOF, # css style
++h1 {
++ text-align:center;
++}
++table {
++ border-style:solid;
++ border-width:1px;
++ border-color:black;
++ width:100%;
++}
++tr.odd {
++ background-color:white;
++}
++tr.even {
++ background-color:silver;
++}
++p.footer {
++ font-size:smaller;
++ text-align:center;
++}
++EOF
++ @_
++ );
++
++ $self-&gt;{_style} = $options{style};
++ $self-&gt;{_cgi} = CGI-&gt;new();
++}
++
++sub get_report {
++ my ($self, $time, $title, $iterator, $type, $columns, $links, $maintainer) = @_;
++
++ my $body;
++ my $lead_columns = [
++ $maintainer ?
++ qw/package media/ :
++ qw/package media maintainer/
++ ];
++ my $line;
++ my @results;
++ $body .= $self-&gt;{_cgi}-&gt;start_table();
++ $body .= $self-&gt;{_cgi}-&gt;Tr([
++ $self-&gt;{_cgi}-&gt;th([
++ @$lead_columns,
++ @$columns
++ ])
++ ]);
++ while (my $result = $iterator-&gt;get_result()) {
++ if (@results &amp;&amp; $result-&gt;{package} ne $results[0]-&gt;{package}) {
++ $body .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ $links,
++ $line++ % 2 ? 'odd' : 'even',
++ \@results
++ );
++ @results = ();
++ }
++ push(@results, $result);
++ }
++ $body .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ $links,
++ $line++ % 2 ? 'odd' : 'even',
++ \@results
++ );
++ $body .= $self-&gt;{_cgi}-&gt;end_table();
++
++ my $content;
++ $content .= $self-&gt;{_cgi}-&gt;start_html(
++ -title =&gt; $title,
++ -style =&gt; { code =&gt; $self-&gt;{_style} }
++ );
++ $content .= $self-&gt;{_cgi}-&gt;h1($title);
++ $content .= $body;
++ $content .= $self-&gt;{_cgi}-&gt;hr();
++ $content .= $self-&gt;{_cgi}-&gt;p(
++ { class =&gt; 'footer' },
++ &quot;Page generated $time&quot;
++ );
++ $content .= $self-&gt;{_cgi}-&gt;end_html();
++
++ return \$content;
++}
++
++sub _get_formated_results {
++ my ($self, $lead_columns, $columns, $links, $class, $results) = @_;
++
++ my $content;
++ $content .= $self-&gt;{_cgi}-&gt;end_Tr();
++ for my $i (0 .. $#$results) {
++ $content .= $self-&gt;{_cgi}-&gt;start_Tr(
++ { class =&gt; $class }
++ );
++ if ($i == 0) {
++ # first line contains spanned cells
++ $content .= $self-&gt;{_cgi}-&gt;td(
++ { rowspan =&gt; scalar @$results },
++ [
++ map { $results-&gt;[$i]-&gt;{$_} }
++ @$lead_columns
++ ]
++ );
++ }
++ $content .= $self-&gt;{_cgi}-&gt;td(
++ [
++ map {
++ $links-&gt;{$_} &amp;&amp; $results-&gt;[$i]-&gt;{$links-&gt;{$_}} ?
++ $self-&gt;{_cgi}-&gt;a(
++ { href =&gt; $results-&gt;[$i]-&gt;{$links-&gt;{$_}} },
++ $self-&gt;{_cgi}-&gt;escapeHTML($results-&gt;[$i]-&gt;{$_})
++ ) :
++ $self-&gt;{_cgi}-&gt;escapeHTML($results-&gt;[$i]-&gt;{$_})
++ } @$columns
++ ]
++ );
++ $content .= $self-&gt;{_cgi}-&gt;end_Tr();
++ }
++
++ return $content;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/Text.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/Text.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format/Text.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,83 @@
++# $Id: Mail.pm 580 2006-01-11 22:59:36Z guillomovitch $
++package Youri::Check::Output::Mail::Format::Text;
++
++=head1 NAME
++
++Youri::Check::Output::Mail::Format::Text - Mail text format support
++
++=head1 DESCRIPTION
++
++This format plugin for L&lt;Youri::Check::Output::Mail&gt; provides text format
++support.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use base 'Youri::Check::Output::Mail::Format';
++
++sub type {
++ return 'text/plain';
++}
++
++sub get_report {
++ my ($self, $time, $title, $iterator, $type, $columns, $links, $maintainer) = @_;
++
++ my $content;
++ my $lead_columns = [
++ $maintainer ?
++ qw/package media/ :
++ qw/package media maintainer/
++ ];
++ my @results;
++ $content .= join(&quot;\t&quot;, @$lead_columns, @$columns) . &quot;\n&quot;;
++ while (my $result = $iterator-&gt;get_result()) {
++ if (@results &amp;&amp; $result-&gt;{package} ne $results[0]-&gt;{package}) {
++ $content .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ \@results
++ );
++ @results = ();
++ }
++ push(@results, $result);
++ }
++
++ $content .= $self-&gt;_get_formated_results(
++ $lead_columns,
++ $columns,
++ \@results
++ );
++
++ return \$content;
++}
++
++sub _get_formated_results {
++ my ($self, $lead_columns, $columns, $results) = @_;
++
++ my $content;
++ $content .= join(
++ &quot;\t&quot;,
++ (map { $results-&gt;[0]-&gt;{$_} || '' } @$lead_columns),
++ (map { $results-&gt;[0]-&gt;{$_} || '' } @$columns)
++ ) . &quot;\n&quot;;
++ for my $i (1 .. $#$results) {
++ $content .= join(
++ &quot;\t&quot;,
++ (map { '' } @$lead_columns),
++ (map { $results-&gt;[$i]-&gt;{$_} || '' } @$columns)
++ ) . &quot;\n&quot;;
++ }
++ return $content;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail/Format.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,66 @@
++# $Id: Base.pm 579 2006-01-09 21:17:54Z guillomovitch $
++package Youri::Check::Output::Mail::Format;
++
++=head1 NAME
++
++Youri::Check::Output::Mail::Format - Abstract mail format support
++
++=head1 DESCRIPTION
++
++This abstract class defines the format support interface for
++L&lt;Youri::Check::Output::Mail&gt;.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++
++sub new {
++ my $class = shift;
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ id =&gt; '',
++ test =&gt; 0,
++ verbose =&gt; 0,
++ @_
++ );
++
++ my $self = bless {
++ _id =&gt; $options{id},
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head2 get_id()
++
++Returns format handler identity.
++
++=cut
++
++sub get_id {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_id};
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output/Mail.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,156 @@
++# $Id: Mail.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Output::Mail;
++
++=head1 NAME
++
++Youri::Check::Output::Mail - Report results by mail
++
++=head1 DESCRIPTION
++
++This plugin reports results by mail. Additional subplugins handle specific
++formats.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use MIME::Entity;
++use Youri::Utils;
++use base 'Youri::Check::Output';
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ from =&gt; '', # mail from header
++ to =&gt; '', # mail to header
++ reply_to =&gt; '', # mail reply-to header
++ mta =&gt; '', # mta path
++ noempty =&gt; 1, # don't generate empty reports
++ formats =&gt; {},
++ @_
++ );
++
++ croak &quot;no format defined&quot; unless $options{formats};
++ croak &quot;formats should be an hashref&quot; unless ref $options{formats} eq 'HASH';
++
++ $self-&gt;{_from} = $options{from};
++ $self-&gt;{_to} = $options{to};
++ $self-&gt;{_reply_to} = $options{reply_to};
++ $self-&gt;{_mta} = $options{mta};
++ $self-&gt;{_noempty} = $options{noempty};
++
++ foreach my $id (keys %{$options{formats}}) {
++ print &quot;Creating format $id\n&quot; if $options{verbose};
++ eval {
++ push(
++ @{$self-&gt;{_formats}},
++ create_instance(
++ 'Youri::Check::Output::Mail::Format',
++ id =&gt; $id,
++ test =&gt; $options{test},
++ verbose =&gt; $options{verbose},
++ %{$options{formats}-&gt;{$id}}
++ )
++ );
++ };
++ print STDERR &quot;Failed to create format $id: $@\n&quot; if $@;
++ }
++
++ croak &quot;no formats created&quot; unless @{$self-&gt;{_formats}};
++}
++
++sub _global_report {
++ my ($self, $resultset, $type, $columns, $links) = @_;
++
++ foreach my $format (@{$self-&gt;{_formats}}) {
++ my $iterator = $resultset-&gt;get_iterator(
++ $type,
++ [ 'package' ]
++ );
++
++ return if $self-&gt;{_noempty} &amp;&amp; ! $iterator-&gt;has_results();
++
++ my $content = $format-&gt;get_report(
++ $self-&gt;{_time},
++ &quot;$type global report&quot;,
++ $iterator,
++ $type,
++ $columns,
++ $links,
++ undef
++ );
++
++ $self-&gt;_send_mail(
++ $format-&gt;type(),
++ $self-&gt;{_to},
++ &quot;$type global report&quot;,
++ $content,
++ );
++ }
++}
++
++sub _individual_report {
++ my ($self, $resultset, $type, $columns, $links, $maintainer) = @_;
++
++ foreach my $format (@{$self-&gt;{_formats}}) {
++ my $iterator = $resultset-&gt;get_iterator(
++ $type,
++ [ 'package' ],
++ { maintainer =&gt; [ $maintainer ] }
++ );
++
++ return if $self-&gt;{_noempty} &amp;&amp; ! $iterator-&gt;has_results();
++
++ my $content = $format-&gt;get_report(
++ $self-&gt;{_time},
++ &quot;$type individual report for $maintainer&quot;,
++ $iterator,
++ $type,
++ $columns,
++ $links,
++ $maintainer
++ );
++
++ $self-&gt;_send_mail(
++ $format-&gt;type(),
++ $maintainer,
++ &quot;$type individual report for $maintainer&quot;,
++ $content,
++ );
++ }
++
++}
++
++sub _send_mail {
++ my ($self, $type, $to, $subject, $content) = @_;
++
++ return unless $content;
++
++ my $mail = MIME::Entity-&gt;build(
++ 'Type' =&gt; $type,
++ 'From' =&gt; $self-&gt;{_from},
++ 'Reply-To' =&gt; $self-&gt;{_reply_to},
++ 'To' =&gt; $to,
++ 'Subject' =&gt; $subject,
++ 'Data' =&gt; $$content
++ );
++
++ if ($self-&gt;{_test}) {
++ $mail-&gt;print(\*STDOUT);
++ } else {
++ open(MAIL, &quot;| $self-&gt;{_mta} -t -oi -oem&quot;) or die &quot;Can't open MTA program: $!&quot;;
++ $mail-&gt;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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Output.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Output.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Output.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,190 @@
++# $Id: Output.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Check::Output;
++
++=head1 NAME
++
++Youri::Check::Output - Abstract output plugin
++
++=head1 DESCRIPTION
++
++This abstract class defines output plugin interface.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Youri::Utils;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Check::Output object.
++
++Generic parameters (subclasses may define additional ones):
++
++=over
++
++=item global true/false
++
++Global reports generation (default: true).
++
++=item individual true/false
++
++Individual reports generation (default: true).
++
++=back
++
++Warning: do not call directly, call subclass constructor instead.
++
++=cut
++
++sub new {
++ my $class = shift;
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ id =&gt; '',
++ test =&gt; 0,
++ verbose =&gt; 0,
++ global =&gt; 1,
++ individual =&gt; 1,
++ config =&gt; undef,
++ @_
++ );
++
++ croak &quot;Neither global nor individual reporting selected&quot; unless $options{global} || $options{individual};
++
++ my $self = bless {
++ _id =&gt; $options{id},
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ _global =&gt; $options{global},
++ _individual =&gt; $options{individual},
++ _config =&gt; $options{config}
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head1 INSTANCE METHODS
++
++=head2 get_id()
++
++Returns plugin identity.
++
++=cut
++
++sub get_id {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_id};
++}
++
++=head2 run($resultset)
++
++Reports the result stored in given L&lt;Youri::Check::Resultset&gt; object.
++
++=cut
++
++sub run {
++ my ($self, $resultset) = @_;
++
++ $self-&gt;_init_report();
++
++ # get types and maintainers list from resultset
++ my @maintainers = $resultset-&gt;get_maintainers();
++ my @types = $resultset-&gt;get_types();
++
++ foreach my $type (@types) {
++ # get formatting instructions from class
++ my $class = $self-&gt;{_config}-&gt;get($type . '_class');
++ load($class);
++ my @columns = $class-&gt;columns();
++ my %links = $class-&gt;links();
++
++ if ($self-&gt;{_global}) {
++ print STDERR &quot;generating global report for $type\n&quot; if $self-&gt;{_verbose};
++ $self-&gt;_global_report(
++ $resultset,
++ $type,
++ \@columns,
++ \%links
++ );
++ }
++
++ if ($self-&gt;{_individual}) {
++ foreach my $maintainer (@maintainers) {
++ print STDERR &quot;generating individual report for $type and $maintainer\n&quot; if $self-&gt;{_verbose};
++
++ $self-&gt;_individual_report(
++ $resultset,
++ $type,
++ \@columns,
++ \%links,
++ $maintainer
++ );
++ }
++ }
++ }
++
++ $self-&gt;_finish_report(\@types, \@maintainers);
++}
++
++sub _init_report {
++ # do nothing
++}
++
++sub _global_report {
++ # do nothing
++}
++
++sub _individual_report {
++ # do nothing
++}
++
++sub _finish_report {
++ # do nothing
++}
++
++=head1 SUBCLASSING
++
++The following methods have to be implemented:
++
++=over
++
++=item run
++
++As an alternative, the following hooks can be implemented:
++
++=over
++
++=item _init_report
++
++=item _global_report
++
++=item _individual_report
++
++=item _finish_report
++
++=back
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/DBI.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/DBI.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/DBI.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,372 @@
++# $Id: Result.pm 485 2005-08-01 21:48:21Z guillomovitch $
++package Youri::Check::Resultset::DBI;
++
++=head1 NAME
++
++Youri::Check::Resultset::DBI - DBI-based resultset
++
++=head1 DESCRIPTION
++
++This is a DBI-based L&lt;Youri::Check::Resultset&gt; implementation.
++
++It can be created with any DBI-supported database.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use DBI 1.38;
++use base 'Youri::Check::Resultset';
++
++my %tables = (
++ packages =&gt; {
++ id =&gt; 'SERIAL PRIMARY KEY',
++ package =&gt; 'TEXT',
++ media =&gt; 'TEXT',
++ maintainer =&gt; 'TEXT',
++ }
++);
++
++my %queries = (
++ add_package =&gt;
++ 'INSERT INTO packages (package, media, maintainer) VALUES (?, ?, ?)',
++ get_package_id =&gt;
++ 'SELECT id FROM packages WHERE package = ?',
++ get_maintainers =&gt;
++ 'SELECT DISTINCT(maintainer) FROM packages WHERE maintainer IS NOT NULL',
++);
++
++=head1 CLASS METHODS
++
++=head2 new(%hash)
++
++Creates and returns a new Youri::Check::Resultset::DBI object.
++
++Specific parameters:
++
++=over
++
++=item driver $driver
++
++Use given string as DBI driver.
++
++=item base $base
++
++Use given string as database name.
++
++=item port $port
++
++Use given string as database port.
++
++=item user $user
++
++Use given string as database user.
++
++=item pass $pass
++
++Use given string as database password.
++
++=back
++
++=cut
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ driver =&gt; '', # driver
++ base =&gt; '', # base
++ port =&gt; '', # port
++ user =&gt; '', # user
++ pass =&gt; '', # pass
++ @_
++ );
++
++ croak &quot;No driver defined&quot; unless $options{driver};
++ croak &quot;No base defined&quot; unless $options{base};
++
++ my $datasource = &quot;DBI:$options{driver}:dbname=$options{base}&quot;;
++ $datasource .= &quot;;host=$options{host}&quot; if $options{host};
++ $datasource .= &quot;;port=$options{port}&quot; if $options{port};
++
++ $self-&gt;{_dbh} = DBI-&gt;connect($datasource, $options{user}, $options{pass}, {
++ RaiseError =&gt; 1,
++ PrintError =&gt; 0,
++ AutoCommit =&gt; 1
++ }) or croak &quot;Unable to connect: $DBI::errstr&quot;;
++
++ $self-&gt;{_dbh}-&gt;trace($options{verbose} - 1) if $options{verbose} &gt; 1;
++}
++
++sub clone {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $clone = bless {
++ _test =&gt; $self-&gt;{_test},
++ _verbose =&gt; $self-&gt;{_verbose},
++ _resolver =&gt; $self-&gt;{_resolver},
++ _dbh =&gt; $self-&gt;{_dbh}-&gt;clone()
++ }, ref $self;
++
++ return $clone;
++}
++
++sub reset {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ foreach my $table ($self-&gt;_get_tables()) {
++ my $query = &quot;DROP TABLE $table&quot;;
++ $self-&gt;{_dbh}-&gt;do($query);
++ }
++
++ foreach my $table (keys %tables) {
++ $self-&gt;_create_table($table, $tables{$table});
++ }
++}
++
++sub _get_tables {
++ my ($self) = @_;
++ my @tables = $self-&gt;{_dbh}-&gt;tables(undef, undef, '%', 'TABLE');
++ # unquote table name if needed
++ my $char = $self-&gt;{_dbh}-&gt;get_info(29);
++ @tables = map { substr($_, 1 , -1) } @tables if $char;
++ return @tables;
++}
++
++sub _get_columns {
++ my ($self, $table) = @_;
++ # proper way would be to use column_info(), but unfortunatly DBD::SQLite
++ # doesn't support it :(
++ return
++ keys
++ %{$self-&gt;{_dbh}-&gt;selectrow_hashref(&quot;SELECT * from $table&quot;)};
++}
++
++sub _create_table {
++ my ($self, $name, $fields) = @_;
++
++ my $query = &quot;CREATE TABLE $name (&quot; .
++ join(',',
++ map { &quot;$_ $fields-&gt;{$_}&quot; }
++ keys %$fields
++ ) .
++ &quot;)&quot;;
++ $self-&gt;{_dbh}-&gt;do($query);
++}
++
++sub add_result {
++ my ($self, $type, $media, $package, $values) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ croak &quot;No type defined&quot; unless $type;
++ croak &quot;No package defined&quot; unless $package;
++ croak &quot;No values defined&quot; unless $values;
++
++ my $key = &quot;add_$type&quot;;
++ my $sth = $self-&gt;{_sths}-&gt;{$key};
++
++ unless ($sth) {
++ my @fields = keys %$values;
++ $self-&gt;_create_table($type, {
++ 'package_id' =&gt; 'INT',
++ map { $_ =&gt; 'TEXT' } @fields
++ });
++ my $query = &quot;INSERT INTO $type (&quot; .
++ join(',', 'package_id', @fields) .
++ &quot;) VALUES (&quot; .
++ join(',', '?', map { '?' } @fields) .
++ &quot;)&quot;;
++ $sth = $self-&gt;{_dbh}-&gt;prepare($query);
++ $self-&gt;{_sths}-&gt;{$key} = $sth;
++ }
++
++ print &quot;adding result for type $type and package $package\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ $sth-&gt;execute(
++ $self-&gt;_get_package_id(
++ $package-&gt;get_canonical_name(),
++ $media-&gt;get_name(),
++ ),
++ values %$values
++ );
++}
++
++sub get_types {
++ my ($self) = @_;
++
++ return
++ grep { ! $tables{$_} }
++ $self-&gt;_get_tables();
++}
++
++sub get_maintainers {
++ my ($self) = @_;
++
++ return $self-&gt;_get_multiple_values('get_maintainers');
++}
++
++sub get_iterator {
++ my ($self, $id, $sort, $filter) = @_;
++
++ die 'No id given, aborting'
++ unless $id;
++ die 'sort should be an arrayref'
++ if $sort and ref $sort ne 'ARRAY';
++ die 'filter should be an hashref'
++ if $filter and ref $filter ne 'HASH';
++
++ my $query = $self-&gt;_get_iterator_query($id, $sort, $filter);
++
++ my $sth = $self-&gt;{_dbh}-&gt;prepare($query);
++ $sth-&gt;execute();
++
++ return Youri::Check::Resultset::DBI::Iterator-&gt;new($sth);
++}
++
++sub _get_iterator_query {
++ my ($self, $table, $sort, $filter) = @_;
++
++ my @fields =
++ grep { ! /package_id/ }
++ $self-&gt;_get_columns($table);
++
++ my $query = &quot;SELECT DISTINCT &quot; .
++ join(',', qw/package media maintainer/, @fields) .
++ &quot; FROM $table, packages&quot; .
++ &quot; WHERE packages.id = $table.package_id&quot;;
++
++ if ($filter) {
++ foreach my $column (keys %{$filter}) {
++ foreach my $value (@{$filter-&gt;{$column}}) {
++ $query .= &quot; AND $column = &quot; . $self-&gt;{_dbh}-&gt;quote($value);
++ }
++ }
++ }
++
++ if ($sort) {
++ $query .= &quot; ORDER BY &quot; . join(', ', @{$sort});
++ }
++
++ return $query;
++}
++
++sub _get_package_id {
++ my ($self, $package, $media) = @_;
++
++ my $id = $self-&gt;_get_single_value(
++ 'get_package_id',
++ $package
++ );
++ $id = $self-&gt;_add_package($package, $media) unless $id;
++
++ return $id;
++}
++
++sub _add_package {
++ my ($self, $package, $media) = @_;
++
++ my $maintainer = $self-&gt;{_resolver} ?
++ $self-&gt;{_resolver}-&gt;get_maintainer($package) :
++ undef;
++
++ my $sth =
++ $self-&gt;{_sths}-&gt;{add_package} ||=
++ $self-&gt;{_dbh}-&gt;prepare($queries{add_package});
++
++ $sth-&gt;execute(
++ $package,
++ $media,
++ $maintainer
++ );
++
++ my $id = $self-&gt;{_dbh}-&gt;last_insert_id(undef, undef, 'packages', 'id');
++
++ return $id;
++}
++
++sub _get_single_value {
++ my ($self, $query, @values) = @_;
++
++ my $sth =
++ $self-&gt;{_sths}-&gt;{$query} ||=
++ $self-&gt;{_dbh}-&gt;prepare($queries{$query});
++
++ $sth-&gt;execute(@values);
++
++ my @row = $sth-&gt;fetchrow_array();
++ return @row ? $row[0]: undef;
++}
++
++sub _get_multiple_values {
++ my ($self, $query, @values) = @_;
++
++ my $sth =
++ $self-&gt;{_sths}-&gt;{$query} ||=
++ $self-&gt;{_dbh}-&gt;prepare($queries{$query});
++
++ $sth-&gt;execute(@values);
++
++ my @results;
++ while (my @row = $sth-&gt;fetchrow_array()) {
++ push @results, $row[0];
++ }
++ return @results;
++}
++
++# close database connection
++sub DESTROY {
++ my ($self) = @_;
++
++ foreach my $sth (values %{$self-&gt;{_sths}}) {
++ $sth-&gt;finish() if $sth;
++ }
++
++ # warning, may be called before _dbh is created
++ $self-&gt;{_dbh}-&gt;disconnect() if $self-&gt;{_dbh};
++}
++
++package Youri::Check::Resultset::DBI::Iterator;
++
++sub new {
++ my ($class, $sth) = @_;
++
++ my $self = bless {
++ _sth =&gt; $sth,
++ _queue =&gt; []
++ }, $class;
++
++ return $self;
++}
++
++sub has_results {
++ my ($self) = @_;
++
++ return 1 if @{$self-&gt;{_queue}};
++
++ push(
++ @{$self-&gt;{_queue}},
++ $self-&gt;{_sth}-&gt;fetchrow_hashref()
++ );
++
++ return defined $self-&gt;{_queue}-&gt;[-1];
++}
++
++sub get_result {
++ my ($self) = @_;
++
++ return @{$self-&gt;{_queue}} ?
++ shift @{$self-&gt;{_queue}}:
++ $self-&gt;{_sth}-&gt;fetchrow_hashref();
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/Iterator.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/Iterator.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset/Iterator.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,22 @@
++# $Id: Base.pm 483 2005-08-01 21:39:05Z guillomovitch $
++package Youri::Check::Resultset::Iterator;
++
++=head1 INSTANCE METHODS
++
++=head2 has_results()
++
++Returns true if results are available.
++
++=head2 get_result()
++
++Returns next available result, as an field =&gt; value hash reference.
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Check/Resultset.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,116 @@
++# $Id: Base.pm 483 2005-08-01 21:39:05Z guillomovitch $
++package Youri::Check::Resultset;
++
++=head1 NAME
++
++Youri::Check::Resultset - Abstract resultset
++
++=head1 DESCRIPTION
++
++This abstract class defines Youri::Check::Resultset interface
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Scalar::Util qw/blessed/;
++use Youri::Utils;
++
++=head1 CLASS METHODS
++
++=head2 new(%hash)
++
++Creates and returns a new Youri::Check::Resultset object.
++
++No generic parameters (subclasses may define additional ones).
++
++Warning: do not call directly, call subclass constructor instead.
++
++=cut
++
++sub new {
++ my $class = shift;
++ my %options = (
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ resolver =&gt; undef, # maintainer resolver,
++ mode =&gt; 'output', # access mode
++ @_
++ );
++
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my $self = bless {
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ _resolver =&gt; $options{resolver},
++ _mode =&gt; $options{mode}
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head1 INSTANCE METHODS
++
++=head2 set_resolver()
++
++Set L&lt;Youri::Check::Maintainer::Resolver&gt; object used to resolve package
++maintainers.
++
++=cut
++
++sub set_resolver {
++ my ($self, $resolver) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ croak &quot;resolver should be a Youri::Check::Maintainer::Resolver object&quot;
++ unless blessed $resolver &amp;&amp;
++ $resolver-&gt;isa(&quot;Youri::Check::Maintainer::Resolver&quot;);
++
++ $self-&gt;{_resolver} = $resolver;
++}
++
++=head2 clone()
++
++Clone resultset object.
++
++=head2 reset()
++
++Reset resultset object, by deleting all contained results.
++
++=head2 add_result($type, $media, $package, $values)
++
++Add given hash reference as a new result for given type and L&lt;Youri::Package&gt; object.
++
++=head2 get_maintainers()
++
++Returns the list of all maintainers with results.
++
++=head2 get_iterator($id, $sort, $filter)
++
++Returns a L&lt;Youri::Check::Resultset::Iterator&gt; object over results for given input it, with optional sort and filter directives.
++
++sort must be an arrayref of column names, such as [ 'package' ].
++
++filter must be a hashref of arrayref of acceptables values indexed by column names, such as { level =&gt; [ 'warning', 'error'] }.
++
++=head1 SUBCLASSING
++
++All instances methods have to be implemented.
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Config.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Config.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Config.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,202 @@
++# $Id: Config.pm 1709 2006-10-16 16:33:43Z warly $
++package Youri::Config;
++
++=head1 NAME
++
++Youri::Application - Youri application handler
++
++=head1 SYNOPSIS
++
++ use Youri::Application;
++
++ my $app = Youri::Application-&gt;new(
++ options =&gt; {
++ help =&gt; '|h!'
++ },
++ directories =&gt; [ '/etc/youri', &quot;$ENV{HOME}/.youri&quot; ],
++ file =&gt; 'app.conf',
++ );
++
++ # get command line argument
++ my $foo = $app-&gt;get_arg('foo');
++
++ # get configuration file parameter
++ my $bar = $app-&gt;get_param('bar');
++
++=head1 DESCRIPTION
++
++This class handle configuration for all YOURI applications.
++
++The command line specification is used to manage arguments through
++Getopt::Long. Unless B&lt;--config&gt; argument is given, the list of directories is
++then scanned for a file with given name, and halt as soon as it find one. If no
++readable file is found, an exception is thrown. The file is then processed
++through YAML::AppConfig. If parsing fails, an exception is thrown.
++
++=head1 CONFIGURATION FILE FORMAT
++
++=head2 SHARED KEYS
++
++In addition to the application-specific optional or mandatory parameters, all
++YOURI applications support the following optional top-level parameters:
++
++=over
++
++=item B&lt;includes&gt;
++
++A list of additional configuration files.
++
++=item B&lt;foo&gt;
++
++An arbitrary variable, usable everywhere else in the file.
++
++=back
++
++=head2 PLUGIN DEFINITION
++
++All YOURI application heavily rely on plugins defined in their configuration
++files. A plugin definition is composed from the following parameters:
++
++=over
++
++=item B&lt;class&gt;
++
++The class of this plugin.
++
++=item B&lt;options&gt;
++
++The options of this plugin.
++
++=back
++
++=head1 SEE ALSO
++
++YAML::AppConfig, Getopt::Long
++
++=cut
++
++use strict;
++use warnings;
++use YAML::AppConfig;
++use Getopt::Long;
++use File::Spec;
++use Pod::Usage;
++use Carp;
++
++sub new {
++ my ($class, %options) = @_;
++
++
++ # command line arguments
++ my $args = {
++ verbose =&gt; 0
++ };
++ my @args;
++ if ($options{args}) {
++ while (my ($arg, $spec) = each %{$options{args}}) {
++ push(@args, ($arg . $spec) =&gt; \$args-&gt;{$arg});
++ }
++ }
++ push(@args,
++ 'config=s' =&gt; \$args-&gt;{config},
++ 'h|help' =&gt; \$args-&gt;{help},
++ 'v|verbose+' =&gt; \$args-&gt;{verbose}
++ );
++ GetOptions(@args);
++
++ if ($args-&gt;{help}) {
++ if (!@ARGV) {
++ # standard help, available immediatly
++ my $filename = (caller)[1];
++ pod2usage(
++ -input =&gt; $filename,
++ -verbose =&gt; 0
++ );
++ }
++ }
++
++ # config files parameters
++
++ # find configuration file to use
++ my $main_file;
++ if ($args-&gt;{config}) {
++ if (! -f $args-&gt;{config}) {
++ croak &quot;Non-existing file $args-&gt;{config}&quot;;
++ } elsif (! -r $args-&gt;{config}) {
++ croak &quot;Non-readable file $args-&gt;{config}&quot;;
++ } else {
++ $main_file = $args-&gt;{config};
++ }
++ } else {
++ foreach my $directory (@{$options{directories}}) {
++ my $file = &quot;$directory/$options{file}&quot;;
++ next unless -f $file &amp;&amp; -r $file;
++ $main_file = $file;
++ last;
++ }
++ croak 'No config file found, aborting' unless $main_file;
++ }
++
++ my $params;
++ eval {
++ $params = YAML::AppConfig-&gt;new(file =&gt; $main_file);
++ };
++ if ($@) {
++ croak &quot;Invalid configuration file $main_file, aborting&quot;;
++ }
++
++ # process inclusions
++ my $includes = $params-&gt;get('includes');
++ if ($includes) {
++ foreach my $include_file (@{$includes}) {
++ # convert relative path to absolute ones
++ $include_file = File::Spec-&gt;rel2abs(
++ $include_file, (File::Spec-&gt;splitpath($main_file))[1]
++ );
++
++ if (! -f $include_file) {
++ warn &quot;Non-existing file $include_file, skipping&quot;;
++ } elsif (! -r $include_file) {
++ warn &quot;Non-readable file $include_file, skipping&quot;;
++ } else {
++ eval {
++ $params-&gt;merge(file =&gt; $include_file);
++ };
++ if ($@) {
++ carp &quot;Invalid included configuration file $include_file, skipping&quot;;
++ }
++ }
++ }
++ }
++
++ my $self = bless {
++ _args =&gt; $args,
++ _params =&gt; $params
++ }, $class;
++
++ return $self;
++}
++
++sub get_arg {
++ my ($self, $arg) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_args}-&gt;{$arg};
++}
++
++sub get_param {
++ my ($self, $param) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_params}-&gt;get($param);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Media/URPM.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Media/URPM.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Media/URPM.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,273 @@
++# $Id: URPM.pm 1179 2006-08-05 08:30:57Z warly $
++package Youri::Media::URPM;
++
++=head1 NAME
++
++Youri::Media::URPM - URPM-based media implementation
++
++=head1 DESCRIPTION
++
++This is an URPM-based L&lt;Youri::Media&gt; implementation.
++
++It can be created either from local or remote full (hdlist) or partial
++(synthesis) compressed header files, or from a package directory. File-based
++inputs are only usable with this latest option.
++
++=cut
++
++use URPM;
++use File::Find;
++use File::Temp ();
++use Youri::Utils;
++use LWP::Simple;
++use Carp;
++use strict;
++use warnings;
++use Youri::Package::URPM;
++
++use base 'Youri::Media';
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Media::URPM object.
++
++Specific parameters:
++
++=over
++
++=item synthesis $synthesis
++
++Path, URL or list of path or URL of synthesis file used for creating
++this media. If a list is given, the first successfully accessed will be used,
++so as to allow better reliability.
++
++=item hdlist $hdlist
++
++Path, URL or list of path or URL of hdlist file used for creating
++this media. If a list is given, the first successfully accessed will be used,
++so as to allow better reliability.
++
++=item path $path
++
++Path or list of pathes of package directory used for creating this
++media. If a list is given, the first successfully accessed will be used, so as
++to allow better reliability.
++
++=item max_age $age
++
++Maximum age of packages for this media.
++
++=item rpmlint_config $file
++
++rpmlint configuration file for this media.
++
++=back
++
++In case of multiple B&lt;synthesis&gt;, B&lt;hdlist&gt; and B&lt;path&gt; options given, they
++will be tried in this order, so as to minimize parsing time.
++
++=cut
++
++sub _init {
++ my $self = shift;
++
++ my %options = (
++ hdlist =&gt; '', # hdlist from which to create this media
++ synthesis =&gt; '', # synthesis from which to create this media
++ path =&gt; '', # directory from which to create this media
++ max_age =&gt; '', # maximum build age for packages
++ rpmlint_config =&gt; '', # rpmlint configuration for packages
++ @_
++ );
++
++ my $urpm = URPM-&gt;new();
++ SOURCE: {
++ if ($options{synthesis}) {
++ foreach my $file (
++ ref $options{synthesis} eq 'ARRAY' ?
++ @{$options{synthesis}} :
++ $options{synthesis}
++ ) {
++ print &quot;Attempting to retrieve synthesis $file\n&quot;
++ if $options{verbose};
++ my $synthesis = $self-&gt;_get_file($file);
++ if ($synthesis) {
++ $urpm-&gt;parse_synthesis($synthesis, keep_all_tags =&gt; 1);
++ last SOURCE;
++ }
++ }
++ }
++
++ if ($options{hdlist}) {
++ foreach my $file (
++ ref $options{hdlist} eq 'ARRAY' ?
++ @{$options{hdlist}} :
++ $options{hdlist}
++ ) {
++ print &quot;Attempting to retrieve hdlist $file\n&quot;
++ if $options{verbose};
++ my $hdlist = $self-&gt;_get_file($file);
++ if ($hdlist) {
++ $urpm-&gt;parse_hdlist($hdlist, keep_all_tags =&gt; 1);
++ last SOURCE;
++ }
++ }
++ }
++
++ if ($options{path}) {
++ foreach my $path (
++ ref $options{path} eq 'ARRAY' ?
++ @{$options{path}} :
++ $options{path}
++ ) {
++ print &quot;Attempting to scan directory $path\n&quot;
++ if $options{verbose};
++ unless (-d $path) {
++ carp &quot;non-existing directory $path&quot;;
++ next;
++ }
++ unless (-r $path) {
++ carp &quot;non-readable directory $path&quot;;
++ next;
++ }
++
++ my $parse = sub {
++ return unless -f $File::Find::name;
++ return unless -r $File::Find::name;
++ return unless /\.rpm$/;
++
++ $urpm-&gt;parse_rpm($File::Find::name, keep_all_tags =&gt; 1);
++ };
++
++ find($parse, $path);
++ last SOURCE;
++ }
++ }
++
++ croak &quot;no source specified&quot;;
++ }
++
++ $self-&gt;{_urpm} = $urpm;
++ $self-&gt;{_path} = $options{path};
++ $self-&gt;{_max_age} = $options{max_age};
++ $self-&gt;{_rpmlint_config} = $options{rpmlint_config};
++
++ return $self;
++}
++
++sub _remove_all_archs {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ $self-&gt;{_urpm}-&gt;{depslist} = [];
++}
++
++sub _remove_archs {
++ my ($self, $skip_archs) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $urpm = $self-&gt;{_urpm};
++ $urpm-&gt;{depslist} = [
++ grep { ! $skip_archs-&gt;{$_-&gt;arch()} } @{$urpm-&gt;{depslist}}
++ ];
++}
++
++=head1 INSTANCE METHODS
++
++=head2 max_age()
++
++Returns maximum age of packages for this media.
++
++=cut
++
++sub max_age {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_max_age};
++}
++
++=head2 rpmlint_config()
++
++Returns rpmlint configuration file for this media.
++
++=cut
++
++sub rpmlint_config {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_rpmlint_config};
++}
++
++sub get_package_class {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return &quot;Youri::Package::URPM&quot;;
++}
++
++sub traverse_files {
++ my ($self, $function) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $callback = sub {
++ return unless -f $File::Find::name;
++ return unless -r $File::Find::name;
++ return unless $_ =~ /\.rpm$/;
++
++ my $package = Youri::Package::URPM-&gt;new(file =&gt; $File::Find::name);
++ return if $self-&gt;{_skip_archs}-&gt;{$package-&gt;get_arch()};
++
++ $function-&gt;($File::Find::name, $package);
++ };
++
++ find($callback, $self-&gt;{_path});
++}
++
++sub traverse_headers {
++ my ($self, $function) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ $self-&gt;{_urpm}-&gt;traverse(sub {
++ local $_; # workaround mysterious problem between URPM and AppConfig
++ $function-&gt;(Youri::Package::URPM-&gt;new(header =&gt; $_[0]));
++ });
++
++}
++
++sub _get_file {
++ my ($self, $file) = @_;
++
++ if ($file =~ /^(?:http|ftp):\/\/.*$/) {
++ my $tempfile = File::Temp-&gt;new();
++ my $status = getstore($file, $tempfile-&gt;filename());
++ unless (is_success($status)) {
++ carp &quot;invalid URL $file: $status&quot;;
++ return;
++ }
++ return $tempfile;
++ } else {
++ unless (-f $file) {
++ carp &quot;non-existing file $file&quot;;
++ return;
++ }
++ unless (-r $file) {
++ carp &quot;non-readable file $file&quot;;
++ return;
++ }
++ return $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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Media.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Media.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Media.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,311 @@
++# $Id: Media.pm 1710 2006-10-16 16:35:11Z warly $
++package Youri::Media;
++
++=head1 NAME
++
++Youri::Media - Abstract media class
++
++=head1 DESCRIPTION
++
++This abstract class defines Youri::Media interface.
++
++=cut
++
++use Carp;
++use strict;
++use warnings;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Media object.
++
++Generic parameters:
++
++=over
++
++=item id $id
++
++Media id.
++
++=item name $name
++
++Media name.
++
++=item type $type (source/binary)
++
++Media type.
++
++=item test true/false
++
++Test mode (default: false).
++
++=item verbose true/false
++
++Verbose mode (default: false).
++
++=item allow_deps $media_ids
++
++list of ids of medias allowed to provide dependencies.
++
++=item skip_tests $test_ids
++
++list of ids of test plugins to skip.
++
++=item skip_archs $arches
++
++list of arches to skip.
++
++=back
++
++Subclass may define additional parameters.
++
++Warning: do not call directly, call subclass constructor instead.
++
++=cut
++
++sub new {
++ my $class = shift;
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ name =&gt; '', # media name
++ canonical_name =&gt; '', # media canonical name
++ type =&gt; '', # media type
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ allow_deps =&gt; undef, # list of media ids from which deps are allowed
++ allow_srcs =&gt; undef, # list of media ids from which packages can be built
++ skip_tests =&gt; undef, # list of tests ids to skip
++ skip_archs =&gt; undef, # list of archs for which to skip tests
++ @_
++ );
++
++
++ croak &quot;No type given&quot; unless $options{type};
++ croak &quot;Wrong value for type: $options{type}&quot;
++ unless $options{type} =~ /^(?:binary|source)$/o;
++
++ # some options need to be arrays. Check it and convert to hashes
++ foreach my $option (qw(allow_deps allow_srcs skip_archs skip_tests)) {
++ next unless defined $options{$option};
++ croak &quot;$option should be an arrayref&quot; unless ref $options{$option} eq 'ARRAY';
++ $options{$option} = {
++ map { $_ =&gt; 1 } @{$options{$option}}
++ };
++ }
++
++ my $self = bless {
++ _id =&gt; $options{id},
++ _name =&gt; $options{name} || $options{id},
++ _type =&gt; $options{type},
++ _allow_deps =&gt; $options{allow_deps},
++ _allow_srcs =&gt; $options{allow_srcs},
++ _skip_archs =&gt; $options{skip_archs},
++ _skip_tests =&gt; $options{skip_tests},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ # remove unwanted archs
++ if ($options{skip_archs}-&gt;{all}) {
++ $self-&gt;_remove_all_archs()
++ } elsif ($options{skip_archs}) {
++ $self-&gt;_remove_archs($options{skip_archs});
++ }
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head1 INSTANCE METHODS
++
++=head2 get_id()
++
++Returns media identity.
++
++=cut
++
++sub get_id {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_id};
++}
++
++=head2 get_name()
++
++Returns the name of this media.
++
++=cut
++
++sub get_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_name};
++}
++
++=head2 get_type()
++
++Returns the type of this media.
++
++=cut
++
++sub get_type {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_type};
++}
++
++=head2 allow_deps()
++
++Returns the list of id of medias allowed to provide dependencies for this
++media.
++
++=cut
++
++sub allow_deps {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return keys %{$self-&gt;{_allow_deps}};
++}
++
++=head2 allow_dep($media_id)
++
++Tells wether media with given id is allowed to provide dependencies for
++this media.
++
++=cut
++
++sub allow_dep {
++ my ($self, $dep) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_allow_deps}-&gt;{all} ||
++ $self-&gt;{_allow_deps}-&gt;{$dep};
++}
++
++=head2 allow_srcs()
++
++Returns the list medias where the source packages can be
++
++=cut
++
++sub allow_srcs {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return keys %{$self-&gt;{_allow_srcs}};
++}
++
++=head2 allow_src($media_id)
++
++Tells wether media with given id is allowed to host sources dependencies for
++this media.
++
++=cut
++
++sub allow_src {
++ my ($self, $src) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_allow_srcs}-&gt;{all} || $self-&gt;{_allow_srcs}-&gt;{$src};
++}
++
++=head2 skip_archs()
++
++Returns the list of arch which are to be skipped for this media.
++
++=cut
++
++sub skip_archs {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return keys %{$self-&gt;{_skip_archs}};
++}
++
++=head2 skip_arch($arch)
++
++Tells wether given arch is to be skipped for this media.
++
++=cut
++
++sub skip_arch {
++ my ($self, $arch) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_skip_archs}-&gt;{all} ||
++ $self-&gt;{_skip_archs}-&gt;{$arch};
++}
++
++=head2 skip_tests()
++
++Returns the list of id of test which are to be skipped for this media.
++
++=cut
++
++sub skip_tests {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return keys %{$self-&gt;{_skip_tests}};
++}
++
++=head2 skip_test($test_id)
++
++Tells wether test with given id is to be skipped for this media.
++
++=cut
++
++sub skip_test {
++ my ($self, $test) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_skip_tests}-&gt;{all} ||
++ $self-&gt;{_skip_tests}-&gt;{$test};
++}
++
++=head2 get_package_class()
++
++Return package class for this media.
++
++=head2 traverse_files($function)
++
++Apply given function to all files of this media.
++
++=head2 traverse_headers($function)
++
++Apply given function to all headers of this media.
++
++=head1 SUBCLASSING
++
++The following methods have to be implemented:
++
++=over
++
++=item traverse_headers
++
++=item traverse_files
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,58 @@
++# $Id: /local/youri/soft/trunk/lib/Youri/Package/URPM.pm 2257 2006-07-05T09:22:47.088572Z guillaume $
++package Youri::Package::RPM;
++
++=head1 NAME
++
++Youri::Package::RPM - Base class for all RPM-based package implementation
++
++=head1 DESCRIPTION
++
++This bases class factorize code between various RPM-based package
++implementation.
++
++=cut
++
++use strict;
++use warnings;
++use base 'Youri::Package';
++use Carp;
++
++sub get_pattern {
++ my ($class, $name, $version, $release, $arch) = @_;
++
++ return
++ ($name ? quotemeta($name) : '[\w-]+' ).
++ '-' .
++ ($version ? quotemeta($version) : '[^-]+' ).
++ '-' .
++ ($release ? quotemeta($release) : '[^-]+' ).
++ '\.' .
++ ($arch ? quotemeta($arch) : '\w+' ).
++ '\.rpm';
++}
++
++sub as_file {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_file};
++}
++
++sub is_debug {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $name = $self-&gt;get_name();
++ my $group = $self-&gt;get_tag('group');
++
++ # debug packages' names must end in -debug, except kernel
++ if ($group =~ m,^Development/Debug$, &amp;&amp;
++ ($name =~ /-debug$/o || $name =~ /^kernel-.*-debug/o)) {
++ return 1;
++ }
++ else {
++ return 0;
++ }
++}
++
++1;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM4.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM4.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Package/RPM4.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,424 @@
++# $Id: /local/youri/soft/trunk/lib/Youri/Package/URPM.pm 2129 2006-06-23T09:41:01.599329Z guillomovitch $
++package Youri::Package::RPM4;
++
++=head1 NAME
++
++Youri::Package::RPM4 - URPM-based rpm package implementation
++
++=head1 DESCRIPTION
++
++This is an RPM4-based L&lt;Youri::Package&gt; implementation for rpm.
++
++=cut
++
++use strict;
++use warnings;
++use Carp;
++use RPM4;
++use RPM4::Header;
++use RPM4::Sign;
++use File::Spec;
++use Scalar::Util qw/refaddr/;
++use base 'Youri::Package::RPM';
++use overload
++ '&quot;&quot;' =&gt; 'as_string',
++ '0+' =&gt; '_to_number',
++ fallback =&gt; 1;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Package::RPM4 object.
++
++Specific parameters:
++
++=over
++
++=item file $file
++
++Path of file to use for creating this package.
++
++=item header $header
++
++L&lt;RPM4::Header&gt; object to use for creating this package.
++
++=back
++
++=cut
++
++sub _init {
++ my ($self, %options) = @_;
++
++ my $header;
++ HEADER: {
++ if (exists $options{header}) {
++ croak &quot;undefined header&quot;
++ unless $options{header};
++ croak &quot;invalid header&quot;
++ unless $options{header}-&gt;isa('RPM4::Header');
++ $header = $options{header};
++ last HEADER;
++ }
++
++ if (exists $options{file}) {
++ croak &quot;undefined file&quot;
++ unless $options{file};
++ croak &quot;non-existing file $options{file}&quot;
++ unless -f $options{file};
++ croak &quot;non-readable file $options{file}&quot;
++ unless -r $options{file};
++ $header = RPM4::Header-&gt;new($options{file});
++ croak &quot;Can't get header from file $options{file}&quot; if (!$header);
++
++ last HEADER;
++ }
++
++ croak &quot;no way to extract header from arguments&quot;;
++ }
++
++ $self-&gt;{_header} = $header;
++ $self-&gt;{_file} = File::Spec-&gt;rel2abs($options{file});
++}
++
++sub compare_versions {
++ my ($class, $version1, $version2) = @_;
++
++ return RPM4::rpmvercmp($version1, $version2);
++}
++
++sub _depsense2flag {
++ my ($string) = @_;
++ my @flags = 0;
++ push(@flags, 'EQUAL') if ($string =~ /=/);
++ push(@flags, 'LESS') if ($string =~ /&lt;/);
++ push(@flags, 'GREATER') if ($string =~ /&gt;/);
++ return \@flags;
++}
++
++sub check_ranges_compatibility {
++ my ($class, $range1, $range2) = @_;
++ my @deps1 = split(/ /, $range1);
++ my @deps2 = split(/ /, $range2);
++ $deps1[1] = _depsense2flag($range1);
++ $deps2[1] = _depsense2flag($range2);
++ my $dep1 = RPM4::Header::Dependencies(
++ &quot;PROVIDENAME&quot;,
++ \@deps1,
++ );
++ my $dep2 = RPM4::Header::Dependencies(
++ &quot;PROVIDENAME&quot;,
++ \@deps2,
++ );
++
++ return $dep1-&gt;overlap($dep2);
++}
++
++sub get_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('name');
++}
++
++sub get_version {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('version');
++}
++
++sub get_release {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('release');
++}
++
++sub get_revision {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;queryformat('%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}');
++}
++
++sub get_file_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;queryformat('%{NAME}-%{VERSION}-%{RELEASE}.%|SOURCERPM?{%{ARCH}}:{src}|.rpm');
++}
++
++
++sub get_arch {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;queryformat('%|SOURCERPM?{%{ARCH}}:{src}|');
++}
++
++sub get_url {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('url');
++}
++
++sub get_summary {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('summary');
++}
++
++sub get_description {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('description');
++}
++
++sub get_packager {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('packager');
++}
++
++sub is_source {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;issrc();
++}
++
++sub is_binary {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return !$self-&gt;{_header}-&gt;issrc();
++}
++
++sub get_type {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_header}-&gt;issrc() ?
++ &quot;source&quot; :
++ &quot;binary&quot;;
++}
++
++sub get_age {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('buildtime');
++}
++
++sub get_source_package {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;tag('sourcerpm');
++}
++
++sub get_canonical_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ $self-&gt;{_header}-&gt;sourcerpmname() =~ /^(\S+)-[^-]+-[^-]+\.src\.rpm$/;
++ return $1;
++}
++
++sub get_tag {
++ my ($self, $tag) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ #croak &quot;invalid tag $tag&quot; unless $self-&gt;{_header}-&gt;can($tag);
++ return $self-&gt;{_header}-&gt;tag($tag);
++}
++
++
++sub _get_dependencies {
++ my ($self, $deptype) = @_;
++ my $deps = $self-&gt;{_header}-&gt;dep($deptype);
++ my @deps_list;
++ if ($deps) {
++ $deps-&gt;init();
++ while ($deps-&gt;next() &gt;= 0) {
++ my @deps = $deps-&gt;info();
++ $deps[1] =~ m/^rpmlib\(/ and next; # skipping internal rpmlib dep
++ $deps[2] =~ s/^=$/==/; # rpm say foo = 1, not foo == 1, == come from URPM, which sucks
++ my $range = $deps[3] ? ($deps[2] . ' ' . $deps[3]) : undef;
++ push(@deps_list, [ $deps[1], $range ]);
++ }
++ }
++ @deps_list
++}
++
++sub get_requires {
++ my ($self) = @_;
++
++ return $self-&gt;_get_dependencies('REQUIRENAME');
++}
++
++sub get_provides {
++ my ($self) = @_;
++
++ return $self-&gt;_get_dependencies('PROVIDENAME');
++}
++
++sub get_obsoletes {
++ my ($self) = @_;
++
++ return $self-&gt;_get_dependencies('OBSOLETENAME');
++}
++
++sub get_conflicts {
++ my ($self) = @_;
++
++ return $self-&gt;_get_dependencies('CONFLICTNAME');
++}
++
++sub get_files {
++ my ($self) = @_;
++
++ my $files = $self-&gt;{_header}-&gt;files();
++ my @fileslist;
++ if ($files) {
++ $files-&gt;init();
++ while ($files-&gt;next() &gt;= 0) {
++ my $smode = $files-&gt;mode();
++ my $umode = 0;
++ foreach (0..15) { # converting unsigned to signed int :\
++ $umode |= $smode &amp; (1 &lt;&lt; $_);
++ }
++ push(@fileslist, [ $files-&gt;filename(), $umode, $files-&gt;md5() || '' ]);
++ }
++ }
++ @fileslist
++}
++
++sub get_gpg_key {
++ my ($self) = @_;
++
++ my $signature = $self-&gt;{_header}-&gt;queryformat('%{SIGGPG:pgpsig}');
++
++ return if $signature eq '(not a blob)';
++
++ my $key_id = (split(/\s+/, $signature))[-1];
++
++ return substr($key_id, 8);
++}
++
++sub get_information {
++ my ($self) = @_;
++
++ return $self-&gt;{_header}-&gt;queryformat(&lt;&lt;EOF);
++Name : %-27{NAME} Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|
++Version : %-27{VERSION} Vendor: %{VENDOR}
++Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}
++Install Date: %|INSTALLTIME?{%-27{INSTALLTIME:date}}:{(not installed) }| Build Host: %{BUILDHOST}
++Group : %-27{GROUP} Source RPM: %{SOURCERPM}
++Size : %-27{SIZE}%|LICENSE?{ License: %{LICENSE}}|
++Signature : %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|
++%|PACKAGER?{Packager : %{PACKAGER}\n}|%|URL?{URL : %{URL}\n}|Summary : %{SUMMARY}
++Description :\n%{DESCRIPTION}
++EOF
++}
++
++sub get_changes {
++ my ($self) = @_;
++
++ my @names = $self-&gt;{_header}-&gt;tag('changelogname');
++ my @time = $self-&gt;{_header}-&gt;tag('changelogtime');
++ my @text = $self-&gt;{_header}-&gt;tag('changelogtext');
++
++ my @changes;
++ foreach my $i (0 .. $#names) {
++ $changes[$i] = [
++ $names[$i],
++ $time[$i],
++ $text[$i],
++ ];
++ }
++
++ return @changes;
++}
++
++sub get_last_change {
++ my ($self) = @_;
++
++ return [
++ ($self-&gt;{_header}-&gt;tag('changelogname'))[0],
++ ($self-&gt;{_header}-&gt;tag('changelogtime'))[0],
++ ($self-&gt;{_header}-&gt;tag('changelogtext'))[0],
++ ];
++}
++
++sub as_string {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;fullname();
++}
++
++sub as_formated_string {
++ my ($self, $format) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;queryformat($format);
++}
++
++sub _to_number {
++ return refaddr($_[0]);
++}
++
++sub compare {
++ my ($self, $package) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;compare($package-&gt;{_header}) || 0;
++}
++
++sub satisfy_range {
++ my ($self, $range) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;check_range_compatibility($self-&gt;get_revision(), $range);
++}
++
++sub sign {
++ my ($self, $name, $path, $passphrase) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # check if parent directory is writable
++ my $parent = (File::Spec-&gt;splitpath($self-&gt;{_file}))[1];
++ croak &quot;Unsignable package, parent directory is read-only&quot;
++ unless -w $parent;
++
++ my $sign = RPM4::Sign-&gt;new(
++ name =&gt; $name,
++ path =&gt; $path,
++ );
++ $sign-&gt;{passphrase} = $passphrase;
++
++ $sign-&gt;rpmssign($self-&gt;{_file})
++}
++
++sub extract {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ system(&quot;rpm2cpio $self-&gt;{_file} | cpio -id &gt;/dev/null 2&gt;&amp;1&quot;);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Package/Test.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Package/Test.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Package/Test.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,151 @@
++# $Id: /local/youri/soft/core/trunk/lib/Youri/Package/URPM.pm 2133 2006-09-20T21:40:20.575763Z guillaume $
++package Youri::Package::Test;
++
++=head1 NAME
++
++Youri::Package::Test - Fake test package
++
++=head1 DESCRIPTION
++
++This is just a fake package object, intended for testing purposes.
++
++=cut
++
++use strict;
++use warnings;
++use Carp;
++use base 'Youri::Package::RPM';
++use overload
++ '&quot;&quot;' =&gt; 'as_string',
++ '0+' =&gt; '_to_number',
++ fallback =&gt; 1;
++
++our $AUTOLOAD;
++
++my @tags = qw/
++ name
++ version
++ release
++ filename
++ arch
++ url
++ summary
++ description
++ packager
++ buildtime
++ sourcerpm
++/;
++
++my %tags = map { $_ =&gt; 1 } @tags;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Package::Test object.
++
++Specific parameters:
++
++=over
++
++=item tag $tag
++
++Use given value for given tag
++
++=back
++
++=cut
++
++sub _init {
++ my ($self, %options) = @_;
++
++ $self-&gt;{&quot;_$_&quot;} = $options{$_} foreach keys %options;
++}
++
++sub get_revision {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_epoch} ?
++ &quot;$self-&gt;{_epoch}:$self-&gt;{_version}-$self-&gt;{_release}&quot; :
++ &quot;$self-&gt;{_version}-$self-&gt;{_release}&quot;;
++}
++
++sub get_tag {
++ my ($self, $tag) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ croak &quot;invalid tag $tag&quot; unless $tags{$tag};
++ return $self-&gt;{'_' . $tag};
++}
++
++sub is_source {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_arch} eq 'src';
++}
++
++sub is_binary {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_arch} ne 'src';
++}
++
++sub get_type {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_arch} eq 'src' ?
++ &quot;source&quot; :
++ &quot;binary&quot;;
++}
++
++sub get_canonical_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ if ($self-&gt;{_arch} eq 'src') {
++ return $self-&gt;{_name};
++ } else {
++ if ($self-&gt;{_sourcerpm}) {
++ $self-&gt;{_sourcerpm} =~ /^(\S+)-[^-]+-[^-]+\.src\.rpm$/;
++ return $1;
++ } else {
++ return undef;
++ }
++ }
++}
++
++sub as_string {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_name} ? $self-&gt;{_name} : '' .
++ '-' .
++ $self-&gt;{_version} ? $self-&gt;{_version} : '' .
++ '-' .
++ $self-&gt;{_release} ? $self-&gt;{_release} : '';
++}
++
++sub _to_number {
++ return refaddr($_[0]);
++}
++
++sub AUTOLOAD {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my $method = $AUTOLOAD;
++ $method =~ s/.*:://;
++ return if $method eq 'DESTROY';
++ croak &quot;invalid method&quot; unless $method =~ /^get_(\w+)$/;
++
++ my $tag = $1;
++ croak &quot;invalid tag $tag&quot; unless $tags{$tag};
++ return $self-&gt;{'_' . $tag};
++}
++
++1;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Package/URPM.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Package/URPM.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Package/URPM.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,399 @@
++# $Id: URPM.pm 266577 2010-03-02 14:51:24Z bogdano $
++package Youri::Package::URPM;
++
++=head1 NAME
++
++Youri::Package::URPM - URPM-based rpm package implementation
++
++=head1 DESCRIPTION
++
++This is an URPM-based L&lt;Youri::Package&gt; implementation for rpm.
++
++It is merely a wrapper over URPM::Package class, with a more structured
++interface.
++
++=cut
++
++use strict;
++use warnings;
++use Carp;
++use URPM;
++use File::Spec;
++use Expect;
++use Scalar::Util qw/refaddr/;
++use base 'Youri::Package::RPM';
++use overload
++ '&quot;&quot;' =&gt; 'as_string',
++ '0+' =&gt; '_to_number',
++ fallback =&gt; 1;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Package::URPM object.
++
++Specific parameters:
++
++=over
++
++=item file $file
++
++Path of file to use for creating this package.
++
++=item header $header
++
++L&lt;URPM::Package&gt; object to use for creating this package.
++
++=back
++
++=cut
++
++sub _init {
++ my ($self, %options) = @_;
++
++ my $header;
++ HEADER: {
++ if (exists $options{header}) {
++ croak &quot;undefined header&quot;
++ unless $options{header};
++ croak &quot;invalid header&quot;
++ unless $options{header}-&gt;isa('URPM::Package');
++ $header = $options{header};
++ last HEADER;
++ }
++
++ if (exists $options{file}) {
++ croak &quot;undefined file&quot;
++ unless $options{file};
++ croak &quot;non-existing file $options{file}&quot;
++ unless -f $options{file};
++ croak &quot;non-readable file $options{file}&quot;
++ unless -r $options{file};
++ my $urpm = URPM-&gt;new();
++ $urpm-&gt;parse_rpm($options{file}, keep_all_tags =&gt; 1);
++ $header = $urpm-&gt;{depslist}-&gt;[0];
++ croak &quot;non-rpm file $options{file}&quot; unless $header;
++ last HEADER;
++ }
++
++ croak &quot;no way to extract header from arguments&quot;;
++ }
++
++ $self-&gt;{_header} = $header;
++ $self-&gt;{_file} = File::Spec-&gt;rel2abs($options{file});
++}
++
++sub compare_versions {
++ my ($class, $version1, $version2) = @_;
++
++ return URPM::rpmvercmp($version1, $version2);
++}
++
++sub check_ranges_compatibility {
++ my ($class, $range1, $range2) = @_;
++
++ return URPM::ranges_overlap($range1, $range2);
++}
++
++sub get_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;name();
++}
++
++sub get_version {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;version();
++}
++
++sub get_release {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;release();
++}
++
++sub get_revision {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;queryformat('%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}');
++}
++
++sub get_file_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_file} || die &quot;_file is not defined in header-only objects!\n&quot;;
++}
++
++sub get_arch {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;arch();
++}
++
++sub get_url {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;url();
++}
++
++sub get_summary {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;summary();
++}
++
++sub get_description {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;description();
++}
++
++sub get_packager {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;packager();
++}
++
++sub is_source {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;arch() eq 'src';
++}
++
++sub is_binary {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;arch() ne 'src';
++}
++
++sub get_type {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_header}-&gt;arch() eq 'src' ?
++ &quot;source&quot; :
++ &quot;binary&quot;;
++}
++
++sub get_age {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;buildtime();
++}
++
++sub get_source_package {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;sourcerpm();
++}
++
++sub get_canonical_name {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ if ($self-&gt;{_header}-&gt;arch() eq 'src') {
++ return $self-&gt;{_header}-&gt;name();
++ } else {
++ $self-&gt;{_header}-&gt;sourcerpm() =~ /^(\S+)-[^-]+-[^-]+\.src\.rpm$/;
++ return $1;
++ }
++}
++
++sub get_tag {
++ my ($self, $tag) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ croak &quot;invalid tag $tag&quot; unless $self-&gt;{_header}-&gt;can($tag);
++ return $self-&gt;{_header}-&gt;$tag();
++}
++
++sub get_requires {
++ my ($self) = @_;
++
++ return map {
++ $_ =~ /^([^[]+)(?:\[\*\])?(?:\[(.+)\])?$/;
++ [ $1, $2 ]
++ } $self-&gt;{_header}-&gt;requires();
++}
++
++sub get_provides {
++ my ($self) = @_;
++
++ return map {
++ $_ =~ /^([^[]+)(?:\[(.+)\])?$/;
++ [ $1, $2 &amp;&amp; $2 ne '*' ? $2 : undef ]
++ } $self-&gt;{_header}-&gt;provides();
++}
++
++sub get_obsoletes {
++ my ($self) = @_;
++
++ return map {
++ $_ =~ /^([^[]+)(?:\[(.+)\])?$/;
++ [ $1, $2 &amp;&amp; $2 ne '*' ? $2 : undef ]
++ } $self-&gt;{_header}-&gt;obsoletes();
++}
++
++sub get_conflicts {
++ my ($self) = @_;
++
++ return $self-&gt;{_header}-&gt;conflicts();
++}
++
++sub get_files {
++ my ($self) = @_;
++
++ my @modes = $self-&gt;{_header}-&gt;files_mode();
++ my @md5sums = $self-&gt;{_header}-&gt;files_md5sum();
++
++ return map {
++ [ $_, shift @modes, shift @md5sums ]
++ } $self-&gt;{_header}-&gt;files();
++}
++
++sub get_gpg_key {
++ my ($self) = @_;
++
++ my $signature = $self-&gt;{_header}-&gt;queryformat('%{SIGGPG:pgpsig}');
++
++ return if $signature eq '(not a blob)';
++
++ my $key_id = (split(/\s+/, $signature))[-1];
++
++ return substr($key_id, 8);
++}
++
++sub get_information {
++ my ($self) = @_;
++
++ return $self-&gt;{_header}-&gt;queryformat(&lt;&lt;EOF);
++Name : %-27{NAME} Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|
++Version : %-27{VERSION} Vendor: %{VENDOR}
++Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}
++Install Date: %|INSTALLTIME?{%-27{INSTALLTIME:date}}:{(not installed) }| Build Host: %{BUILDHOST}
++Group : %-27{GROUP} Source RPM: %{SOURCERPM}
++Size : %-27{SIZE}%|LICENSE?{ License: %{LICENSE}}|
++Signature : %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|
++%|PACKAGER?{Packager : %{PACKAGER}\n}|%|URL?{URL : %{URL}\n}|Summary : %{SUMMARY}
++Description :\n%{DESCRIPTION}
++EOF
++}
++
++sub get_changes {
++ my ($self) = @_;
++
++ my @names = $self-&gt;{_header}-&gt;changelog_name();
++ my @time = $self-&gt;{_header}-&gt;changelog_time();
++ my @text = $self-&gt;{_header}-&gt;changelog_text();
++
++ my @changes;
++ foreach my $i (0 .. $#names) {
++ $changes[$i] = [
++ $names[$i],
++ $time[$i],
++ $text[$i],
++ ];
++ }
++
++ return @changes;
++}
++
++sub get_last_change {
++ my ($self) = @_;
++
++ return [
++ ($self-&gt;{_header}-&gt;changelog_name())[0],
++ ($self-&gt;{_header}-&gt;changelog_time())[0],
++ ($self-&gt;{_header}-&gt;changelog_text())[0],
++ ];
++}
++
++sub as_string {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;fullname();
++}
++
++sub as_formated_string {
++ my ($self, $format) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;queryformat($format);
++}
++
++sub _to_number {
++ return refaddr($_[0]);
++}
++
++sub compare {
++ my ($self, $package) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_header}-&gt;compare_pkg($package-&gt;{_header});
++}
++
++sub satisfy_range {
++ my ($self, $range) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;check_ranges_compatibility(&quot;== &quot; . $self-&gt;get_revision(), $range);
++}
++
++sub sign {
++ my ($self, $name, $path, $passphrase, $target) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ # check if parent directory is writable
++ my $parent = (File::Spec-&gt;splitpath($self-&gt;{_file}))[1];
++ croak &quot;Unsignable package, parent directory is read-only&quot;
++ unless -w $parent;
++
++ # FIXME Will have to change that
++ # we sign with cooker key even fro 2007.0 because this is for testing section
++ return !system(&quot;sudo -H /root/bin/resign_cooker $self-&gt;{_file}&quot;);
++
++ my $command =
++ 'LC_ALL=C rpm --resign ' . $self-&gt;{_file} .
++ ' --define &quot;_gpg_name ' . $name . '&quot;' .
++ ' --define &quot;_gpg_path ' . $path . '&quot;';
++ my $expect = Expect-&gt;spawn($command) or die &quot;Couldn't spawn command $command: $!\n&quot;;
++ $expect-&gt;log_stdout(0);
++ $expect-&gt;expect(20, -re =&gt; 'Enter pass phrase:');
++ $expect-&gt;send(&quot;$passphrase\n&quot;);
++
++ $expect-&gt;soft_close();
++}
++
++sub extract {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ system(&quot;rpm2cpio $self-&gt;{_file} | cpio -id &gt;/dev/null 2&gt;&amp;1&quot;);
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Package.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Package.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Package.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,336 @@
++# $Id: Package.pm 223952 2007-06-23 13:54:13Z pixel $
++package Youri::Package;
++
++=head1 NAME
++
++Youri::Package - Abstract package class
++
++=head1 DESCRIPTION
++
++This abstract class defines Youri::Package interface.
++
++=cut
++
++use Carp;
++use strict;
++use warnings;
++
++use constant DEPENDENCY_NAME =&gt; 0;
++use constant DEPENDENCY_RANGE =&gt; 1;
++
++use constant FILE_NAME =&gt; 0;
++use constant FILE_MODE =&gt; 1;
++use constant FILE_MD5SUM =&gt; 2;
++
++use constant CHANGE_AUTHOR =&gt; 0;
++use constant CHANGE_TIME =&gt; 1;
++use constant CHANGE_TEXT =&gt; 2;
++
++=head1 CLASS METHODS
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Package object.
++
++Warning: do not call directly, call subclass constructor instead.
++
++=cut
++
++sub new {
++ my $class = shift;
++ croak &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ @_
++ );
++
++ my $self = bless {
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head2 get_pattern($name, $version, $release, $arch)
++
++Returns a pattern matching a file for a package, using available informations.
++
++=head2 compare_revisions($revision1, $revision2)
++
++Compares two revision tokens, and returns a numeric value:
++
++=over
++
++=item positive if first revision is higher
++
++=item null if both revisions are equal
++
++=item negative if first revision is lower
++
++=back
++
++=head2 check_ranges_compatibility($range1, $range2)
++
++Returns a true value if given revision ranges are compatible.
++
++=head1 INSTANCE METHODS
++
++=head2 as_file()
++
++Returns the file corresponding to this package.
++
++=head2 as_string()
++
++Returns a string representation of this package.
++
++=head2 as_formated_string(I&lt;format&gt;)
++
++Returns a string representation of this package, formated according to
++I&lt;format&gt;. Format is a string, where each %{foo} token will get replaced by
++equivalent tag value.
++
++=head2 get_name()
++
++Returns the name of this package.
++
++=head2 get_version()
++
++Returns the version of this package.
++
++=head2 get_release()
++
++Returns the release of this package.
++
++=head2 get_revision()
++
++Returns the revision of this package.
++
++=head2 get_arch()
++
++Returns the architecture of this package.
++
++=head2 get_file_name()
++
++Returns the file name of this package (name-version-release.arch.extension).
++
++=head2 is_source()
++
++Returns true if this package is a source package.
++
++=head2 is_binary()
++
++Returns true if this package is a binary package.
++
++=head2 is_debug()
++
++Returns true if this package is a debug package.
++
++=head2 get_type()
++
++Returns the type (binary/source) of this package.
++
++=head2 get_age()
++
++Returns the age of this package
++
++=head2 get_url()
++
++Returns the URL of this package
++
++=head2 get_summary()
++
++Returns the summary of this package
++
++=head2 get_description()
++
++Returns the description of this package
++
++=head2 get_packager()
++
++Returns the packager of this package.
++
++=head2 get_source_package()
++
++Returns the name of the source package of this package.
++
++=head2 get_tag($tag)
++
++Returns the value of tag $tag of this package.
++
++=head2 get_canonical_name()
++
++Returns the canonical name of this package, shared by its multiple components,
++usually the one from the source package.
++
++=head2 get_requires()
++
++Returns the list of dependencies required by this package, each dependency
++being represented as an array reference, with the following informations:
++
++=over
++
++=item B&lt;name&gt;
++
++Name of the dependency (index DEPENDENCY_NAME)
++
++=item B&lt;range&gt;
++
++Range of the dependency (index DEPENDENCY_RANGE)
++
++=back
++
++For more conveniency, fields index are available as constant in this package.
++
++=head2 get_provides()
++
++Returns the list of dependencies provided by this package, each dependency
++being represented as an array reference, using the same structure as previous method.
++
++=head2 get_obsoletes()
++
++Returns the list of other packages obsoleted by this one, each one
++being represented as an array reference, using the same structure as previous method.
++
++=head2 get_conflicts()
++
++Returns the list of other packages conflicting with this one.
++
++=head2 get_files()
++
++Returns the list of files contained in this package, each file being
++represented as an array reference, with the following informations:
++
++=over
++
++=item B&lt;name&gt;
++
++Name of the file (index FILE_NAME).
++
++=item B&lt;mode&gt;
++
++Mode of the file (index FILE_MODE).
++
++=item B&lt;md5sum&gt;
++
++Md5sum of the file (index FILE_MD5SUM).
++
++=back
++
++For more conveniency, fields index are available as constant in this package.
++
++=head2 get_gpg_key()
++
++Returns the gpg key id of package signature.
++
++=head2 get_information()
++
++Returns formated informations about the package.
++
++=head2 get_changes()
++
++Returns the list of changes for this package, each change being
++represented as an array reference, with the following informations:
++
++=over
++
++=item B&lt;author&gt;
++
++Author of the change (index CHANGE_AUTHOR).
++
++=item B&lt;time&gt;
++
++Time of the change (index CHANGE_TIME).
++
++=item B&lt;text&gt;
++
++Raw textual description of the change (index CHANGE_TEXT).
++
++=back
++
++For more conveniency, fields index are available as constant in this package.
++
++=head2 get_last_change()
++
++Returns the last change for this package, as as structure described before.
++
++=head2 compare($package)
++
++Compares ordering with other package, according to their corresponding revision
++tokens, and returns a numeric value:
++
++=over
++
++=item positive if this package is newer
++
++=item null if both have same revision
++
++=item negative if this package is older
++
++=back
++
++=head2 satisfy_range($range)
++
++Returns a true value if this package revision satisfies given revision range.
++
++=head2 sign($name, $path, $passphrase)
++
++Signs the package with given name, keyring path and passphrase.
++
++=head2 extract()
++
++Extract package content in local directory.
++
++=head1 SUBCLASSING
++
++All instances methods have to be implemented.
++
++=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
++
++sub get_file {
++ my ($self) = @_;
++ carp &quot;Deprecated method, use as_file now&quot;;
++
++ return $self-&gt;as_file();
++}
++
++sub get_full_name {
++ my ($self) = @_;
++ carp &quot;Deprecated method, use as_string now&quot;;
++
++ return $self-&gt;as_string();
++}
++
++sub compare_versions {
++ my ($self, $version1, $version2) = @_;
++ carp &quot;Deprecated method, use compare_revisions now&quot;;
++
++ return $self-&gt;compare_revisions($version1, $version2);
++}
++
++sub compare_ranges {
++ my ($self, $range1, $range2) = @_;
++ carp &quot;Deprecated method, use are_range_compatible now&quot;;
++
++ return $self-&gt;check_ranges_compatibility($range1, $range2);
++}
++
++sub get_revision_name {
++ my ($self) = @_;
++ carp &quot;Deprecated method, use as_formated_string('%name-%version-%release') now&quot;;
++
++ return $self-&gt;as_formated_string('%{name}-%{version}-%{release}');
++}
++
++
++1;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,546 @@
++# $Id: /local/youri/soft/trunk/lib/Youri/Upload/Action/RSS.pm 857 2006-01-29T10:15:43.298856Z guillaume $
++package Youri::Repository::Mandriva_upload;
++
++=head1 NAME
++
++Youri::Repository::PLF - PLF repository implementation
++
++=head1 DESCRIPTION
++
++This module implements PLF repository.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Memoize;
++use File::Find 'find';
++use base qw/Youri::Repository/;
++use MDV::Distribconf::Build;
++use SVN::Client;
++
++use constant {
++ PACKAGE_CLASS =&gt; 'Youri::Package::URPM',
++ PACKAGE_CHARSET =&gt; 'utf8'
++};
++
++memoize('_get_media_config');
++
++my %translate_arch = (
++ i386 =&gt; 'i586',
++ sparc64 =&gt; 'sparcv9',
++);
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ noarch =&gt; 'i586', # noarch packages policy
++ src =&gt; 'i586',
++ install_root =&gt; '',
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ queue =&gt; '',
++ rejected =&gt; '',
++ @_
++ );
++ foreach my $var ('upload_state') {
++ $self-&gt;{&quot;_$var&quot;} = [];
++ foreach my $value (split ' ', $options{$var}) {
++ push @{$self-&gt;{&quot;_$var&quot;}}, $value
++ }
++ }
++ print &quot;Initializing repository\n&quot;;
++ foreach my $v ('rejected', 'svn', 'queue', 'noarch', 'install_root', 'upload_root', 'verbose') {
++ $self-&gt;{&quot;_$v&quot;} = $options{$v}
++ }
++ foreach my $target (@{$options{targets}}) {
++ $self-&gt;{$target} = [];
++ print &quot;Adding $target ($options{$target}{arch})\n&quot; if $self-&gt;{_verbose};
++ foreach my $value (split ' ', $options{$target}{arch}) {
++ push @{$self-&gt;{_arch}{$target}}, $value;
++ push @{$self-&gt;{_extra_arches}}, $value
++ }
++ }
++ $self
++}
++
++sub get_group_id {
++ my ($user) = @_;
++ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
++ $year+=1900;
++ $mon++;
++ my $hostname = `hostname`;
++ my ($host) = $hostname =~ /([^.]*)/;
++ sprintf &quot;$year%02d%02d%02d%02d%02d.$user.$host.${$}_&quot;, $mon, $mday, $hour, $min, $sec;
++}
++
++sub get_target_arch {
++ my ($self, $target) = $_;
++ return $self-&gt;{_arch}{$target}
++}
++
++sub set_arch_changed {
++ my ($self, $target, $arch) = @_;
++ if ($arch eq 'noarch') {
++ $self-&gt;{_arch_changed}{$_} = 1 foreach @{$self-&gt;{_arch}{$target}}
++ } elsif ($arch eq 'src') {
++ $self-&gt;{_arch_changed} = $self-&gt;{_src}
++ } else {
++ $self-&gt;{_arch_changed}{$arch} = 1
++ }
++}
++
++sub get_arch_changed {
++ my ($self, $target) = @_;
++ return [ keys %{$self-&gt;{_arch_changed}} ]
++}
++
++sub set_install_dir_changed {
++ my ($self, $install_dir) = @_;
++ $self-&gt;{_install_dir_changed}{$install_dir} = 1;
++}
++
++sub get_install_dir_changed {
++ my ($self) = @_;
++ return [ keys %{$self-&gt;{_install_dir_changed}} ];
++}
++
++sub _get_media_config {
++ my ($self, $target) = @_;
++ my %media;
++ my $real_target = $target;
++ $real_target =~ s/_force//;
++ foreach my $arch (@{$self-&gt;{_arch}{$target}}) {
++ my $root = &quot;$self-&gt;{_install_root}/$real_target/$arch&quot;;
++ my $distrib = MDV::Distribconf::Build-&gt;new($root);
++ print &quot;Getting media config from $root\n&quot; if $self-&gt;{_verbose};
++ $self-&gt;{distrib}{$arch} = $distrib;
++ $distrib-&gt;loadtree or die &quot;$root does not seem to be a distribution tree\n&quot;;
++ $distrib-&gt;parse_mediacfg;
++ foreach my $media ($distrib-&gt;listmedia) {
++ my $rpms = $distrib-&gt;getvalue($media, 'rpms');
++ my $debug_for = $distrib-&gt;getvalue($media, 'debug_for');
++ my $srpms = $distrib-&gt;getvalue($media, 'srpms');
++ my $path = $distrib-&gt;getfullpath($media, 'path');
++ if (!$rpms) {
++ if (-d $path) {
++ print &quot;MEDIA defining $media in $path\n&quot; if $self-&gt;{_verbose} &gt; 1;
++ $media{$arch}{$media} = $path
++ } else {
++ print &quot;ERROR $path does not exist for media $media on $arch\n&quot;
++ }
++ } else {
++ my ($media) = split ' ', $rpms;
++ if (-d $path) {
++ print &quot;MEDIA defining SOURCE media for $media in $path\n&quot; if $self-&gt;{_verbose} &gt; 1;
++ $media{src}{$media} = $path
++ } else {
++ print &quot;ERROR $path does not exist for source media $media on $arch\n&quot;
++ }
++ }
++ }
++ }
++ \%media
++}
++
++sub get_package_class {
++ return PACKAGE_CLASS;
++}
++
++sub get_package_charset {
++ return PACKAGE_CHARSET;
++}
++
++sub get_upload_dir {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ my $arch = $package-&gt;get_arch();
++ return
++ $self-&gt;{_upload_root} .
++ &quot;/$self-&gt;{_queue}/$target/&quot; .
++ _get_section($self, $package, $target, $user_context, $app_context) .
++ '/' .
++ ($user_context-&gt;{prefix} ? '' : get_group_id($user_context-&gt;{user}))
++}
++
++sub get_install_path {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++
++ return $self-&gt;_get_path($package, $target, $user_context, $app_context);
++}
++
++
++sub get_distribution_paths {
++ my ($self, $package, $target) = @_;
++
++ return $self-&gt;_get_distribution_paths($package, $target);
++}
++
++sub get_archive_path {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++
++ return $self-&gt;_get_path($package, $target, $user_context, $app_context);
++}
++
++sub get_reject_path {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++
++ return $self-&gt;{_rejected};
++}
++
++
++sub _get_path {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++
++ my $section = $self-&gt;_get_section($package, $target, $user_context, $app_context);
++ my $arch = $app_context-&gt;{arch} || $package-&gt;get_arch();
++ $arch = $translate_arch{$arch} || $arch;
++ if ($arch eq 'noarch') {
++ $arch = $self-&gt;{_noarch}
++ } elsif ($arch eq 'src') {
++ return &quot;$target/SRPMS/$section&quot;
++ }
++ &quot;$target/$arch/media/$section&quot;
++}
++
++sub _get_distribution_paths {
++ my ($self, $package, $target) = @_;
++
++ my $arch = $package-&gt;get_arch();
++ $arch = $translate_arch{$arch} || $arch;
++ if ($arch eq 'noarch') {
++ map { &quot;$target/$_&quot; } $self-&gt;get_extra_arches;
++ } elsif ($arch eq 'src') {
++ die &quot;no way to get distribution path using a $arch package&quot;;
++ } else {
++ &quot;$target/$arch&quot;;
++ }
++}
++
++sub get_arch {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ my $arch = $package-&gt;get_arch();
++ $arch = $translate_arch{$arch} || $arch;
++ if ($arch eq 'noarch') {
++ $arch = $self-&gt;{_noarch}
++ }
++ $arch
++}
++
++sub get_version_path {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++
++ my $section = $self-&gt;_get_section($package, $target, $user_context, $app_context);
++
++ return &quot;$self-&gt;{_module}/$section&quot;;
++}
++
++=head2 get_replaced_packages($package, $target, $user_context, $app_context)
++
++Overrides parent method to add libified packages.
++
++=cut
++
++sub get_replaced_packages {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my @replaced_packages =
++ $self-&gt;SUPER::get_replaced_packages($package, $target, $user_context, $app_context);
++
++ # mandriva lib policy:
++ # library package names change with revision, making mandatory to
++ # duplicate older revisions search with a custom pattern
++ my $name = $package-&gt;get_name();
++ if ($name =~ /^(lib\w+[a-zA-Z_])[\d_\.]+([-\w]*)$/) {
++ push(@replaced_packages,
++ grep { $package-&gt;compare($_) &gt; 0 }
++ map { PACKAGE_CLASS-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ $self-&gt;get_install_path($package, $target, $user_context, $app_context),
++ PACKAGE_CLASS-&gt;get_pattern(
++ $1 . '[\d_\.]+' . $2, # custom name pattern
++ undef,
++ undef,
++ $package-&gt;get_arch()
++ ),
++ )
++ );
++ }
++
++ # kernel packages have the version in the name
++ # binary dkms built for old kernels have to be removed too
++ if ($name =~ /^kernel-([^\d]*-)?([\d.]*)-(.*)$/) { # &quot;desktop&quot;, &quot;2.6.28&quot;, &quot;2mnb&quot;
++ push(@replaced_packages,
++ map { PACKAGE_CLASS-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ $self-&gt;get_install_path($package, $target, $user_context, $app_context),
++ PACKAGE_CLASS-&gt;get_pattern(
++ '(kernel-' . $1 . '\d.*|.*-kernel-[\d.]*-' . $1 . '\d.*)',
++ undef,
++ undef,
++ $package-&gt;get_arch()
++ ),
++ )
++ );
++ }
++
++ return @replaced_packages;
++
++}
++
++sub _get_main_section {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++
++ my $section = $self-&gt;_get_section($package, $target, $user_context, $app_context);
++ my ($main_section) = $section =~ m,^([^/]+),;
++ $main_section
++}
++
++sub _get_section {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++
++ my $name = $package-&gt;get_name();
++ my $cname = $package-&gt;get_canonical_name();
++ my $version = $package-&gt;get_version();
++ my $release = $package-&gt;get_release();
++ my $section = $user_context-&gt;{section};
++ my $media = $self-&gt;_get_media_config($target);
++ my $arch = $package-&gt;get_arch();
++ my $file = $package-&gt;as_file();
++ $file =~ s,/+,/,g; # unneeded?
++ # FIXME: use $self-&gt;get_arch()
++ $arch = $self-&gt;{_noarch} if $arch eq 'noarch';
++ $arch = $translate_arch{$arch} || $arch;
++
++ if (!$section) {
++ $section = $self-&gt;{packages}{$file}{section};
++ print &quot;Section undefined, repository says it is '$section' for '$file'\n&quot; if $self-&gt;{_verbose};
++ }
++ if ($section &amp;&amp; $section !~ /debug_/ &amp;&amp; $package-&gt;is_debug()) {
++ $section = &quot;debug_$section&quot;
++ }
++
++ # if have section already, check if it exists, and may return immediately
++ if ($section) {
++ print &quot;Using requested section $section\n&quot;;
++ if ($media-&gt;{$arch}{$section}) {
++ return $section
++ } else {
++ die &quot;FATAL youri: unknown section $section for target $target for arch $arch\n&quot;
++ }
++ }
++ # else, try to find section automatically
++
++ # pattern for search of src package with specific version-release,
++ # should be searched first, because we prefer to find the precise
++ # section a package is already in
++ my $specific_source_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $cname,
++ $version,
++ $release,
++ 'src'
++ );
++
++ my $source_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $cname,
++ undef,
++ undef,
++ 'src'
++ );
++
++ # if a media has no source media configured, or if it is a debug
++ # package, we search in binary media
++
++ # pattern for search when a binary media has no src media configured
++ my $specific_binary_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $name,
++ $version,
++ $release,
++ $arch
++ );
++
++ # last resort pattern: previous existing binary packages
++ my $binary_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $name,
++ undef,
++ undef,
++ $arch
++ );
++
++ # first try to find section for the specific version, as it is possibly already there;
++ # this is the case for when called in Youri::Submit::Action::Archive, to find the
++ # section the package got installed
++ print &quot;Looking for package $name with version $version-$release\n&quot;;
++ foreach my $m (keys %{$media-&gt;{$arch}}) {
++ print &quot; .. section '$m' path '&quot;.$media-&gt;{$arch}{$m}.&quot;'\n&quot; if $self-&gt;{_verbose};
++ # - prefer source for non-debug packages, use binary if there is no source media configured
++ # - debug packages must be searched in binary medias, due to their
++ # src section != binary section; NOTE: should/need we search in
++ # src medias and add the 'debug_' prefix?
++ if (!$package-&gt;is_debug() &amp;&amp; $media-&gt;{src}{$m}) {
++ next unless $self-&gt;get_files('', $media-&gt;{src}{$m}, $specific_source_pattern);
++ } else {
++ next unless $self-&gt;get_files('', $media-&gt;{$arch}{$m}, $specific_binary_pattern);
++ }
++ $section = $m;
++ last;
++ }
++
++ # if still not found, try finding any version of the package in a
++ # /release subsection (safe default: /release is default for cooker,
++ # should be locked for released distros, and we don't risk wrongly
++ # choosing /backports, /testing, or /updates);
++ # this is the case for when called at submit, to find the section where
++ # the package already resides
++ if (!$section) {
++ # debug packages should be found by previous specific version search
++ # NOTE: as above, should/need we search here and add the 'debug_' prefix?
++ # ... probably... as at least mdv-youri-submit-force will process debug packages
++ if ($package-&gt;is_debug() &amp;&amp; $self-&gt;{_verbose}) {
++ print &quot;Warning: debug package $name with version $version-$release not found.\n&quot;;
++ }
++
++ print &quot;Warning: Looking for any section with a package $name of any version\n&quot;;
++ foreach my $m (keys %{$media-&gt;{$arch}}) {
++ print &quot; .. section '$m' path '&quot;.$media-&gt;{$arch}{$m}.&quot;'\n&quot; if $self-&gt;{_verbose};
++ # NOTE: !$package-&gt;is_debug() test is here to prevent when above FATAL error is removed
++ next if $m !~ /release/ || ($m =~ /debug/ &amp;&amp; !$package-&gt;is_debug());
++ # - prefer source
++ if ($media-&gt;{src}{$m}) {
++ next unless $self-&gt;get_files('', $media-&gt;{src}{$m}, $source_pattern);
++ } else {
++ next unless $self-&gt;get_files('', $media-&gt;{$arch}{$m}, $binary_pattern);
++ }
++ $section = $m;
++ last;
++ }
++ }
++
++ # FIXME: doing this here is wrong; this way the caller can never know if
++ # a section was actually found or not; should return undef and let the
++ # caller set a default (Note: IIRC PLF|Zarb has this right, see there) -spuk
++ print STDERR &quot;Warning: Can't guess destination: section missing, defaulting to contrib/release\n&quot; unless $section;
++ $section ||= 'contrib/release';
++
++ # next time we don't need to search everything again
++ $self-&gt;{packages}{$file}{section} = $section;
++
++ print &quot;Section is '$section'.\n&quot;;
++
++ return $section;
++}
++
++sub get_upload_newer_revisions {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ my $arch = $package-&gt;get_arch();
++ my $name = $package-&gt;get_full_name;
++ $name =~ s/^\@\d+://;
++ my $pattern = $self-&gt;get_package_class()-&gt;get_pattern($package-&gt;get_name(), undef, undef, $arch);
++ my $media = $self-&gt;_get_media_config($target);
++ my @packages;
++ foreach my $state (@{$self-&gt;{_upload_state}}) {
++ foreach my $m (keys %{$media-&gt;{$arch}}) {
++ my $path = &quot;$self-&gt;{_upload_root}/$state/$target/$m&quot;;
++ print &quot;Looking for package $package revisions for $target in $path (pattern $pattern)\n&quot; if $self-&gt;{_verbose};
++ find(
++ sub {
++ s/\d{14}\.[^.]*\.[^.]*\.\d+_//;
++ s/^\@\d+://;
++ return if ! /^$pattern/;
++ return if /\.info$/;
++ print &quot;Find $_\n&quot;;
++ push @packages, $File::Find::name if $package-&gt;check_ranges_compatibility(&quot;== $name&quot;, &quot;&lt; $_&quot;)
++ }, $path);
++ }
++ }
++ return
++ @packages;
++}
++
++sub package_in_svn {
++ my ($self, $srpm_name) = @_;
++ my $ctx = new SVN::Client(
++ auth =&gt; [SVN::Client::get_simple_provider(),
++ SVN::Client::get_simple_prompt_provider(\&amp;simple_prompt,2),
++ SVN::Client::get_username_provider()]
++ );
++
++ my $svn_entry = $ctx-&gt;ls(&quot;$self-&gt;{_svn}/$srpm_name&quot;, 'HEAD', 0);
++ if ($svn_entry) {
++ print &quot;Package $srpm_name is in the SVN\n&quot;;
++ return 1
++ }
++}
++
++sub get_svn_url {
++ my ($self) = @_;
++ $self-&gt;{_svn}
++}
++
++sub get_revisions {
++ my ($self, $package, $target, $user_context, $app_context, $filter) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for package $package revisions for $target\n&quot; if $self-&gt;{_verbose} &gt; 0;
++
++ my $arch = $app_context-&gt;{arch} || $user_context-&gt;{arch} || $package-&gt;get_arch();
++ my $media_arch = $arch eq 'noarch' ? $self-&gt;{_noarch} : $arch;
++ my $path = $arch eq 'src' ? &quot;$target/SRPMS/&quot; : &quot;$target/$media_arch/media&quot;;
++ my $media = $self-&gt;_get_section($package, $target, $user_context, $app_context);
++ my $name = $package-&gt;get_name();
++ my @packages = map { $self-&gt;get_package_class()-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ &quot;$path/$media&quot;,
++ $self-&gt;get_package_class()-&gt;get_pattern(
++ $name,
++ undef,
++ undef,
++ $package-&gt;get_arch(),
++ )
++ );
++
++ @packages = grep { $filter-&gt;($_) } @packages if $filter;
++
++ return
++ sort { $b-&gt;compare($a) } # sort by revision order
++ @packages;
++}
++
++sub reject {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++
++}
++
++sub get_archive_dir {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;{_archive_root}
++}
++
++
++# 20060801 warly
++#
++# Upload steps
++# SRPMS are uploaded in /home/mandrake/uploads/todo/$target/$media/group_id
++#
++#
++#
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload_pre.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload_pre.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Repository/Mandriva_upload_pre.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,274 @@
++# $Id: /local/youri/soft/trunk/lib/Youri/Upload/Action/RSS.pm 857 2006-01-29T10:15:43.298856Z guillaume $
++package Youri::Repository::Mandriva_upload_pre;
++
++=head1 NAME
++
++Youri::Repository::PLF - PLF repository implementation
++
++=head1 DESCRIPTION
++
++This module implements PLF repository.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Memoize;
++use File::Find 'find';
++use base qw/Youri::Repository/;
++use SVN::Client;
++use constant {
++ PACKAGE_CLASS =&gt; 'Youri::Package::URPM',
++ PACKAGE_CHARSET =&gt; 'utf8'
++};
++
++memoize('_get_section');
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ module =&gt; 'SPECS', # CVS module
++ noarch =&gt; 'i586', # noarch packages policy
++ svn =&gt; '',
++ upload_root =&gt; '',
++ @_
++ );
++
++ $self-&gt;{_module} = $options{module};
++ $self-&gt;{_noarch} = $options{noarch};
++ $self-&gt;{_svn} = $options{svn};
++ $self-&gt;{_upload_root} = $options{upload_root};
++
++ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
++ $year+=1900;
++ my $hostname = `hostname`;
++ my ($host) = $hostname =~ /([^.]*)/;
++ $self-&gt;{group_dir} = sprintf &quot;$ENV{SUDO_USER}.$host.$$.$year%02d%02d%02d%02d%02d&quot;, $mon, $mday, $hour, $min, $sec;
++}
++
++sub get_package_class {
++ return PACKAGE_CLASS;
++}
++
++sub package_in_svn {
++ my ($self, $srpm_name) = @_;
++ my $ctx = new SVN::Client(
++ auth =&gt; [SVN::Client::get_simple_provider(),
++ SVN::Client::get_simple_prompt_provider(\&amp;simple_prompt,2),
++ SVN::Client::get_username_provider()]
++ );
++
++ my $svn_entry = $ctx-&gt;ls(&quot;$self-&gt;{_svn}/&quot;, 'HEAD', 0);
++ foreach (keys %{$svn_entry}) {
++ if ($srpm_name eq $_) {
++ print &quot;Package $_ is in the SVN\n&quot;;
++ return 1
++ }
++ }
++}
++
++sub get_svn_url {
++ my ($self) = @_;
++ $self-&gt;{_svn}
++}
++
++sub get_revisions {
++ my ($self, $package, $target, $define, $filter) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for package $package revisions for $target\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ my $arch = $define-&gt;{arch} || $package-&gt;get_arch;
++ if ($arch eq 'src') {
++ $arch = 'SRPMS'
++ } else {
++ $arch .= '/media'
++ }
++ my @packages;
++ foreach my $dir ('main', 'contrib') {
++ print &quot;Looking into $self-&gt;{_install_root}/$target/$arch/$dir/release\n&quot;;
++ push @packages,
++ map { $self-&gt;get_package_class()-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ &quot;$target/$arch/$dir/release&quot; ,
++ $self-&gt;get_package_class()-&gt;get_pattern($package-&gt;get_name(),undef, undef, $arch)
++ );
++ }
++
++ @packages = grep { $filter-&gt;($_) } @packages if $filter;
++
++ return
++ sort { $b-&gt;compare($a) } # sort by revision order
++ @packages;
++}
++
++sub get_package_charset {
++ return PACKAGE_CHARSET;
++}
++
++sub get_upload_dir {
++ my ($self, $package, $target, $define) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ my $arch = $package-&gt;get_arch();
++ my $section = $self-&gt;_get_section($package, $target, $define);
++ my $media_path = $section eq 'main' ? $target : $target =~ /^cooker/ ? &quot;contrib&quot; : &quot;$target/contrib&quot;;
++ my $arch_path = $arch eq 'src' ? 'SRPMS' : 'RPMS';
++ my $force = $target =~ /_force/ ? 'force' : '';
++ $self-&gt;{_upload_root} . &quot;/$media_path/$force/$arch_path/&quot;
++}
++
++sub get_arch {
++ my ($self, $package, $target, $define) = @_;
++ my $arch = $package-&gt;get_arch();
++ if ($arch eq 'noarch') {
++ $arch = $self-&gt;{_noarch}
++ }
++ $arch
++}
++
++sub get_install_path {
++ my ($self, $package, $target, $define) = @_;
++
++ return $self-&gt;_get_path($package, $target, $define);
++}
++
++sub get_archive_path {
++ my ($self, $package, $target, $define) = @_;
++
++ return $self-&gt;_get_path($package, $target, $define);
++}
++
++sub _get_path {
++ my ($self, $package, $target, $define) = @_;
++
++ my $arch = $package-&gt;get_arch;
++ if ($arch eq 'src') {
++ $arch = 'SRPMS'
++ } else {
++ $arch .= '/media'
++ }
++ my $section = $self-&gt;_get_section($package, $target, $define);
++
++ return &quot;$target/$arch/$section/release/&quot;;
++}
++
++
++sub get_version_path {
++ my ($self, $package, $target, $define) = @_;
++
++ my $section = $self-&gt;_get_section($package, $target, $define);
++
++ return &quot;$self-&gt;{_module}/$section/release/&quot;;
++}
++
++=head2 get_replaced_packages($package, $target, $define)
++
++Overrides parent method to add libified packages.
++
++=cut
++
++sub get_replaced_packages {
++ my ($self, $package, $target, $define) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my @replaced_packages =
++ $self-&gt;SUPER::get_replaced_packages($package, $target, $define);
++
++ # mandriva lib policy:
++ # library package names change with revision, making mandatory to
++ # duplicate older revisions search with a custom pattern
++ my $name = $package-&gt;get_name();
++ if ($name =~ /^(lib\w+[a-zA-Z_])[\d_\.]+([-\w]*)$/) {
++ push(@replaced_packages,
++ grep { $package-&gt;compare($_) &gt; 0 }
++ map { PACKAGE_CLASS-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ $self-&gt;get_install_path($package, $target, $define),
++ PACKAGE_CLASS-&gt;get_pattern(
++ $1 . '[\d_\.]+' . $2, # custom name pattern
++ undef,
++ undef,
++ $package-&gt;get_arch()
++ ),
++ )
++ );
++ }
++
++ return @replaced_packages;
++
++}
++
++sub _get_section {
++ my ($self, $package, $target, $define) = @_;
++
++ my $section;
++
++ # try to find section automatically
++ my $arch = $package-&gt;get_arch();
++ $arch = $self-&gt;{_noarch} if $arch eq 'noarch';
++
++ my $source_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $package-&gt;get_canonical_name(),
++ undef,
++ undef,
++ 'src'
++ );
++
++ my $binary_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $package-&gt;get_name(),
++ undef,
++ undef,
++ $arch
++ );
++
++ # for each potential section, try to match
++ # a suitable source patten in source directory
++ # a suitable binary patten in binary directory
++ foreach my $dir (qw/main contrib/) {
++ next unless
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ &quot;$target/SRPMS/$dir/release&quot;,
++ $source_pattern
++ ) || $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ &quot;$target/$arch/media/$dir/release&quot;,
++ $binary_pattern
++ );
++ print &quot;Section is $dir\n&quot;;
++ $section = $dir;
++ last;
++ }
++
++ # use defined section if not found
++ $section = $define-&gt;{section} unless $section;
++
++ $section || 'contrib'
++}
++
++sub get_upload_newer_revisions {
++ my ($self, $package, $target, $define) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ my $arch = $package-&gt;get_arch();
++ my $pattern = $self-&gt;get_package_class()-&gt;get_pattern($package-&gt;get_name(), undef, undef, $arch);
++ print &quot;Looking for package $package revisions for $target in $self-&gt;{_upload_root} (pattern $pattern)\n&quot;;
++ my @packages;
++ foreach my $dir ('cooker', 'contrib') {
++ find(sub { return if ! /^$pattern/; print &quot;Find $_\n&quot;; push @packages, $File::Find::name if $package-&gt;compare($self-&gt;get_package_class()-&gt;new(file =&gt; $File::Find::name)) &lt;= 0 }, &quot;$self-&gt;{_upload_root}/$dir&quot;);
++ }
++ return
++ @packages;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Repository/PLF.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Repository/PLF.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Repository/PLF.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,196 @@
++# $Id: /local/youri/soft/trunk/lib/Youri/Upload/Action/RSS.pm 857 2006-01-29T10:15:43.298856Z guillaume $
++package Youri::Repository::PLF;
++
++=head1 NAME
++
++Youri::Repository::PLF - PLF repository implementation
++
++=head1 DESCRIPTION
++
++This module implements PLF repository.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use Memoize;
++use base qw/Youri::Repository/;
++use constant {
++ PACKAGE_CLASS =&gt; 'Youri::Package::URPM',
++ PACKAGE_CHARSET =&gt; 'utf8'
++};
++
++memoize('_get_section');
++
++
++sub _init {
++ my $self = shift;
++ my %options = (
++ module =&gt; 'SPECS', # CVS module
++ noarch =&gt; 'noarch', # noarch packages policy
++ @_
++ );
++
++ $self-&gt;{_module} = $options{module};
++ $self-&gt;{_noarch} = $options{noarch};
++}
++
++sub get_package_class {
++ return PACKAGE_CLASS;
++}
++
++sub get_package_charset {
++ return PACKAGE_CHARSET;
++}
++
++sub get_install_path {
++ my ($self, $package, $target, $define) = @_;
++
++ return $self-&gt;_get_path($package, $target, $define);
++}
++
++sub get_archive_path {
++ my ($self, $package, $target, $define) = @_;
++
++ return $self-&gt;_get_path($package, $target, $define);
++}
++
++sub _get_path {
++ my ($self, $package, $target, $define) = @_;
++
++ my $section = $self-&gt;_get_section($package, $target, $define);
++
++ my $subpath = $self-&gt;_get_subpath($package, $target);
++
++ return &quot;$section/$subpath&quot;;
++}
++
++
++sub get_version_path {
++ my ($self, $package, $target, $define) = @_;
++
++ my $section = $self-&gt;_get_section($package, $target, $define);
++
++ return &quot;$self-&gt;{_module}/$section&quot;;
++}
++
++=head2 get_replaced_packages($package, $target, $define)
++
++Overrides parent method to add libified packages.
++
++=cut
++
++sub get_replaced_packages {
++ my ($self, $package, $target, $define) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ my @replaced_packages =
++ $self-&gt;SUPER::get_replaced_packages($package, $target, $define);
++
++ # mandriva lib policy:
++ # library package names change with revision, making mandatory to
++ # duplicate older revisions search with a custom pattern
++ my $name = $package-&gt;get_name();
++ if ($name =~ /^(lib\w+[a-zA-Z_])[\d_\.]+([-\w]*)$/) {
++ push(@replaced_packages,
++ grep { $package-&gt;compare($_) &gt; 0 }
++ map { PACKAGE_CLASS-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ $self-&gt;get_install_path($package, $target, $define),
++ PACKAGE_CLASS-&gt;get_pattern(
++ $1 . '[\d_\.]+' . $2, # custom name pattern
++ undef,
++ undef,
++ $package-&gt;get_arch()
++ ),
++ )
++ );
++ }
++
++ return @replaced_packages;
++
++}
++
++sub _get_section {
++ my ($self, $package, $target, $define) = @_;
++
++ my $section;
++
++ # try to find section automatically
++ my $arch = $package-&gt;get_arch();
++
++ my $source_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $package-&gt;get_canonical_name(),
++ undef,
++ undef,
++ 'src'
++ );
++
++ my $binary_pattern = PACKAGE_CLASS-&gt;get_pattern(
++ $package-&gt;get_name(),
++ undef,
++ undef,
++ $arch
++ );
++
++ my $source_subpath = $self-&gt;_get_subpath($package, $target, 'src');
++ my $binary_subpath = $self-&gt;_get_subpath($package, $target, $arch);
++
++ # for each potential section, try to match
++ # a suitable source patten in source directory
++ # a suitable binary patten in binary directory
++ foreach my $dir (qw/free non-free/) {
++ next unless
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ &quot;$dir/$source_subpath&quot;,
++ $source_pattern
++ ) || $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ &quot;$dir/$binary_subpath&quot;,
++ $binary_pattern
++ );
++ $section = $dir;
++ last;
++ }
++
++ # use defined section if not found
++ $section = $define-&gt;{section} unless $section;
++
++ die &quot;Can't guess destination: section missing&quot; unless $section;
++
++ return $section;
++}
++
++sub _get_subpath {
++ my ($self, $package, $target, $arch) = @_;
++
++ my $subpath;
++
++ # use package arch if not specified
++ $arch = $package-&gt;get_arch() unless $arch;
++
++ if ($arch eq 'src') {
++ $subpath = 'src';
++ } else {
++ if ($arch eq 'noarch') {
++ $subpath = &quot;$target/$self-&gt;{_noarch}&quot;;
++ } else {
++ $subpath = &quot;$target/$arch&quot;;
++ }
++ }
++
++ return $subpath;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Repository.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Repository.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Repository.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,492 @@
++# $Id: Base.pm 631 2006-01-26 22:22:23Z guillomovitch $
++package Youri::Repository;
++
++=head1 NAME
++
++Youri::Repository - Abstract repository
++
++=head1 DESCRIPTION
++
++This abstract class defines Youri::Repository interface.
++
++=cut
++
++use warnings;
++use strict;
++use Carp;
++use File::Basename;
++use Youri::Package;
++
++=head1 CLASS METHODS
++
++
++=head2 new(%args)
++
++Creates and returns a new Youri::Repository 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 &quot;Abstract class&quot; if $class eq __PACKAGE__;
++
++ my %options = (
++ install_root =&gt; '', # path to top-level directory
++ archive_root =&gt; '', # path to top-level directory
++ version_root =&gt; '', # path to top-level directory
++ test =&gt; 0, # test mode
++ verbose =&gt; 0, # verbose mode
++ @_
++ );
++
++
++ croak &quot;no install root&quot; unless $options{install_root};
++ croak &quot;invalid install root&quot; unless -d $options{install_root};
++
++ my $self = bless {
++ _install_root =&gt; $options{install_root},
++ _archive_root =&gt; $options{archive_root},
++ _version_root =&gt; $options{version_root},
++ _test =&gt; $options{test},
++ _verbose =&gt; $options{verbose},
++ }, $class;
++
++ $self-&gt;_init(%options);
++
++ return $self;
++}
++
++sub _init {
++ # do nothing
++}
++
++=head1 INSTANCE METHODS
++
++=head2 get_package_class()
++
++Return package class for this repository.
++
++=cut
++
++sub get_package_class {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ return $self-&gt;{_package_class};
++}
++
++=head2 get_package_charset()
++
++Return package charset for this repository.
++
++=cut
++
++sub get_package_charset {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ return $self-&gt;{_package_charset};
++}
++
++=head2 get_extra_arches()
++
++Return the list of additional archictectures to handle when dealing with noarch
++packages.
++
++=cut
++
++sub get_extra_arches {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ return @{$self-&gt;{_extra_arches}};
++}
++
++
++=head2 get_older_revisions($package, $target, $user_context, $app_context)
++
++Get all older revisions from a package found in its installation directory, as a
++list of L&lt;Youri::Package&gt; objects.
++
++=cut
++
++sub get_older_revisions {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for package $package older revisions for $target\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ return $self-&gt;get_revisions(
++ $package,
++ $target,
++ $user_context,
++ $app_context,
++ sub { return $package-&gt;compare($_[0]) &gt; 0 }
++ );
++}
++
++=head2 get_last_older_revision($package, $target, $user_context, $app_context)
++
++Get last older revision from a package found in its installation directory, as a
++single L&lt;Youri::Package&gt; object.
++
++=cut
++
++sub get_last_older_revision {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for package $package last older revision for $target\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ return (
++ $self-&gt;get_older_revisions(
++ $package,
++ $target,
++ $user_context,
++ $app_context
++ )
++ )[0];
++}
++
++=head2 get_newer_revisions($package, $target, $user_context, $app_context)
++
++Get all newer revisions from a package found in its installation directory, as
++a list of L&lt;Youri::Package&gt; objects.
++
++=cut
++
++sub get_newer_revisions {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for package $package newer revisions for $target\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ return $self-&gt;get_revisions(
++ $package,
++ $target,
++ $user_context,
++ $app_context,
++ sub { return $_[0]-&gt;compare($package) &gt; 0 }
++ );
++}
++
++
++=head2 get_revisions($package, $target, $user_context, $app_context, $filter)
++
++Get all revisions from a package found in its installation directory, using an
++optional filter, as a list of L&lt;Youri::Package&gt; objects.
++
++=cut
++
++sub get_revisions {
++ my ($self, $package, $target, $user_context, $app_context, $filter) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for package $package revisions for $target\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ my @packages =
++ map { $self-&gt;get_package_class()-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ $self-&gt;get_install_path(
++ $package,
++ $target,
++ $user_context,
++ $app_context
++ ),
++ $self-&gt;get_package_class()-&gt;get_pattern(
++ $package-&gt;get_name(),
++ undef,
++ undef,
++ $package-&gt;get_arch(),
++ )
++ );
++ @packages = grep { $filter-&gt;($_) } @packages if $filter;
++
++ return
++ sort { $b-&gt;compare($a) } # sort by revision order
++ @packages;
++}
++
++=head2 get_obsoleted_packages($package, $target, $user_context, $app_context)
++
++Get all packages obsoleted by given one, as a list of L&lt;Youri::Package&gt;
++objects.
++
++=cut
++
++sub get_obsoleted_packages {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for packages obsoleted by $package for $target\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ my @packages;
++ foreach my $obsolete ($package-&gt;get_obsoletes()) {
++ my $pattern = $self-&gt;get_package_class()-&gt;get_pattern($obsolete-&gt;[Youri::Package::DEPENDENCY_NAME]);
++ my $range = $obsolete-&gt;[Youri::Package::DEPENDENCY_RANGE];
++ push(@packages,
++ grep { $range ? $_-&gt;satisfy_range($range) : 1 }
++ map { $self-&gt;get_package_class()-&gt;new(file =&gt; $_) }
++ $self-&gt;get_files(
++ $self-&gt;{_install_root},
++ $self-&gt;get_install_path(
++ $package, $target,
++ $user_context,
++ $app_context
++ ),
++ $pattern
++ )
++ );
++ }
++
++ return @packages;
++}
++
++=head2 get_replaced_packages($package, $target, $user_context, $app_context)
++
++Get all packages replaced by given one, as a list of L&lt;Youri::Package&gt;
++objects.
++
++=cut
++
++sub get_replaced_packages {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ print &quot;Looking for packages replaced by $package for $target\n&quot;
++ if $self-&gt;{_verbose} &gt; 0;
++
++ my @list;
++
++ # collect all older revisions
++ push(@list, $self-&gt;get_older_revisions(
++ $package,
++ $target,
++ $user_context,
++ $app_context
++ ));
++
++ # noarch packages are potentially linked from other directories
++ if ($package-&gt;get_arch() eq 'noarch') {
++ foreach my $arch ($self-&gt;get_extra_arches()) {
++ push(@list, $self-&gt;get_older_revisions(
++ $package,
++ $target,
++ $user_context,
++ { arch =&gt; $arch }
++ ));
++ }
++ }
++
++ # collect all obsoleted packages
++ push(@list, $self-&gt;get_obsoleted_packages(
++ $package,
++ $target,
++ $user_context,
++ $app_context
++ ));
++
++ return @list;
++}
++
++=head2 get_files($path, $pattern)
++
++Get all files found in a directory, using an optional filtering pattern
++(applied to the whole file name), as a list of files.
++
++=cut
++
++sub get_files {
++ my ($self, $root, $path, $pattern) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++ # debugging for bug 34999
++ print &quot;Looking for files matching $pattern in $root/$path\n&quot;;
++# if $self-&gt;{_verbose} &gt; 1;
++
++ my $grep = &quot;&quot;;
++ $grep = &quot;-regextype posix-egrep -regex '.*\/$pattern'&quot; if ($pattern);
++ # XXX: run find in a directory the user is guaranteed to have read
++ # permissions! find simply exits with error if the user doesn't have
++ # read permission on the *current* dir; as this code is run thru many
++ # sudo invocations, sometimes the user calling it has $HOME chmoded to
++ # 0700, making find fail when run as mandrake
++ # debugging for bug 34999
++ print &quot;.. running command: find -L $root/$path $grep -type f\n&quot;;
++ my @files = map { chop; $_; } `cd &amp;&amp; find -L $root/$path $grep -type f`;
++ die &quot;FATAL: get_files(): find failed!&quot; if ($?);
++
++ return @files;
++}
++
++=head2 get_install_root()
++
++Returns installation root
++
++=cut
++
++sub get_install_root {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_install_root};
++}
++
++
++=head2 get_distribution_roots()
++
++Returns distribution roots (ie install_root + target + arch)
++(it returns a list in case of noarch)
++
++=cut
++
++sub get_distribution_roots {
++ my ($self, $package, $target) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ map {
++ $self-&gt;_get_dir($self-&gt;{_install_root}, $_);
++ } $self-&gt;get_distribution_paths($package, $target);
++}
++
++=head2 get_install_dir($package, $target, $user_context, $app_context)
++
++Returns install destination directory for given L&lt;Youri::Package&gt; object
++and given target.
++
++=cut
++
++sub get_install_dir {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;_get_dir(
++ $self-&gt;{_install_root},
++ $self-&gt;get_install_path($package, $target, $user_context, $app_context)
++ );
++}
++
++=head2 get_archive_root()
++
++Returns archiving root
++
++=cut
++
++sub get_archive_root {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_archive_root};
++}
++
++=head2 get_archive_dir($package, $target, $user_context, $app_context)
++
++Returns archiving destination directory for given L&lt;Youri::Package&gt; object
++and given target.
++
++=cut
++
++sub get_archive_dir {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;_get_dir(
++ $self-&gt;{_archive_root},
++ $self-&gt;get_archive_path($package, $target, $user_context, $app_context)
++ );
++}
++
++
++=head2 get_version_root()
++
++Returns versionning root
++
++=cut
++
++sub get_version_root {
++ my ($self) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;{_version_root};
++}
++
++=head2 get_version_dir($package, $target, $user_context, $app_context)
++
++Returns versioning destination directory for given L&lt;Youri::Package&gt;
++object and given target.
++
++=cut
++
++sub get_version_dir {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return $self-&gt;_get_dir(
++ $self-&gt;{_version_root},
++ $self-&gt;get_version_path($package, $target, $user_context, $app_context)
++ );
++}
++
++sub _get_dir {
++ my ($self, $root, $path) = @_;
++
++ return substr($path, 0, 1) eq '/' ?
++ $path :
++ $root . '/' . $path;
++}
++
++=head2 get_install_file($package, $target, $user_context, $app_context)
++
++Returns install destination file for given L&lt;Youri::Package&gt; object and
++given target.
++
++=cut
++
++sub get_install_file {
++ my ($self, $package, $target, $user_context, $app_context) = @_;
++ croak &quot;Not a class method&quot; unless ref $self;
++
++ return
++ $self-&gt;get_install_dir($package, $target, $user_context, $app_context) .
++ '/' .
++ $package-&gt;get_file_name();
++}
++
++=head2 get_install_path($package, $target, $user_context, $app_context)
++
++Returns installation destination path (relative to repository root) for given
++L&lt;Youri::Package&gt; object and given target.
++
++=head2 get_archive_path($package, $target, $user_context, $app_context)
++
++Returns archiving destination path (relative to repository root) for given
++L&lt;Youri::Package&gt; object and given target.
++
++=head2 get_version_path($package, $target, $user_context, $app_context)
++
++Returns versioning destination path (relative to repository root) for given
++L&lt;Youri::Package&gt; object and given target.
++
++=head1 SUBCLASSING
++
++The following methods have to be implemented:
++
++=over
++
++=item get_install_path
++
++=item get_archive_path
++
++=item get_version_path
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/lib/Youri/Utils.pm
+===================================================================
+--- build_system/mdv-youri-core/trunk/lib/Youri/Utils.pm (rev 0)
++++ build_system/mdv-youri-core/trunk/lib/Youri/Utils.pm 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,98 @@
++# $Id: Utils.pm 1713 2006-10-16 16:39:53Z warly $
++package Youri::Utils;
++
++=head1 NAME
++
++Youri::Utils - Youri shared functions
++
++=head1 DESCRIPTION
++
++This module implement some helper functions for all youri applications.
++
++=cut
++
++use base qw(Exporter);
++use Carp;
++use strict;
++use warnings;
++
++our @EXPORT = qw(
++ create_instance
++ load_class
++ add2hash
++ add2hash_
++);
++
++=head2 create_instance($class, $config, $options)
++
++Create an instance from a plugin implementing given interface, using given
++configuration and local options.
++Returns a plugin instance, or undef if something went wrong.
++
++=cut
++
++sub create_instance {
++ my ($interface, $config, $options) = @_;
++
++ croak 'No interface given' unless $interface;
++ croak 'No config given' unless $config;
++
++ my $class = $config-&gt;{class};
++ if (!$class) {
++ carp &quot;No class given, can't load plugin&quot;;
++ return;
++ }
++
++ # ensure loaded
++ load_class($class);
++
++ # check interface
++ if (!$class-&gt;isa($interface)) {
++ carp &quot;$class is not a $interface&quot;;
++ return;
++ }
++
++ # instantiate
++ no strict 'refs';
++
++ return $class-&gt;new(
++ $config-&gt;{options} ? %{$config-&gt;{options}} : (),
++ $options ? %{$options} : (),
++ );
++}
++
++sub load_class {
++ my ($class) = @_;
++
++ $class .= '.pm';
++ $class =~ s/::/\//g;
++ require $class;
++}
++
++# structure helpers
++
++sub add2hash {
++ my ($a, $b) = @_;
++ while (my ($k, $v) = each %{$b || {}}) {
++ $a-&gt;{$k} ||= $v;
++ }
++ return $a;
++}
++
++sub add2hash_ {
++ my ($a, $b) = @_;
++ while (my ($k, $v) = each %{$b || {}}) {
++ exists $a-&gt;{$k} or $a-&gt;{$k} = $v;
++ }
++ return $a;
++}
++
++=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;
+
+Added: build_system/mdv-youri-core/trunk/t/00distribution.t
+===================================================================
+--- build_system/mdv-youri-core/trunk/t/00distribution.t (rev 0)
++++ build_system/mdv-youri-core/trunk/t/00distribution.t 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,15 @@
++#!/usr/bin/perl
++# $Id: 00distribution.t 1179 2006-08-05 08:30:57Z warly $
++
++use Test::More;
++
++BEGIN {
++ eval {
++ require Test::Distribution;
++ };
++ if($@) {
++ plan skip_all =&gt; 'Test::Distribution not installed';
++ } else {
++ import Test::Distribution only =&gt; [ qw/use pod description/ ];
++ }
++}
+
+
+Property changes on: build_system/mdv-youri-core/trunk/t/00distribution.t
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: build_system/mdv-youri-core/trunk/t/cowsay-3.03-11mdv2007.0.noarch.rpm
+===================================================================
+(Binary files differ)
+
+
+Property changes on: build_system/mdv-youri-core/trunk/t/cowsay-3.03-11mdv2007.0.noarch.rpm
+___________________________________________________________________
+Added: svn:mime-type
+ + application/octet-stream
+
+Added: build_system/mdv-youri-core/trunk/t/gpghome/pubring.gpg
+===================================================================
+(Binary files differ)
+
+
+Property changes on: build_system/mdv-youri-core/trunk/t/gpghome/pubring.gpg
+___________________________________________________________________
+Added: svn:mime-type
+ + application/octet-stream
+
+Added: build_system/mdv-youri-core/trunk/t/gpghome/secring.gpg
+===================================================================
+(Binary files differ)
+
+
+Property changes on: build_system/mdv-youri-core/trunk/t/gpghome/secring.gpg
+___________________________________________________________________
+Added: svn:mime-type
+ + application/octet-stream
+
+Added: build_system/mdv-youri-core/trunk/t/gpghome/trustdb.gpg
+===================================================================
+(Binary files differ)
+
+
+Property changes on: build_system/mdv-youri-core/trunk/t/gpghome/trustdb.gpg
+___________________________________________________________________
+Added: svn:mime-type
+ + application/octet-stream
+
+Added: build_system/mdv-youri-core/trunk/t/package.t
+===================================================================
+--- build_system/mdv-youri-core/trunk/t/package.t (rev 0)
++++ build_system/mdv-youri-core/trunk/t/package.t 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,482 @@
++#!/usr/bin/perl
++# $Id: /local/youri/soft/trunk/t/version.t 2257 2006-07-05T09:22:47.088572Z guillaume $
++
++use Test::More;
++use Test::Exception;
++use Youri::Utils;
++use File::Temp qw/tempdir/;
++use File::Basename;
++use strict;
++
++my @classes = qw/
++ Youri::Package::URPM
++ Youri::Package::RPM4
++/;
++my $dir = dirname($0);
++my $rpm = 'cowsay-3.03-11mdv2007.0.noarch.rpm';
++my $fake_rpm = 'foobar.rpm';
++plan(tests =&gt; 37 * scalar @classes);
++
++foreach my $class (@classes) {
++ load_class($class);
++
++ my $temp_dir = tempdir(CLEANUP =&gt; 1);
++ my $file = &quot;$dir/$rpm&quot;;
++ my $fake_file = &quot;$temp_dir/$fake_rpm&quot;;
++
++ # instanciation errors
++ dies_ok { $class-&gt;new(file =&gt; undef) } 'undefined file';
++ dies_ok { $class-&gt;new(file =&gt; $fake_file) } 'non-existant file';
++ system('touch', $fake_file);
++ chmod 0000, $fake_file;
++ dies_ok { $class-&gt;new(file =&gt; $fake_file) } 'non-readable file';
++ chmod 0644, $fake_file;
++ dies_ok { $class-&gt;new(file =&gt; $fake_file) } 'non-rpm file';
++
++ my $package = $class-&gt;new(file =&gt; $file);
++ isa_ok($package, $class);
++
++ # tag value access
++ is($package-&gt;get_name(), 'cowsay', 'get name directly');
++ is($package-&gt;get_tag('name'), 'cowsay', 'get name indirectly');
++ is($package-&gt;get_version(), '3.03', 'get version directly');
++ is($package-&gt;get_tag('version'), '3.03', 'get version indirectly');
++ is($package-&gt;get_release(), '11mdv2007.0', 'get release directly');
++ is($package-&gt;get_tag('release'), '11mdv2007.0', 'get release indirectly');
++ is($package-&gt;get_arch(), 'noarch', 'get arch directly');
++ is($package-&gt;get_tag('arch'), 'noarch', 'get arch indirectly');
++ is($package-&gt;get_summary(), 'Configurable talking cow', 'get summary directly');
++ is($package-&gt;get_tag('summary'), 'Configurable talking cow', 'get summary indirectly');
++ is($package-&gt;get_url(), '<A HREF="http://www.nog.net/~tony/warez/cowsay.shtml">http://www.nog.net/~tony/warez/cowsay.shtml</A>', 'get url directly');
++ is($package-&gt;get_tag('url'), '<A HREF="http://www.nog.net/~tony/warez/cowsay.shtml">http://www.nog.net/~tony/warez/cowsay.shtml</A>', 'get url indirectly');
++ is($package-&gt;get_packager(), 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandriva.org</A>&gt;', 'get packager directly');
++ is($package-&gt;get_tag('packager'), 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandriva.org</A>&gt;', 'get packager indirectly');
++ is($package-&gt;get_file_name(), 'cowsay-3.03-11mdv2007.0.noarch.rpm', 'file name');
++ is($package-&gt;get_revision(), '3.03-11mdv2007.0', 'revision');
++
++ # name formating
++ is($package-&gt;as_formated_string('%{name}-%{version}-%{release}'), 'cowsay-3.03-11mdv2007.0', 'formated string name');
++ is($package-&gt;as_string(), 'cowsay-3.03-11mdv2007.0.noarch', 'default string');
++ is($package, 'cowsay-3.03-11mdv2007.0.noarch', 'stringification');
++
++ # type
++ ok(!$package-&gt;is_source(), 'not a source package');
++ ok($package-&gt;is_binary(), 'a binary package');
++ is($package-&gt;get_type(), 'binary', 'a binary package');
++
++ # gpg key
++ is($package-&gt;get_gpg_key(), '26752624', 'get gpg key');
++
++ # dependencies
++ is_deeply(
++ [ $package-&gt;get_requires() ],
++ [
++ [ 'perl-base', undef ],
++ [ 'perl(Cwd)', undef ],
++ [ 'perl(File::Basename)', undef ],
++ [ 'perl(Getopt::Std)', undef ],
++ [ 'perl(Text::Tabs)', undef ],
++ [ 'perl(Text::Wrap)', undef ]
++ ],
++ 'requires'
++ );
++ is_deeply(
++ [ $package-&gt;get_provides() ],
++ [
++ [ 'cowsay', '== 3.03-11mdv2007.0']
++ ],
++ 'provides'
++ );
++ is_deeply(
++ [ $package-&gt;get_obsoletes() ],
++ [ ],
++ 'obsoletes'
++ );
++ is_deeply(
++ [ $package-&gt;get_conflicts() ],
++ [ ],
++ 'conflicts'
++ );
++
++ # files
++ is_deeply(
++ [ $package-&gt;get_files() ],
++ [
++ [
++ '/etc/bash_completion.d/cowsay',
++ 33188,
++ '6048be1dd827011c15cab0c3db1f438d'
++ ],
++ [
++ '/usr/bin/cowsay',
++ 33261,
++ 'b405026c6040eeb4781ca5c523129fe4'
++ ],
++ [
++ '/usr/bin/cowthink',
++ 41471,
++ ''
++ ],
++ [
++ '/usr/share/cows',
++ 16877,
++ ''
++ ],
++ [
++ '/usr/share/cows/beavis.zen.cow',
++ 33188,
++ '582b2ddb72122d3aa078730abd0456b3'
++ ],
++ [
++ '/usr/share/cows/bong.cow',
++ 33188,
++ '045f9bf39c027dded9a7145f619bac02'
++ ],
++ [
++ '/usr/share/cows/bud-frogs.cow',
++ 33188,
++ '5c61632eb06305d613061882e1955cd2'
++ ],
++ [
++ '/usr/share/cows/bunny.cow',
++ 33188,
++ '05eb914d3b96aea903542cb29f5c42c7'
++ ],
++ [
++ '/usr/share/cows/cheese.cow',
++ 33188,
++ 'f3618110a22d8e9ecde888c1f5e38b61'
++ ],
++ [
++ '/usr/share/cows/cower.cow',
++ 33188,
++ 'd73ea60eec692555a34a9f3eec981578'
++ ],
++ [
++ '/usr/share/cows/daemon.cow',
++ 33188,
++ 'a7dd7588ee0386a0f29e88e4881885ee'
++ ],
++ [
++ '/usr/share/cows/default.cow',
++ 33188,
++ 'f1206515a0f27e9d5cf09c188e46bc82'
++ ],
++ [
++ '/usr/share/cows/dragon-and-cow.cow',
++ 33188,
++ '0ca99b8edd1a9d14fd231a88d9746b39'
++ ],
++ [
++ '/usr/share/cows/dragon.cow',
++ 33188,
++ '448f736bf56dccafa2635e71e7485345'
++ ],
++ [
++ '/usr/share/cows/duck.cow',
++ 33188,
++ 'd8ffcd64667d2e3697a3e8b65e8bea9d'
++ ],
++ [
++ '/usr/share/cows/elephant-in-snake.cow',
++ 33188,
++ 'c5a9f406277e0e8a674bd3ffb503738f'
++ ],
++ [
++ '/usr/share/cows/elephant.cow',
++ 33188,
++ 'e355c72e893787376c047805d4a1fe9d'
++ ],
++ [
++ '/usr/share/cows/eyes.cow',
++ 33188,
++ 'b2eb5b612fae17877895aa6edafa0a5f'
++ ],
++ [
++ '/usr/share/cows/flaming-sheep.cow',
++ 33188,
++ '3213cfa04a069f42d71115ca623a2f95'
++ ],
++ [
++ '/usr/share/cows/ghostbusters.cow',
++ 33188,
++ 'df294e6278bcb275aecb0fbd6b2546ba'
++ ],
++ [
++ '/usr/share/cows/girafe.cow',
++ 33188,
++ '6d2e142313109b6a5a0a45dba0f11351'
++ ],
++ [
++ '/usr/share/cows/head-in.cow',
++ 33188,
++ '365287a5d1f34a53f8716285e79c28df'
++ ],
++ [
++ '/usr/share/cows/hellokitty.cow',
++ 33188,
++ 'e0bbea69c4cbcfb3d799740ccc8a0b0e'
++ ],
++ [
++ '/usr/share/cows/kenny.cow',
++ 33188,
++ '16ce8c334a7547197ac4c9e8a1d6ae90'
++ ],
++ [
++ '/usr/share/cows/kiss.cow',
++ 33188,
++ '2a7bdd4a20741b7769af463bf09e64e8'
++ ],
++ [
++ '/usr/share/cows/kitty.cow',
++ 33188,
++ '76d65a3ebfbacb16a654c1aa1af6ed27'
++ ],
++ [
++ '/usr/share/cows/koala.cow',
++ 33188,
++ 'cc524706707f32253dd06fc548334f11'
++ ],
++ [
++ '/usr/share/cows/kosh.cow',
++ 33188,
++ 'e4e28e0f472bd524fd1b44c67ae357c2'
++ ],
++ [
++ '/usr/share/cows/luke-koala.cow',
++ 33188,
++ '63bbc35da73cd22b8cf25f86dcf9f870'
++ ],
++ [
++ '/usr/share/cows/mech-and-cow',
++ 33188,
++ '12c0320b33704d8564dd97278d056204'
++ ],
++ [
++ '/usr/share/cows/meow.cow',
++ 33188,
++ 'a6092008647ed37cfe1663d10e388cbb'
++ ],
++ [
++ '/usr/share/cows/milk.cow',
++ 33188,
++ 'd26ac36e13e77dabb408e104fc8e0167'
++ ],
++ [
++ '/usr/share/cows/moofasa.cow',
++ 33188,
++ '5fcdd4a9f3bf521c337af0a066b14512'
++ ],
++ [
++ '/usr/share/cows/moose.cow',
++ 33188,
++ 'dcfa09df7d2b9afa112dab374bf06e99'
++ ],
++ [
++ '/usr/share/cows/mutilated.cow',
++ 33188,
++ '24cdaef0a29fb44dc673abf19a8ba631'
++ ],
++ [
++ '/usr/share/cows/phaco.cow',
++ 33188,
++ 'f277c1bf92ce2a3f6058955ba93758aa'
++ ],
++ [
++ '/usr/share/cows/pumpkin.cow',
++ 33188,
++ 'c661ea78714c1ce31559f77d73694473'
++ ],
++ [
++ '/usr/share/cows/ren.cow',
++ 33188,
++ '3d7941d454779e000adc1c91e5f0b20b'
++ ],
++ [
++ '/usr/share/cows/satanic.cow',
++ 33188,
++ 'a69ca42a31486757ddcb322a1e68f886'
++ ],
++ [
++ '/usr/share/cows/shark.cow',
++ 33188,
++ 'd8950ec63abb00bbd9d96ec63637c1ac'
++ ],
++ [
++ '/usr/share/cows/sheep.cow',
++ 33188,
++ '543b75f295cbd51326f5a40f111469f1'
++ ],
++ [
++ '/usr/share/cows/skeleton.cow',
++ 33188,
++ '64f6ec1a0c170508e72269d533492e57'
++ ],
++ [
++ '/usr/share/cows/small.cow',
++ 33188,
++ '50cb1c55628c439fc81f96db9d855252'
++ ],
++ [
++ '/usr/share/cows/sodomized.cow',
++ 33188,
++ 'b4888afcca51629cc3138b283608b837'
++ ],
++ [
++ '/usr/share/cows/stegosaurus.cow',
++ 33188,
++ 'fb0e45d101a3ecba9cf6e112facbbc7e'
++ ],
++ [
++ '/usr/share/cows/stimpy.cow',
++ 33188,
++ '9b4ec6e0750ba0eeaaa432d8d3413559'
++ ],
++ [
++ '/usr/share/cows/supermilker.cow',
++ 33188,
++ '316573fb585e4a6b375373c85be025b1'
++ ],
++ [
++ '/usr/share/cows/surgery.cow',
++ 33188,
++ '7f25005083c1fde19d4e548c005ef000'
++ ],
++ [
++ '/usr/share/cows/telebears.cow',
++ 33188,
++ '15f00abb070d9018ce6ef3441e936ef4'
++ ],
++ [
++ '/usr/share/cows/three-eyes.cow',
++ 33188,
++ 'c85faef9496f4a5b111bd92bfd7e7528'
++ ],
++ [
++ '/usr/share/cows/turkey.cow',
++ 33188,
++ '484b5bc69c09d420d7fd5586d8570f04'
++ ],
++ [
++ '/usr/share/cows/turtle.cow',
++ 33188,
++ '87eed5a00e88860b78dbec04efcdede3'
++ ],
++ [
++ '/usr/share/cows/tux.cow',
++ 33188,
++ 'dc1db4eac66c99179ef6adb15dd75bda'
++ ],
++ [
++ '/usr/share/cows/udder.cow',
++ 33188,
++ 'd97f78887c3b218a54876edc51f2963b'
++ ],
++ [
++ '/usr/share/cows/vader-koala.cow',
++ 33188,
++ '7b5dd51278f0fa217a70a9b499f97a07'
++ ],
++ [
++ '/usr/share/cows/vader.cow',
++ 33188,
++ '97b4ef9fc4c26082f253e9f0f35c4590'
++ ],
++ [
++ '/usr/share/cows/www.cow',
++ 33188,
++ 'ef4c0bc8330f329666e1705f97f283cc'
++ ],
++ [
++ '/usr/share/doc/cowsay-3.03',
++ 16877,
++ ''
++ ],
++ [
++ '/usr/share/doc/cowsay-3.03/INSTALL',
++ 33188,
++ '3333fd2865107626d5dffc0dbfb7e244'
++ ],
++ [
++ '/usr/share/doc/cowsay-3.03/LICENSE',
++ 33188,
++ 'f879dda90a5a9928253a63ecd76406e6'
++ ],
++ [
++ '/usr/share/doc/cowsay-3.03/README',
++ 33188,
++ 'a5c1c61e4920c278a735cdaaca62453e'
++ ],
++ [
++ '/usr/share/man/man1/cowsay.1.bz2',
++ 33188,
++ '01fdd49d0b477f20099aae384fe8c1b2'
++ ],
++ [
++ '/usr/share/man/man1/cowthink.1.bz2',
++ 41471,
++ ''
++ ]
++ ],
++ 'files'
++ );
++
++ # changelog
++ is_deeply(
++ [ $package-&gt;get_changes() ],
++ [
++ [
++ 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandriva.org</A>&gt; 3.03-11mdv2007.0',
++ 1149847200,
++ '- %mkrel' . &quot;\n&quot; .
++ '- rpmbuildupdate aware',
++ ],
++ [
++ 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandriva.org</A>&gt; 3.03-10mdk ',
++ 1117879200,
++ '- fix man page (fix #16291)',
++ ],
++ [
++ 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandrake.org</A>&gt; 3.03-9mdk ',
++ 1090058400,
++ '- hurry businesman compliant (aka two new wonderful cows)',
++ ],
++ [
++ 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandrake.org</A>&gt; 3.03-8mdk ',
++ 1089540000,
++ '- apologies to the girafes (with one only f)',
++ ],
++ [
++ 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandrake.org</A>&gt; 3.03-7mdk ',
++ 1086429600,
++ '- #mandrakefr compliant (aka four new additional cows)',
++ ],
++ [
++ 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at linux-mandrake.com</A>&gt; 3.03-6mdk',
++ 1061460000,
++ '- save.the.world patch',
++ ]
++ ],
++ 'changelog'
++ );
++ is_deeply(
++ $package-&gt;get_last_change(),
++ [
++ 'Guillaume Rousse &lt;<A HREF="https://www.mageia.org/mailman/listinfo/mageia-sysadm">guillomovitch at mandriva.org</A>&gt; 3.03-11mdv2007.0',
++ 1149847200,
++ '- %mkrel' . &quot;\n&quot; .
++ '- rpmbuildupdate aware',
++ ],
++ 'last change'
++ );
++ is($package-&gt;compare($package), 0, 'compare');
++
++ # signature test
++ system('cp', $file, $temp_dir);
++ $package = $class-&gt;new(file =&gt; &quot;$temp_dir/$rpm&quot;);
++
++ $package-&gt;sign('Youri', 't/gpghome', 'Youri rulez');
++
++ $package = $class-&gt;new(file =&gt; &quot;$temp_dir/$rpm&quot;);
++ is($package-&gt;get_gpg_key(), '2333e817', 'get gpg key');
++}
+
+
+Property changes on: build_system/mdv-youri-core/trunk/t/package.t
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Added: build_system/mdv-youri-core/trunk/t/version.t
+===================================================================
+--- build_system/mdv-youri-core/trunk/t/version.t (rev 0)
++++ build_system/mdv-youri-core/trunk/t/version.t 2011-01-05 13:23:45 UTC (rev 210)
+@@ -0,0 +1,71 @@
++#!/usr/bin/perl
++# $Id: version.t 1179 2006-08-05 08:30:57Z warly $
++
++use Test::More;
++use Youri::Check::Input::Updates;
++use strict;
++
++my @differents = (
++ [ '3.0.0', '1.0.0' ],
++ [ '3.0.0', '1.99.9' ],
++ [ '3.0.1', '3.0' ],
++ [ '3.0pl1', '3.0' ],
++ [ '3.0', '3.0beta1' ],
++ [ '3.0', '3.0beta' ],
++ [ '3.0', '3.0alpha1' ],
++ [ '3.0', '3.0alpha' ],
++ [ '3.0', '3.0pre1' ],
++ [ '3.0', '3.0pre' ],
++ [ '3.0pre', '3.0beta' ],
++ [ '3.0beta', '3.0alpha' ],
++ [ '1.0.0-p1', '1.0.0RC1' ],
++ [ '0.9.7f', '0.9.7e' ],
++ [ '10', '9' ],
++);
++
++my @equals = (
++ [ '1.0.0', '1.0.0' ],
++ [ '0.9Beta1', '0.9beta1' ],
++ [ '0.9beta1', '0.9 beta 1' ],
++ [ '0.3-alpha', '0.3_alpha' ],
++ [ '0.02', '.02' ],
++ [ '2.0.11', '15aug2000' ],
++ [ '2.0.11', '20060401' ],
++ [ '20', '20060401' ],
++);
++
++plan tests =&gt; 2 * @differents + 2 * @equals;
++
++foreach my $different (@differents) {
++ ok(
++ Youri::Check::Input::Updates::is_newer(
++ $different-&gt;[0],
++ $different-&gt;[1]
++ ),
++ &quot;$different-&gt;[0] is newer as $different-&gt;[1]&quot;
++ );
++ ok(
++ !Youri::Check::Input::Updates::is_newer(
++ $different-&gt;[1],
++ $different-&gt;[0]
++ ),
++ &quot;$different-&gt;[1] is older as $different-&gt;[0]&quot;
++ );
++}
++
++foreach my $equal (@equals) {
++ ok(
++ !Youri::Check::Input::Updates::is_newer(
++ $equal-&gt;[0],
++ $equal-&gt;[1]
++ ),
++ &quot;$equal-&gt;[0] is equal as $equal-&gt;[1]&quot;
++ );
++ ok(
++ !Youri::Check::Input::Updates::is_newer(
++ $equal-&gt;[1],
++ $equal-&gt;[0]
++ ),
++ &quot;$equal-&gt;[1] is equal as $equal-&gt;[0]&quot;
++ );
++}
+
+
+Property changes on: build_system/mdv-youri-core/trunk/t/version.t
+___________________________________________________________________
+Added: svn:executable
+ + *
+-------------- next part --------------
+An HTML attachment was scrubbed...
+URL: &lt;/pipermail/mageia-sysadm/attachments/20110105/797a51f6/attachment-0001.html&gt;
+</PRE>
+
+
+
+
+
+
+
+
+
+<!--endarticle-->
+ <HR>
+ <P><UL>
+ <!--threads-->
+ <LI>Previous message: <A HREF="001512.html">[Mageia-sysadm] [209] add mandriva version of youri-submit, downloaded from http://svn. mandriva.com/svn/soft/build_system/youri/submit/trunk at revision 271600
+</A></li>
+ <LI>Next message: <A HREF="001514.html">[Mageia-sysadm] [654] Add ssh key for pterjan.
+</A></li>
+ <LI> <B>Messages sorted by:</B>
+ <a href="date.html#1513">[ date ]</a>
+ <a href="thread.html#1513">[ thread ]</a>
+ <a href="subject.html#1513">[ subject ]</a>
+ <a href="author.html#1513">[ author ]</a>
+ </LI>
+ </UL>
+
+<hr>
+<a href="https://www.mageia.org/mailman/listinfo/mageia-sysadm">More information about the Mageia-sysadm
+mailing list</a><br>
+</body></html>