feeds 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #!/usr/bin/perl
  2. use Getopt::Std;
  3. use FindBin;
  4. use Cwd;
  5. use lib "$FindBin::Bin";
  6. use metadata;
  7. use warnings;
  8. use strict;
  9. chdir "$FindBin::Bin/..";
  10. $ENV{TOPDIR}=getcwd();
  11. my @feeds;
  12. my %build_packages;
  13. my %installed;
  14. sub parse_config() {
  15. my $line = 0;
  16. my %name;
  17. open FEEDS, "feeds.conf";
  18. while (<FEEDS>) {
  19. chomp;
  20. s/#.+$//;
  21. next unless /\S/;
  22. my @line = split /\s+/, $_, 3;
  23. $line++;
  24. my $valid = 1;
  25. $line[0] =~ /^src-\w+$/ or $valid = 0;
  26. $line[1] =~ /^\w+$/ or $valid = 0;
  27. $line[2] =~ /\s/ and $valid = 0;
  28. $valid or die "Syntax error in feeds.list, line: $line\n";
  29. $name{$line[1]} and die "Duplicate feed name '$line[1]', line: $line\n";
  30. $name{$line[1]} = 1;
  31. push @feeds, [@line];
  32. }
  33. close FEEDS;
  34. }
  35. sub update_svn($$) {
  36. my $name = shift;
  37. my $src = shift;
  38. system("svn co $src ./feeds/$name") == 0 or return 1;
  39. -d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1;
  40. -d "./feeds/$name.tmp/info" or mkdir "./feeds/$name.tmp/info" or return 1;
  41. system("make -s prepare-mk TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\"");
  42. 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\"");
  43. system("ln -sf $name.tmp/.packageinfo ./feeds/$name.index");
  44. return 0;
  45. }
  46. sub get_feed($) {
  47. my $feed = shift;
  48. clear_packages();
  49. parse_package_metadata("./feeds/$feed.index") or return;
  50. return { %package };
  51. }
  52. sub get_installed() {
  53. system("make -s prepare-tmpinfo");
  54. clear_packages();
  55. parse_package_metadata("./tmp/.packageinfo");
  56. %installed = %package;
  57. }
  58. sub search_feed {
  59. my $feed = shift;
  60. my @substr = @_;
  61. my $display;
  62. return unless @substr > 0;
  63. get_feed($feed);
  64. foreach my $name (sort { lc($a) cmp lc($b) } keys %package) {
  65. my $pkg = $package{$name};
  66. my $substr;
  67. my $pkgmatch = 1;
  68. foreach my $substr (@substr) {
  69. my $match;
  70. foreach my $key (qw(name title description)) {
  71. $substr and $pkg->{$key} =~ m/$substr/i and $match = 1;
  72. }
  73. $match or undef $pkgmatch;
  74. };
  75. $pkgmatch and do {
  76. $display or do {
  77. print "Search results in feed '$feed':\n";
  78. $display = 1;
  79. };
  80. printf "\%-25s\t\%s\n", $pkg->{name}, $pkg->{title};
  81. };
  82. }
  83. return 0;
  84. }
  85. sub search {
  86. my %opts;
  87. getopt('r:', \%opts);
  88. foreach my $feed (@feeds) {
  89. search_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]);
  90. }
  91. }
  92. sub install_svn() {
  93. my $feed = shift;
  94. my $pkg = shift;
  95. my $path = $pkg->{makefile};
  96. $path =~ s/\/Makefile$//;
  97. -d "./package/feeds" or mkdir "./package/feeds";
  98. -d "./package/feeds/$feed->[1]" or mkdir "./package/feeds/$feed->[1]";
  99. system("ln -sf ../../../$path ./package/feeds/$feed->[1]/");
  100. return 0;
  101. }
  102. my %install_method = (
  103. 'src-svn' => \&install_svn
  104. );
  105. my %feed;
  106. sub lookup_package($$) {
  107. my $feed = shift;
  108. my $package = shift;
  109. foreach my $feed ($feed, @feeds) {
  110. next unless $feed->[1];
  111. next unless $feed{$feed->[1]};
  112. $feed{$feed->[1]}->{$package} and return $feed;
  113. }
  114. return;
  115. }
  116. sub install_package {
  117. my $feed = shift;
  118. my $name = shift;
  119. my $ret = 0;
  120. $feed = lookup_package($feed, $name);
  121. $feed or do {
  122. $installed{$name} and return 0;
  123. warn "WARNING: Package '$name' is not available.\n";
  124. return 1;
  125. };
  126. my $pkg = $feed{$feed->[1]}->{$name} or return 1;
  127. my $src = $pkg->{src};
  128. my $type = $feed->[0];
  129. $src or $src = $name;
  130. # previously installed packages set the runtime package
  131. # newly installed packages set the source package
  132. $installed{$src} and return 0;
  133. # install all dependencies
  134. foreach my $dep (@{$pkg->{depends}}) {
  135. next if $dep =~ /@/;
  136. $dep =~ s/^\+//;
  137. install_package($feed, $dep) == 0 or $ret = 1;
  138. }
  139. # check previously installed packages
  140. $installed{$name} and return 0;
  141. $installed{$src} = 1;
  142. warn "Installing package '$src'\n";
  143. $install_method{$type} or do {
  144. warn "Unknown installation method: '$type'\n";
  145. return 1;
  146. };
  147. &{$install_method{$type}}($feed, $pkg) == 0 or do {
  148. warn "failed.\n";
  149. return 1;
  150. };
  151. return $ret;
  152. }
  153. sub refresh_config {
  154. my $default = shift;
  155. $default or $default = "o";
  156. # workaround for timestamp check
  157. system("rm -f tmp/.packageinfo");
  158. # refresh the config
  159. system("make oldconfig CONFDEFAULT=\"$default\" Config.in >/dev/null 2>/dev/null");
  160. }
  161. sub install {
  162. my $name;
  163. my %opts;
  164. my $feed;
  165. my $ret = 0;
  166. getopt('p:d:', \%opts);
  167. get_installed();
  168. foreach my $f (@feeds) {
  169. # index all feeds
  170. $feed{$f->[1]} = get_feed($f->[1]);
  171. # look up the preferred feed
  172. $opts{p} and $f->[1] eq $opts{p} and $feed = $f;
  173. }
  174. while ($name = shift @ARGV) {
  175. install_package($feed, $name) == 0 or $ret = 1;
  176. }
  177. # workaround for timestamp check
  178. # set the defaults
  179. if ($opts{d} and $opts{d} =~ /^[ymn]$/) {
  180. refresh_config($opts{d});
  181. }
  182. return $ret;
  183. }
  184. sub uninstall {
  185. my $name;
  186. my $uninstall;
  187. if ($ARGV[0] eq '-a') {
  188. system("rm -rf ./package/feeds");
  189. $uninstall = 1;
  190. } else {
  191. get_installed();
  192. while ($name = shift @ARGV) {
  193. my $pkg = $installed{$name};
  194. $pkg or do {
  195. warn "WARNING: $name not installed\n";
  196. next;
  197. };
  198. $pkg->{src} and $name = $pkg->{src};
  199. warn "Uninstalling package '$name'\n";
  200. system("rm -f ./package/feeds/*/$name");
  201. $uninstall = 1;
  202. }
  203. }
  204. $uninstall and refresh_config();
  205. return 0;
  206. }
  207. sub usage() {
  208. print <<EOF;
  209. Usage: $0 <command> [options]
  210. Commands:
  211. install [options] <package>: Install a package
  212. Options:
  213. -p <feedname>: Prefer this feed when installing packages
  214. -d <y|m|n>: Set default for newly installed packages
  215. search [options] <substring>: Search for a package
  216. Options:
  217. -r <feedname>: Only search in this feed
  218. uninstall -a|<package>: Uninstall a package
  219. -a uninstalls all packages
  220. update: Update packages and lists of feeds in feeds.list
  221. clean: Remove downloaded/generated files
  222. EOF
  223. exit(1);
  224. }
  225. my %update_method = (
  226. 'src-svn' => \&update_svn
  227. );
  228. my %commands = (
  229. 'update' => sub {
  230. -d "feeds" or do {
  231. mkdir "feeds" or die "Unable to create the feeds directory";
  232. };
  233. $ENV{SCAN_COOKIE} = $$;
  234. $ENV{KBUILD_VERBOSE} = 99;
  235. foreach my $feed (@feeds) {
  236. my ($type, $name, $src) = @$feed;
  237. $update_method{$type} or do {
  238. warn "Unknown type '$type' in feed $name\n";
  239. next;
  240. };
  241. warn "Updating feed '$name'...\n";
  242. &{$update_method{$type}}($name, $src) == 0 or do {
  243. warn "failed.\n";
  244. return 1;
  245. };
  246. }
  247. return 0;
  248. },
  249. 'install' => \&install,
  250. 'search' => \&search,
  251. 'uninstall' => \&uninstall,
  252. 'clean' => sub {
  253. system("rm -rf feeds");
  254. }
  255. );
  256. my $arg = shift @ARGV;
  257. $arg or usage();
  258. parse_config;
  259. foreach my $cmd (keys %commands) {
  260. $arg eq $cmd and do {
  261. exit(&{$commands{$cmd}}());
  262. };
  263. }
  264. usage();