parent
d7502c446b
commit
f8dfc57573
@ -0,0 +1,2 @@ |
|||||||
|
src-svn packages https://svn.openwrt.org/openwrt/packages |
||||||
|
src-svn xwrt http://svn.berlios.de/svnroot/repos/xwrt/trunk/package |
@ -0,0 +1,322 @@ |
|||||||
|
#!/usr/bin/perl |
||||||
|
use Getopt::Std; |
||||||
|
use FindBin; |
||||||
|
use Cwd; |
||||||
|
use lib "$FindBin::Bin"; |
||||||
|
use metadata; |
||||||
|
use warnings; |
||||||
|
use strict; |
||||||
|
|
||||||
|
chdir "$FindBin::Bin/.."; |
||||||
|
$ENV{TOPDIR}=getcwd(); |
||||||
|
|
||||||
|
my @feeds; |
||||||
|
my %build_packages; |
||||||
|
my %installed; |
||||||
|
|
||||||
|
sub parse_config() { |
||||||
|
my $line = 0; |
||||||
|
my %name; |
||||||
|
|
||||||
|
open FEEDS, "feeds.conf"; |
||||||
|
while (<FEEDS>) { |
||||||
|
chomp; |
||||||
|
s/#.+$//; |
||||||
|
next unless /\S/; |
||||||
|
my @line = split /\s+/, $_, 3; |
||||||
|
$line++; |
||||||
|
|
||||||
|
my $valid = 1; |
||||||
|
$line[0] =~ /^src-\w+$/ or $valid = 0; |
||||||
|
$line[1] =~ /^\w+$/ or $valid = 0; |
||||||
|
$line[2] =~ /\s/ and $valid = 0; |
||||||
|
$valid or die "Syntax error in feeds.list, line: $line\n"; |
||||||
|
|
||||||
|
$name{$line[1]} and die "Duplicate feed name '$line[1]', line: $line\n"; |
||||||
|
$name{$line[1]} = 1; |
||||||
|
|
||||||
|
push @feeds, [@line]; |
||||||
|
} |
||||||
|
close FEEDS; |
||||||
|
} |
||||||
|
|
||||||
|
sub update_svn($$) { |
||||||
|
my $name = shift; |
||||||
|
my $src = shift; |
||||||
|
|
||||||
|
system("svn co $src ./feeds/$name") == 0 or return 1; |
||||||
|
-d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1; |
||||||
|
-d "./feeds/$name.tmp/info" or mkdir "./feeds/$name.tmp/info" or return 1; |
||||||
|
|
||||||
|
system("make -s prepare-mk TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\""); |
||||||
|
system("make -s -f include/scan.mk IS_TTY=1 SCAN_TARGET=\"packageinfo\" SCAN_DIR=\"feeds/$name\" SCAN_NAME=\"package\" SCAN_DEPS=\"$ENV{TOPDIR}/include/package*.mk\" SCAN_DEPTH=4 SCAN_EXTRA=\"\" TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\""); |
||||||
|
system("ln -sf $name.tmp/.packageinfo ./feeds/$name.index"); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
sub get_feed($) { |
||||||
|
my $feed = shift; |
||||||
|
|
||||||
|
clear_packages(); |
||||||
|
parse_package_metadata("./feeds/$feed.index") or return; |
||||||
|
return { %package }; |
||||||
|
} |
||||||
|
|
||||||
|
sub get_installed() { |
||||||
|
system("make -s prepare-tmpinfo"); |
||||||
|
clear_packages(); |
||||||
|
parse_package_metadata("./tmp/.packageinfo"); |
||||||
|
%installed = %package; |
||||||
|
} |
||||||
|
|
||||||
|
sub search_feed { |
||||||
|
my $feed = shift; |
||||||
|
my @substr = @_; |
||||||
|
my $display; |
||||||
|
|
||||||
|
return unless @substr > 0; |
||||||
|
get_feed($feed); |
||||||
|
foreach my $name (sort { lc($a) cmp lc($b) } keys %package) { |
||||||
|
my $pkg = $package{$name}; |
||||||
|
my $substr; |
||||||
|
my $pkgmatch = 1; |
||||||
|
|
||||||
|
foreach my $substr (@substr) { |
||||||
|
my $match; |
||||||
|
foreach my $key (qw(name title description)) { |
||||||
|
$substr and $pkg->{$key} =~ m/$substr/i and $match = 1; |
||||||
|
} |
||||||
|
$match or undef $pkgmatch; |
||||||
|
}; |
||||||
|
$pkgmatch and do { |
||||||
|
$display or do { |
||||||
|
print "Search results in feed '$feed':\n"; |
||||||
|
$display = 1; |
||||||
|
}; |
||||||
|
printf "\%-25s\t\%s\n", $pkg->{name}, $pkg->{title}; |
||||||
|
}; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
sub search { |
||||||
|
my %opts; |
||||||
|
|
||||||
|
getopt('r:', \%opts); |
||||||
|
foreach my $feed (@feeds) { |
||||||
|
search_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sub install_svn() { |
||||||
|
my $feed = shift; |
||||||
|
my $pkg = shift; |
||||||
|
my $path = $pkg->{makefile}; |
||||||
|
$path =~ s/\/Makefile$//; |
||||||
|
|
||||||
|
-d "./package/feeds" or mkdir "./package/feeds"; |
||||||
|
-d "./package/feeds/$feed->[1]" or mkdir "./package/feeds/$feed->[1]"; |
||||||
|
system("ln -sf ../../../$path ./package/feeds/$feed->[1]/"); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
my %install_method = ( |
||||||
|
'src-svn' => \&install_svn |
||||||
|
); |
||||||
|
|
||||||
|
my %feed; |
||||||
|
|
||||||
|
sub lookup_package($$) { |
||||||
|
my $feed = shift; |
||||||
|
my $package = shift; |
||||||
|
|
||||||
|
foreach my $feed ($feed, @feeds) { |
||||||
|
next unless $feed->[1]; |
||||||
|
next unless $feed{$feed->[1]}; |
||||||
|
$feed{$feed->[1]}->{$package} and return $feed; |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
sub install_package { |
||||||
|
my $feed = shift; |
||||||
|
my $name = shift; |
||||||
|
my $ret = 0; |
||||||
|
|
||||||
|
$feed = lookup_package($feed, $name); |
||||||
|
$feed or do { |
||||||
|
$installed{$name} and return 0; |
||||||
|
warn "WARNING: Package '$name' is not available.\n"; |
||||||
|
return 1; |
||||||
|
}; |
||||||
|
|
||||||
|
my $pkg = $feed{$feed->[1]}->{$name} or return 1; |
||||||
|
my $src = $pkg->{src}; |
||||||
|
my $type = $feed->[0]; |
||||||
|
$src or $src = $name; |
||||||
|
|
||||||
|
# previously installed packages set the runtime package |
||||||
|
# newly installed packages set the source package |
||||||
|
$installed{$src} and return 0; |
||||||
|
|
||||||
|
# install all dependencies |
||||||
|
foreach my $dep (@{$pkg->{depends}}) { |
||||||
|
next if $dep =~ /@/; |
||||||
|
$dep =~ s/^\+//; |
||||||
|
install_package($feed, $dep) == 0 or $ret = 1; |
||||||
|
} |
||||||
|
|
||||||
|
# check previously installed packages |
||||||
|
$installed{$name} and return 0; |
||||||
|
$installed{$src} = 1; |
||||||
|
warn "Installing package '$src'\n"; |
||||||
|
|
||||||
|
$install_method{$type} or do { |
||||||
|
warn "Unknown installation method: '$type'\n"; |
||||||
|
return 1; |
||||||
|
}; |
||||||
|
|
||||||
|
&{$install_method{$type}}($feed, $pkg) == 0 or do { |
||||||
|
warn "failed.\n"; |
||||||
|
return 1; |
||||||
|
}; |
||||||
|
|
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
sub refresh_config { |
||||||
|
my $default = shift; |
||||||
|
$default or $default = "o"; |
||||||
|
|
||||||
|
# workaround for timestamp check |
||||||
|
system("rm -f tmp/.packageinfo"); |
||||||
|
|
||||||
|
# refresh the config |
||||||
|
system("make oldconfig CONFDEFAULT=\"$default\" Config.in >/dev/null 2>/dev/null"); |
||||||
|
} |
||||||
|
|
||||||
|
sub install { |
||||||
|
my $name; |
||||||
|
my %opts; |
||||||
|
my $feed; |
||||||
|
my $ret = 0; |
||||||
|
|
||||||
|
getopt('p:d:', \%opts); |
||||||
|
get_installed(); |
||||||
|
|
||||||
|
foreach my $f (@feeds) { |
||||||
|
# index all feeds |
||||||
|
$feed{$f->[1]} = get_feed($f->[1]); |
||||||
|
|
||||||
|
# look up the preferred feed |
||||||
|
$opts{p} and $f->[1] eq $opts{p} and $feed = $f; |
||||||
|
} |
||||||
|
|
||||||
|
while ($name = shift @ARGV) { |
||||||
|
install_package($feed, $name) == 0 or $ret = 1; |
||||||
|
} |
||||||
|
|
||||||
|
# workaround for timestamp check |
||||||
|
|
||||||
|
# set the defaults |
||||||
|
if ($opts{d} and $opts{d} =~ /^[ymn]$/) { |
||||||
|
refresh_config($opts{d}); |
||||||
|
} |
||||||
|
|
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
sub uninstall { |
||||||
|
my $name; |
||||||
|
my $uninstall; |
||||||
|
|
||||||
|
if ($ARGV[0] eq '-a') { |
||||||
|
system("rm -rf ./package/feeds"); |
||||||
|
$uninstall = 1; |
||||||
|
} else { |
||||||
|
get_installed(); |
||||||
|
while ($name = shift @ARGV) { |
||||||
|
my $pkg = $installed{$name}; |
||||||
|
$pkg or do { |
||||||
|
warn "WARNING: $name not installed\n"; |
||||||
|
next; |
||||||
|
}; |
||||||
|
$pkg->{src} and $name = $pkg->{src}; |
||||||
|
warn "Uninstalling package '$name'\n"; |
||||||
|
system("rm -f ./package/feeds/*/$name"); |
||||||
|
$uninstall = 1; |
||||||
|
} |
||||||
|
} |
||||||
|
$uninstall and refresh_config(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
sub usage() { |
||||||
|
print <<EOF; |
||||||
|
Usage: $0 <command> [options] |
||||||
|
|
||||||
|
Commands: |
||||||
|
install [options] <package>: Install a package |
||||||
|
Options: |
||||||
|
-p <feedname>: Prefer this feed when installing packages |
||||||
|
-d <y|m|n>: Set default for newly installed packages |
||||||
|
|
||||||
|
search [options] <substring>: Search for a package |
||||||
|
Options: |
||||||
|
-r <feedname>: Only search in this feed |
||||||
|
|
||||||
|
uninstall -a|<package>: Uninstall a package |
||||||
|
-a uninstalls all packages |
||||||
|
|
||||||
|
update: Update packages and lists of feeds in feeds.list |
||||||
|
clean: Remove downloaded/generated files |
||||||
|
|
||||||
|
EOF |
||||||
|
exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
my %update_method = ( |
||||||
|
'src-svn' => \&update_svn |
||||||
|
); |
||||||
|
|
||||||
|
my %commands = ( |
||||||
|
'update' => sub { |
||||||
|
-d "feeds" or do { |
||||||
|
mkdir "feeds" or die "Unable to create the feeds directory"; |
||||||
|
}; |
||||||
|
$ENV{SCAN_COOKIE} = $$; |
||||||
|
$ENV{KBUILD_VERBOSE} = 99; |
||||||
|
foreach my $feed (@feeds) { |
||||||
|
my ($type, $name, $src) = @$feed; |
||||||
|
$update_method{$type} or do { |
||||||
|
warn "Unknown type '$type' in feed $name\n"; |
||||||
|
next; |
||||||
|
}; |
||||||
|
warn "Updating feed '$name'...\n"; |
||||||
|
&{$update_method{$type}}($name, $src) == 0 or do { |
||||||
|
warn "failed.\n"; |
||||||
|
return 1; |
||||||
|
}; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
}, |
||||||
|
'install' => \&install, |
||||||
|
'search' => \&search, |
||||||
|
'uninstall' => \&uninstall, |
||||||
|
'clean' => sub { |
||||||
|
system("rm -rf feeds"); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
my $arg = shift @ARGV; |
||||||
|
$arg or usage(); |
||||||
|
parse_config; |
||||||
|
foreach my $cmd (keys %commands) { |
||||||
|
$arg eq $cmd and do { |
||||||
|
exit(&{$commands{$cmd}}()); |
||||||
|
}; |
||||||
|
} |
||||||
|
usage(); |
@ -0,0 +1,113 @@ |
|||||||
|
package metadata; |
||||||
|
use base 'Exporter'; |
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
our @EXPORT = qw(%package %srcpackage %category %subdir %preconfig clear_packages parse_package_metadata get_multiline); |
||||||
|
|
||||||
|
our %package; |
||||||
|
our %preconfig; |
||||||
|
our %srcpackage; |
||||||
|
our %category; |
||||||
|
our %subdir; |
||||||
|
|
||||||
|
sub get_multiline { |
||||||
|
my $fh = shift; |
||||||
|
my $prefix = shift; |
||||||
|
my $str; |
||||||
|
while (<$fh>) { |
||||||
|
last if /^@@/; |
||||||
|
s/^\s*//g; |
||||||
|
$str .= (($_ and $prefix) ? $prefix . $_ : $_); |
||||||
|
} |
||||||
|
|
||||||
|
return $str ? $str : ""; |
||||||
|
} |
||||||
|
|
||||||
|
sub clear_packages() { |
||||||
|
%subdir = (); |
||||||
|
%preconfig = (); |
||||||
|
%package = (); |
||||||
|
%srcpackage = (); |
||||||
|
%category = (); |
||||||
|
} |
||||||
|
|
||||||
|
sub parse_package_metadata($) { |
||||||
|
my $file = shift; |
||||||
|
my $pkg; |
||||||
|
my $makefile; |
||||||
|
my $preconfig; |
||||||
|
my $subdir; |
||||||
|
my $src; |
||||||
|
|
||||||
|
open FILE, "<$file" or do { |
||||||
|
warn "Cannot open '$file': $!\n"; |
||||||
|
return undef; |
||||||
|
}; |
||||||
|
while (<FILE>) { |
||||||
|
chomp; |
||||||
|
/^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and do { |
||||||
|
$makefile = $1; |
||||||
|
$subdir = $2; |
||||||
|
$src = $3; |
||||||
|
$subdir =~ s/^package\///; |
||||||
|
$subdir{$src} = $subdir; |
||||||
|
$srcpackage{$src} = []; |
||||||
|
undef $pkg; |
||||||
|
}; |
||||||
|
/^Package:\s*(.+?)\s*$/ and do { |
||||||
|
$pkg = {}; |
||||||
|
$pkg->{src} = $src; |
||||||
|
$pkg->{makefile} = $makefile; |
||||||
|
$pkg->{name} = $1; |
||||||
|
$pkg->{default} = "m if ALL"; |
||||||
|
$pkg->{depends} = []; |
||||||
|
$pkg->{builddepends} = []; |
||||||
|
$pkg->{subdir} = $subdir; |
||||||
|
$package{$1} = $pkg; |
||||||
|
push @{$srcpackage{$src}}, $pkg; |
||||||
|
}; |
||||||
|
/^Version: \s*(.+)\s*$/ and $pkg->{version} = $1; |
||||||
|
/^Title: \s*(.+)\s*$/ and $pkg->{title} = $1; |
||||||
|
/^Menu: \s*(.+)\s*$/ and $pkg->{menu} = $1; |
||||||
|
/^Submenu: \s*(.+)\s*$/ and $pkg->{submenu} = $1; |
||||||
|
/^Submenu-Depends: \s*(.+)\s*$/ and $pkg->{submenudep} = $1; |
||||||
|
/^Default: \s*(.+)\s*$/ and $pkg->{default} = $1; |
||||||
|
/^Provides: \s*(.+)\s*$/ and do { |
||||||
|
my @vpkg = split /\s+/, $1; |
||||||
|
foreach my $vpkg (@vpkg) { |
||||||
|
$package{$vpkg} or $package{$vpkg} = { vdepends => [] }; |
||||||
|
push @{$package{$vpkg}->{vdepends}}, $pkg->{name}; |
||||||
|
} |
||||||
|
}; |
||||||
|
/^Depends: \s*(.+)\s*$/ and $pkg->{depends} = [ split /\s+/, $1 ]; |
||||||
|
/^Build-Depends: \s*(.+)\s*$/ and $pkg->{builddepends} = [ split /\s+/, $1 ]; |
||||||
|
/^Category: \s*(.+)\s*$/ and do { |
||||||
|
$pkg->{category} = $1; |
||||||
|
defined $category{$1} or $category{$1} = {}; |
||||||
|
defined $category{$1}->{$src} or $category{$1}->{$src} = []; |
||||||
|
push @{$category{$1}->{$src}}, $pkg; |
||||||
|
}; |
||||||
|
/^Description: \s*(.*)\s*$/ and $pkg->{description} = "\t\t $1\n". get_multiline(*FILE, "\t\t "); |
||||||
|
/^Config: \s*(.*)\s*$/ and $pkg->{config} = "$1\n".get_multiline(*FILE); |
||||||
|
/^Prereq-Check:/ and $pkg->{prereq} = 1; |
||||||
|
/^Preconfig:\s*(.+)\s*$/ and do { |
||||||
|
my $pkgname = $pkg->{name}; |
||||||
|
$preconfig{$pkgname} or $preconfig{$pkgname} = {}; |
||||||
|
if (exists $preconfig{$pkgname}->{$1}) { |
||||||
|
$preconfig = $preconfig{$pkgname}->{$1}; |
||||||
|
} else { |
||||||
|
$preconfig = { |
||||||
|
id => $1 |
||||||
|
}; |
||||||
|
$preconfig{$pkgname}->{$1} = $preconfig; |
||||||
|
} |
||||||
|
}; |
||||||
|
/^Preconfig-Type:\s*(.*?)\s*$/ and $preconfig->{type} = $1; |
||||||
|
/^Preconfig-Label:\s*(.*?)\s*$/ and $preconfig->{label} = $1; |
||||||
|
/^Preconfig-Default:\s*(.*?)\s*$/ and $preconfig->{default} = $1; |
||||||
|
} |
||||||
|
close FILE; |
||||||
|
return %category; |
||||||
|
} |
||||||
|
|
||||||
|
1; |
Loading…
Reference in new issue