#!/usr/bin/perl #- Synchronize mulitple RPMS/SRPMS directories. #- Copyright (C) 1999 MandrakeSoft (fpons@mandrakesoft.com) #- #- This program is free software; you can redistribute it and/or modify #- it under the terms of the GNU General Public License as published by #- the Free Software Foundation; either version 2, or (at your option) #- any later version. #- #- This program is distributed in the hope that it will be useful, #- but WITHOUT ANY WARRANTY; without even the implied warranty of #- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #- GNU General Public License for more details. #- #- You should have received a copy of the GNU General Public License #- along with this program; if not, write to the Free Software #- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use strict qw(subs vars refs); #- compare a version string. use URPM; #- get basename for a file. sub basename { $_[0] =~ /([^\/]*)$/ ? $1 : $_[0]; } #- system functions. sub cp { my $pid; if ($pid = fork()) { waitpid($pid, 0); } else { exec '/bin/cp', @_; } } sub mv { my $pid; if ($pid = fork()) { waitpid($pid, 0); } else { exec '/bin/mv', @_; } } sub rm { my $pid; if ($pid = fork()) { waitpid($pid, 0); } else { exec '/bin/rm', '-f', @_; } } #- get a hash on name of srpms/rpms in a directory. sub get_rpms { my ($dir, $rpms, $flag, $modifiable) = @_; opendir D, $dir or die "cannot open directory $dir\n"; map { if (/([^\/]*?)-([^-]*)-([^-]*)\.([^-\.]*)\.rpm$/) { my $key = "$1 $4"; #- get name including architecture. if ($rpms->{$key}) { if (URPM::ranges_overlap("== $2-$3", "> $rpms->{$key}{version}-$rpms->{$key}{release}")) { if ($modifiable) { if ($flag->{sorted}) { print "you said rpms directory is sorted, so I keep obsoleted $rpms->{$key}{file} by $_ in $rpms->{$key}{dir}\n" if $flag->{verbose}; } else { if (-d $flag->{conflict}) { print "moving obsoleted $rpms->{$key}{file} by $_ in $rpms->{$key}{dir}\n" if $flag->{verbose}; mv("$rpms->{$key}{dir}/$rpms->{$key}{file}", $flag->{conflict}); } elsif ($flag->{clean}) { print "removing obsoleted $rpms->{$key}{file} by $_ in $rpms->{$key}{dir}\n" if $flag->{verbose}; rm("$rpms->{$key}{dir}/$rpms->{$key}{file}"); } } } $rpms->{$key} = { key => $key, name => $1, version => $2, release => $3, arch => $4, dir => $dir, file => $_, }; } else { if ($modifiable) { if (-d $flag->{conflict}) { print "copying older or equal $_ by $rpms->{$key}{file} in $flag->{conflict}\n" if $flag->{verbose}; cp("$dir/$_", $flag->{conflict}); chmod 0644, "$flag->{conflict}/$_"; } elsif ($flag->{clean}) { print "removing older or equal $_ by $rpms->{$key}{file} in $dir\n" if $flag->{verbose}; rm("$dir/$_"); } } } } else { $rpms->{$key} = { key => $key, name => $1, version => $2, release => $3, arch => $4, dir => $dir, file => $_, }; } } else { print STDERR "unable to parse filename $_\n"; } } grep { /\.rpm$/ } readdir D; closedir D; } #- sync packages list according to hashes of rpms. sub sync_medium { my ($rpmsdirs, $list, $rpms, $flag) = @_; my %pkg2dir; #- build a hash according to rpmsdirs and list for package name. my $i = 0; foreach (@$list) { local *F; open F, $_ or die "unable to open packages list file \"$_\"\n"; foreach () { chomp; print STDERR "package \"$_\" is listed in mulitple list files!\n" if $pkg2dir{$_}; $pkg2dir{$_} = $rpmsdirs->[$i]; print "package \"$_\" listed in list files does not exists in rpms directory\n" if $flag->{verbose} && !$rpms->{$_}; } close F; ++$i; } #- check for right directory, and move if necessary. foreach (values %$rpms) { unless ($pkg2dir{$_->{key}}) { print "file $_->{file} in $_->{dir} define package \"$_->{name}\" not listed in list files\n" if $flag->{verbose}; } elsif ($_->{dir} ne $pkg2dir{$_->{key}}) { print "moving file $_->{file} in $_->{dir} to $pkg2dir{$_->{key}}\n" if $flag->{verbose}; mv("$_->{dir}/$_->{file}", $pkg2dir{$_->{key}}); $_->{dir} = $pkg2dir{$_->{key}}; } } } #- sync two hashes of rpms, update rpms and printer newer version that are not taken into account. sub sync_rpms { my ($source, $target, $flag) = @_; #- search in source part. foreach (keys %$source) { unless ($target->{$_}) { if ($flag->{verbose}) { print "adding $source->{$_}{file}" . (-d $flag->{add} ? " to $flag->{add}\n" : " is neccessary!\n"); } if (-d $flag->{add}) { cp("$source->{$_}{dir}/$source->{$_}{file}", $flag->{add}); chmod 0644, "$flag->{add}/$source->{$_}{file}"; } } } #- search in both part. foreach (keys %$source) { if ($target->{$_}) { if (URPM::ranges_overlap("== $source->{$_}{version}-$source->{$_}{release}", ">= $target->{$_}{version}-$target->{$_}{release}")) { if ("$source->{$_}{version}-$source->{$_}{release}" eq "$target->{$_}{version}-$target->{$_}{release}") { -s "$source->{$_}{dir}/$source->{$_}{file}" == -s "$target->{$_}{dir}/$target->{$_}{file}" and next; } if ($flag->{verbose}) { print "updating $target->{$_}{dir}/$target->{$_}{file} with newer version $source->{$_}{file}\n"; } if ($flag->{update}) { cp("$source->{$_}{dir}/$source->{$_}{file}", $target->{$_}{dir}); chmod 0644, "$target->{$_}{dir}/$source->{$_}{file}"; unless (-e "$target->{$_}{dir}/$source->{$_}{file}") { die "unable to copy $source->{$_}{file} from $source->{$_}{dir} into $target->{$_}{dir}\n"; } rm("$target->{$_}{dir}/$target->{$_}{file}") unless $source->{$_}{file} eq $target->{$_}{file}; #- copy on eq } } elsif ($source->{$_}{version} ne $target->{$_}{version} || $source->{$_}{release} ne $target->{$_}{release}) { if ($flag->{verbose}) { print STDERR "keeping more up-to-date version $target->{$_}{dir}/$target->{$_}{file} against $source->{$_}{dir}/$source->{$_}{file}, check your repository !\n"; } } #- say nothing if source is equal to target. } } #- search in target part. foreach (keys %$target) { unless ($source->{$_}) { if ($flag->{verbose}) { print "removing $target->{$_}{file}" . ($flag->{remove} ? " from $target->{$_}{dir}\n" : " is neccessary!\n"); my $k = $_; } if ($flag->{remove}) { rm("$target->{$_}{dir}/$target->{$_}{file}"); } } } } #- main program. sub main { my @from_rpms; my @to_rpms; my @list; my $target; my %flag; my %source; my %target; foreach (@_) { if (/^--(\w*)$/) { if ($1 eq 'verbose' || $1 eq 'update' || $1 eq 'remove' || $1 eq 'clean' || $1 eq 'sorted') { $flag{$1} = 1; } elsif ($1 eq 'add' || $1 eq 'conflict') { $flag{$1} = undef; } elsif ($1 eq 'from') { $target = \@from_rpms; } elsif ($1 eq 'to') { $target = \@to_rpms; } elsif ($1 eq 'list') { $target = \@list; } else { die "unknown option: $1\n"; } } else { if (exists $flag{add} && ! $flag{add}) { $flag{add} = $_; die "cannot add to non-directory: $_\n" unless -d $flag{add}; } elsif (exists $flag{conflict} && ! $flag{conflict}) { $flag{conflict} = $_; die "cannot add to non-directory: $_\n" unless -d $flag{conflict}; } else { die "unknown parameter: $_\n" unless $target; push @$target, $_; } } } die "usage: syncrpms [--update] [--remove] [--clean] [--sorted] [--add ] [--conflict ] --from --to [--list ]\n" unless scalar(@from_rpms) > 0 || scalar(@to_rpms) > 0; #- parse directory structures. get_rpms($_, \%source, \%flag, 0) foreach @from_rpms; print STDERR "reading " . scalar(keys %source) . " packages as source rpms from\n"; print STDERR " $_\n" foreach @from_rpms; get_rpms($_, \%target, \%flag, 1) foreach @to_rpms; print STDERR "reading " . scalar(keys %target) . " packages as target rpms from\n"; print STDERR " $_\n" foreach @to_rpms; sync_medium(\@to_rpms, \@list, \%target, \%flag) if scalar(@list) > 0 && scalar(@to_rpms) > 0; sync_rpms(\%source, \%target, \%flag) if scalar(@from_rpms) > 0 && scalar(@to_rpms) > 0; } main(@ARGV); >64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
     # --- Workstation

Office Workstation [icon=office] [path=Workstation] [descr=Office programs: wordprocessors (kword, abiword), spreadsheets (kspread, gnumeric), pdf viewers, etc]
	OFFICE
	PUBLISHING
	PIM

Game station [icon=arcade] [path=Workstation] [descr=Amusement programs: arcade, boards, strategy, etc]
	GAMES

Multimedia station [icon=multimedia] [path=Workstation] [descr=Sound and video playing/editing programs]
	AUDIO
	VIDEO
	GRAPHICS

Internet station [icon=networking] [path=Workstation] [descr=Set of tools to read and send mail and news (pine, mutt, tin..) and to browse the Web]
	NETWORKING_WWW
	NETWORKING_MAIL
	NETWORKING_NEWS
	COMMUNICATIONS
	NETWORKING_CHAT
	NETWORKING_FILE_TRANSFER
	NETWORKING_IRC
	NETWORKING_INSTANT_MESSAGING
	NETWORKING_DNS

Network Computer (client) [icon=terminals] [path=Workstation] [descr=Clients for different protocols including ssh]
	NETWORKING_REMOTE_ACCESS
	NETWORKING_FILE

Configuration [icon=configuration] [path=Workstation] [descr=Tools to ease the configuration of your computer]
	CONFIG

Scientific Workstation [icon=sciences] [path=Workstation] [descr=]
	SCIENCES

Console Tools [icon=terminals] [path=Workstation] [descr=Editors, shells, file tools, terminals]
	EDITORS
	TERMINALS
	TEXT_TOOLS
	SHELLS
	FILE_TOOLS

Utilities [icon=configuration] [path=Workstation] [descr=Archiving, emulators, monitoring]
	MONITORING
	EMULATORS
	ACCESSIBILITY
	ARCHIVING
	NETWORKING_OTHER

     # --- Graphical Environment

KDE Workstation [icon=kde] [path=Graphical Environment] [descr=The K Desktop Environment, the basic graphical environment with a collection of accompanying tools]
	KDE

Gnome Workstation [icon=gnome] [path=Graphical Environment] [descr=A graphical environment with user-friendly set of applications and desktop tools]
	GNOME

Other Graphical Desktops [icon=windowmanager] [path=Graphical Environment] [descr=Icewm, Window Maker, Enlightenment, Fvwm, etc]
	GRAPHICAL_DESKTOP


     # --- Development

Development [icon=editors] [path=Development] [descr=C and C++ development libraries, programs and include files]
	DEVELOPMENT

Documentation [icon=documentation] [path=Development] [descr=Books and Howto's on Linux and Free Software]
	BOOKS

     # --- Server

Web/FTP  [icon=file_transfer] [path=Server] [descr=Apache, Pro-ftpd]
	NETWORKING_WWW_SERVER
	NETWORKING_FILE_TRANSFER_SERVER

Mail/Groupware/News [icon=mail] [path=Server] [descr=Postfix mail server, Inn news server]
	NETWORKING_MAIL_SERVER
	NETWORKING_NEWS_SERVER

Database [icon=archiving] [path=Server] [descr=PostgreSQL or MySQL database server]
	DATABASES
	DATABASES_SERVER

Firewall/Router [icon=networking] [path=Server] [descr=Internet gateway]
	NETWORKING_FIREWALLING_SERVER

DNS/NIS [icon=hardware] [path=Server] [descr=Domain Name and Network Information Server] 
	NIS_SERVER
	NETWORKING_DNS_SERVER

Network Computer server [icon=networking] [path=Server] [descr=NFS server, SMB server, Proxy server, ssh server]
	NETWORKING_FILE_SERVER
	NETWORKING_REMOTE_ACCESS_SERVER