OpenWrt – Blame information for rev 2
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #!/usr/bin/env 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 | use Cwd 'abs_path'; |
||
10 | |||
11 | chdir "$FindBin::Bin/.."; |
||
12 | $ENV{TOPDIR} //= getcwd(); |
||
13 | chdir $ENV{TOPDIR}; |
||
14 | $ENV{GIT_CONFIG_PARAMETERS}="'core.autocrlf=false'"; |
||
15 | $ENV{GREP_OPTIONS}=""; |
||
16 | |||
17 | my $mk=`which gmake 2>/dev/null`; # select the right 'make' program |
||
18 | chomp($mk); # trim trailing newline |
||
19 | $mk or $mk = "make"; # default to 'make' |
||
20 | |||
21 | # check version of make |
||
22 | my @mkver = split /\s+/, `$mk -v`, 4; |
||
23 | my $valid_mk = 1; |
||
24 | $mkver[0] =~ /^GNU/ or $valid_mk = 0; |
||
25 | $mkver[1] =~ /^Make/ or $valid_mk = 0; |
||
26 | |||
27 | my ($mkv1, $mkv2) = split /\./, $mkver[2]; |
||
28 | ($mkv1 >= 4 || ($mkv1 == 3 && $mkv2 >= 81)) or $valid_mk = 0; |
||
29 | |||
30 | $valid_mk or die "Unsupported version of make found: $mk\n"; |
||
31 | |||
32 | my @feeds; |
||
33 | my %build_packages; |
||
34 | my %installed; |
||
35 | my %installed_pkg; |
||
36 | my %installed_targets; |
||
37 | my %feed_cache; |
||
38 | |||
39 | my $feed_package = {}; |
||
40 | my $feed_src = {}; |
||
41 | my $feed_target = {}; |
||
42 | my $feed_vpackage = {}; |
||
43 | |||
44 | sub parse_config() { |
||
45 | my $line = 0; |
||
46 | my %name; |
||
47 | |||
48 | open FEEDS, "feeds.conf" or |
||
49 | open FEEDS, "feeds.conf.default" or |
||
50 | die "Unable to open feeds configuration"; |
||
51 | while (<FEEDS>) { |
||
52 | chomp; |
||
53 | s/#.+$//; |
||
54 | next unless /\S/; |
||
55 | my @line = split /\s+/, $_, 3; |
||
56 | my @src; |
||
57 | $line++; |
||
58 | |||
59 | my $valid = 1; |
||
60 | $line[0] =~ /^src-[\w-]+$/ or $valid = 0; |
||
61 | $line[1] =~ /^\w+$/ or $valid = 0; |
||
62 | @src = split /\s+/, ($line[2] or ''); |
||
63 | @src = ('') if @src == 0; |
||
64 | $valid or die "Syntax error in feeds.conf, line: $line\n"; |
||
65 | |||
66 | $name{$line[1]} and die "Duplicate feed name '$line[1]', line: $line\n"; |
||
67 | $name{$line[1]} = 1; |
||
68 | |||
69 | push @feeds, [$line[0], $line[1], \@src]; |
||
70 | } |
||
71 | close FEEDS; |
||
72 | } |
||
73 | |||
74 | sub update_location($$) |
||
75 | { |
||
76 | my $name = shift; |
||
77 | my $url = shift; |
||
78 | my $old_url; |
||
79 | |||
80 | -d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1; |
||
81 | |||
82 | if( open LOC, "< ./feeds/$name.tmp/location" ) |
||
83 | { |
||
84 | chomp($old_url = readline LOC); |
||
85 | close LOC; |
||
86 | } |
||
87 | |||
88 | if( !$old_url || $old_url ne $url ) |
||
89 | { |
||
90 | if( open LOC, "> ./feeds/$name.tmp/location" ) |
||
91 | { |
||
92 | print LOC $url, "\n"; |
||
93 | close LOC; |
||
94 | } |
||
95 | return $old_url ? 1 : 0; |
||
96 | } |
||
97 | |||
98 | return 0; |
||
99 | } |
||
100 | |||
101 | sub update_index($) |
||
102 | { |
||
103 | my $name = shift; |
||
104 | |||
105 | -d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1; |
||
106 | -d "./feeds/$name.tmp/info" or mkdir "./feeds/$name.tmp/info" or return 1; |
||
107 | |||
108 | system("$mk -s prepare-mk OPENWRT_BUILD= TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\""); |
||
109 | system("$mk -s -f include/scan.mk IS_TTY=1 SCAN_TARGET=\"packageinfo\" SCAN_DIR=\"feeds/$name\" SCAN_NAME=\"package\" SCAN_DEPTH=5 SCAN_EXTRA=\"\" TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\""); |
||
110 | system("$mk -s -f include/scan.mk IS_TTY=1 SCAN_TARGET=\"targetinfo\" SCAN_DIR=\"feeds/$name\" SCAN_NAME=\"target\" SCAN_DEPTH=5 SCAN_EXTRA=\"\" SCAN_MAKEOPTS=\"TARGET_BUILD=1\" TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\""); |
||
111 | system("ln -sf $name.tmp/.packageinfo ./feeds/$name.index"); |
||
112 | system("ln -sf $name.tmp/.targetinfo ./feeds/$name.targetindex"); |
||
113 | |||
114 | return 0; |
||
115 | } |
||
116 | |||
117 | my %update_method = ( |
||
118 | 'src-svn' => { |
||
119 | 'init' => "svn checkout '%s' '%s'", |
||
120 | 'update' => "svn update", |
||
121 | 'controldir' => ".svn", |
||
122 | 'revision' => "svn info | grep 'Revision' | cut -d ' ' -f 2 | tr -d '\n'"}, |
||
123 | 'src-cpy' => { |
||
124 | 'init' => "cp -Rf '%s' '%s'", |
||
125 | 'update' => "", |
||
126 | 'revision' => "echo -n 'local'"}, |
||
127 | 'src-link' => { |
||
128 | 'init' => "ln -s '%s' '%s'", |
||
129 | 'update' => "", |
||
130 | 'revision' => "echo -n 'local'"}, |
||
131 | 'src-dummy' => { |
||
132 | 'init' => "true '%s' && mkdir '%s'", |
||
133 | 'update' => "", |
||
134 | 'revision' => "echo -n 'dummy'"}, |
||
135 | 'src-git' => { |
||
136 | 'init' => "git clone --depth 1 '%s' '%s'", |
||
137 | 'init_branch' => "git clone --depth 1 --branch '%s' '%s' '%s'", |
||
138 | 'init_commit' => "git clone '%s' '%s' && cd '%s' && git checkout -b '%s' '%s' && cd -", |
||
139 | 'update' => "git pull --ff", |
||
140 | 'update_force' => "git pull --ff || (git reset --hard HEAD; git pull --ff; exit 1)", |
||
141 | 'post_update' => "git submodule update --init --recursive", |
||
142 | 'controldir' => ".git", |
||
143 | 'revision' => "git rev-parse --short HEAD | tr -d '\n'"}, |
||
144 | 'src-git-full' => { |
||
145 | 'init' => "git clone '%s' '%s'", |
||
146 | 'init_branch' => "git clone --branch '%s' '%s' '%s'", |
||
147 | 'init_commit' => "git clone '%s' '%s' && cd '%s' && git checkout -b '%s' '%s' && cd -", |
||
148 | 'update' => "git pull --ff", |
||
149 | 'update_force' => "git pull --ff || (git reset --hard HEAD; git pull --ff; exit 1)", |
||
150 | 'post_update' => "git submodule update --init --recursive", |
||
151 | 'controldir' => ".git", |
||
152 | 'revision' => "git rev-parse --short HEAD | tr -d '\n'"}, |
||
153 | 'src-gitsvn' => { |
||
154 | 'init' => "git svn clone -r HEAD '%s' '%s'", |
||
155 | 'update' => "git svn rebase", |
||
156 | 'controldir' => ".git", |
||
157 | 'revision' => "git rev-parse --short HEAD | tr -d '\n'"}, |
||
158 | 'src-bzr' => { |
||
159 | 'init' => "bzr checkout --lightweight '%s' '%s'", |
||
160 | 'update' => "bzr update", |
||
161 | 'controldir' => ".bzr"}, |
||
162 | 'src-hg' => { |
||
163 | 'init' => "hg clone '%s' '%s'", |
||
164 | 'update' => "hg pull --update", |
||
165 | 'controldir' => ".hg"}, |
||
166 | 'src-darcs' => { |
||
167 | 'init' => "darcs get '%s' '%s'", |
||
168 | 'update' => "darcs pull -a", |
||
169 | 'controldir' => "_darcs"}, |
||
170 | ); |
||
171 | |||
172 | # src-git: pull broken |
||
173 | # src-cpy: broken if `basename $src` != $name |
||
174 | |||
175 | sub update_feed_via($$$$$) { |
||
176 | my $type = shift; |
||
177 | my $name = shift; |
||
178 | my $src = shift; |
||
179 | my $relocate = shift; |
||
180 | my $force = shift; |
||
181 | |||
182 | my $m = $update_method{$type}; |
||
183 | my $localpath = "./feeds/$name"; |
||
184 | my $safepath = $localpath; |
||
185 | $safepath =~ s/'/'\\''/; |
||
186 | my ($base_branch, $branch) = split(/;/, $src, 2); |
||
187 | my ($base_commit, $commit) = split(/\^/, $src, 2); |
||
188 | |||
189 | if( $relocate || !$m->{'update'} || !-d "$localpath/$m->{'controldir'}" ) { |
||
190 | system("rm -rf '$safepath'"); |
||
191 | if ($m->{'init_branch'} and $branch) { |
||
192 | system(sprintf($m->{'init_branch'}, $branch, $base_branch, $safepath)) == 0 or return 1; |
||
193 | } elsif ($m->{'init_commit'} and $commit) { |
||
194 | system(sprintf($m->{'init_commit'}, $base_commit, $safepath, $safepath, $commit, $commit)) == 0 or return 1; |
||
195 | } else { |
||
196 | system(sprintf($m->{'init'}, $src, $safepath)) == 0 or return 1; |
||
197 | } |
||
198 | } elsif ($m->{'init_commit'} and $commit) { |
||
199 | # in case git hash has been provided don't update the feed |
||
200 | } else { |
||
201 | my $update_cmd = $m->{'update'}; |
||
202 | if ($force && exists $m->{'update_force'}) { |
||
203 | $update_cmd = $m->{'update_force'}; |
||
204 | } |
||
205 | system("cd '$safepath'; $update_cmd") == 0 or return 1; |
||
206 | } |
||
207 | if ($m->{'post_update'}) { |
||
208 | my $cmd = $m->{'post_update'}; |
||
209 | system("cd '$safepath'; $cmd") == 0 or return 1; |
||
210 | } |
||
211 | |||
212 | return 0; |
||
213 | } |
||
214 | |||
215 | sub get_targets($) { |
||
216 | my $file = shift; |
||
217 | my @target = parse_target_metadata($file); |
||
218 | my %target; |
||
219 | foreach my $target (@target) { |
||
220 | $target{$target->{id}} = $target; |
||
221 | } |
||
222 | return %target |
||
223 | } |
||
224 | |||
225 | sub get_feed($) { |
||
226 | my $feed = shift; |
||
227 | |||
228 | if (!defined($feed_cache{$feed})) { |
||
229 | my $file = "./feeds/$feed.index"; |
||
230 | |||
231 | clear_packages(); |
||
232 | -f $file or do { |
||
233 | print "Ignoring feed '$feed' - index missing\n"; |
||
234 | return; |
||
235 | }; |
||
236 | parse_package_metadata($file) or return; |
||
237 | my %target = get_targets("./feeds/$feed.targetindex"); |
||
238 | |||
239 | $feed_cache{$feed} = [ { %package }, { %srcpackage }, { %target }, { %vpackage } ]; |
||
240 | } |
||
241 | |||
242 | $feed_package = $feed_cache{$feed}->[0]; |
||
243 | $feed_src = $feed_cache{$feed}->[1]; |
||
244 | $feed_target = $feed_cache{$feed}->[2]; |
||
245 | $feed_vpackage = $feed_cache{$feed}->[3]; |
||
246 | } |
||
247 | |||
248 | sub get_installed() { |
||
249 | system("$mk -s prepare-tmpinfo OPENWRT_BUILD="); |
||
250 | clear_packages(); |
||
251 | parse_package_metadata("./tmp/.packageinfo"); |
||
252 | %installed_pkg = %vpackage; |
||
253 | %installed = %srcpackage; |
||
254 | %installed_targets = get_targets("./tmp/.targetinfo"); |
||
255 | } |
||
256 | |||
257 | sub search_feed { |
||
258 | my $feed = shift; |
||
259 | my @substr = @_; |
||
260 | my $display; |
||
261 | |||
262 | return unless @substr > 0; |
||
263 | get_feed($feed); |
||
264 | foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_package) { |
||
265 | my $pkg = $feed_package->{$name}; |
||
266 | my $substr; |
||
267 | my $pkgmatch = 1; |
||
268 | |||
269 | foreach my $substr (@substr) { |
||
270 | my $match; |
||
271 | foreach my $key (qw(name title description src)) { |
||
272 | $pkg->{$key} and $substr and $pkg->{$key} =~ m/$substr/i and $match = 1; |
||
273 | } |
||
274 | $match or undef $pkgmatch; |
||
275 | }; |
||
276 | $pkgmatch and do { |
||
277 | $display or do { |
||
278 | print "Search results in feed '$feed':\n"; |
||
279 | $display = 1; |
||
280 | }; |
||
281 | printf "\%-25s\t\%s\n", $pkg->{name}, $pkg->{title}; |
||
282 | }; |
||
283 | } |
||
284 | |||
285 | foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_target) { |
||
286 | my $target = $feed_target->{$name}; |
||
287 | my $targetmatch = 1; |
||
288 | |||
289 | foreach my $substr (@substr) { |
||
290 | my $match; |
||
291 | foreach my $key (qw(id name description)) { |
||
292 | $target->{$key} and $substr and $target->{$key} =~ m/$substr/i and $match = 1; |
||
293 | } |
||
294 | $match or undef $targetmatch; |
||
295 | }; |
||
296 | $targetmatch and do { |
||
297 | $display or do { |
||
298 | print "Search results in feed '$feed':\n"; |
||
299 | $display = 1; |
||
300 | }; |
||
301 | printf "TARGET: \%-17s\t\%s\n", $target->{id}, $target->{name}; |
||
302 | }; |
||
303 | } |
||
304 | return 0; |
||
305 | } |
||
306 | |||
307 | sub search { |
||
308 | my %opts; |
||
309 | |||
310 | getopt('r:', \%opts); |
||
311 | foreach my $feed (@feeds) { |
||
312 | search_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]); |
||
313 | } |
||
314 | } |
||
315 | |||
316 | sub list_feed { |
||
317 | my $feed = shift; |
||
318 | |||
319 | get_feed($feed); |
||
320 | foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_package) { |
||
321 | my $pkg = $feed_package->{$name}; |
||
322 | if($pkg->{name}) { |
||
323 | printf "\%-32s\t\%s\n", $pkg->{name}, $pkg->{title}; |
||
324 | } |
||
325 | } |
||
326 | |||
327 | foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_target) { |
||
328 | my $target = $feed_target->{$name}; |
||
329 | if($target->{name}) { |
||
330 | printf "TARGET: \%-24s\t\%s\n", $target->{id}, $target->{name}; |
||
331 | } |
||
332 | } |
||
333 | |||
334 | return 0; |
||
335 | } |
||
336 | |||
337 | sub list { |
||
338 | my %opts; |
||
339 | |||
340 | getopts('r:d:nshf', \%opts); |
||
341 | if ($opts{h}) { |
||
342 | usage(); |
||
343 | return 0; |
||
344 | } |
||
345 | if ($opts{n}) { |
||
346 | foreach my $feed (@feeds) { |
||
347 | printf "%s\n", $feed->[1]; |
||
348 | } |
||
349 | return 0; |
||
350 | } |
||
351 | if ($opts{s}) { |
||
352 | foreach my $feed (@feeds) { |
||
353 | my $localpath = "./feeds/$feed->[1]"; |
||
354 | my $m = $update_method{$feed->[0]}; |
||
355 | my $revision; |
||
356 | if (!-d "$localpath" || !$m->{'revision'}) { |
||
357 | $revision = "X"; |
||
358 | } |
||
359 | elsif( $m->{'controldir'} && -d "$localpath/$m->{'controldir'}" ) { |
||
360 | $revision = `cd '$localpath'; $m->{'revision'}`; |
||
361 | } |
||
362 | else { |
||
363 | $revision = "local"; |
||
364 | } |
||
365 | if ($opts{d}) { |
||
366 | printf "%s%s%s%s%s%s%s\n", $feed->[1], $opts{d}, $feed->[0], $opts{d}, $revision, $opts{d}, join(", ", @{$feed->[2]}); |
||
367 | } |
||
368 | elsif ($opts{f}) { |
||
369 | my $uri = join(", ", @{$feed->[2]}); |
||
370 | if ($revision ne "local" && $revision ne "X") { |
||
371 | $uri =~ s/[;^].*//; |
||
372 | $uri .= "^" . $revision; |
||
373 | } |
||
374 | printf "%s %s %s\n", $feed->[0], $feed->[1], $uri; |
||
375 | } |
||
376 | else { |
||
377 | printf "\%-10s \%-8s \%-8s \%s\n", $feed->[1], $feed->[0], $revision, join(", ", @{$feed->[2]}); |
||
378 | } |
||
379 | } |
||
380 | return 0; |
||
381 | } |
||
382 | foreach my $feed (@feeds) { |
||
383 | list_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]); |
||
384 | } |
||
385 | return 0; |
||
386 | } |
||
387 | |||
388 | sub do_install_src($$) { |
||
389 | my $feed = shift; |
||
390 | my $src = shift; |
||
391 | |||
392 | my $path = $src->{makefile}; |
||
393 | if ($path) { |
||
394 | $path =~ s/\/Makefile$//; |
||
395 | |||
396 | -d "./package/feeds" or mkdir "./package/feeds"; |
||
397 | -d "./package/feeds/$feed->[1]" or mkdir "./package/feeds/$feed->[1]"; |
||
398 | system("ln -sf ../../../$path ./package/feeds/$feed->[1]/"); |
||
399 | } else { |
||
400 | warn "Package is not valid\n"; |
||
401 | return 1; |
||
402 | } |
||
403 | |||
404 | return 0; |
||
405 | } |
||
406 | |||
407 | sub do_install_target($) { |
||
408 | my $target = shift; |
||
409 | my $path = $target->{makefile}; |
||
410 | |||
411 | if ($path) { |
||
412 | $path =~ s/\/Makefile$//; |
||
413 | my $name = $path; |
||
414 | $name =~ s/.*\///; |
||
415 | my $dest = "./target/linux/$name"; |
||
416 | |||
417 | -e $dest and do { |
||
418 | warn "Path $dest already exists"; |
||
419 | return 1; |
||
420 | }; |
||
421 | |||
422 | system("ln -sf ../../$path ./target/linux/"); |
||
423 | } else { |
||
424 | warn "Target is not valid\n"; |
||
425 | return 1; |
||
426 | } |
||
427 | |||
428 | return 0; |
||
429 | } |
||
430 | |||
431 | sub lookup_src($$) { |
||
432 | my $feed = shift; |
||
433 | my $src = shift; |
||
434 | |||
435 | foreach my $feed ($feed, @feeds) { |
||
436 | next unless $feed->[1]; |
||
437 | next unless $feed_cache{$feed->[1]}; |
||
438 | $feed_cache{$feed->[1]}->[1]->{$src} and return $feed; |
||
439 | } |
||
440 | return; |
||
441 | } |
||
442 | |||
443 | sub lookup_package($$) { |
||
444 | my $feed = shift; |
||
445 | my $package = shift; |
||
446 | |||
447 | foreach my $feed ($feed, @feeds) { |
||
448 | next unless $feed->[1]; |
||
449 | next unless $feed_cache{$feed->[1]}; |
||
450 | $feed_cache{$feed->[1]}->[3]->{$package} and return $feed; |
||
451 | } |
||
452 | return; |
||
453 | } |
||
454 | |||
455 | sub lookup_target($$) { |
||
456 | my $feed = shift; |
||
457 | my $target = shift; |
||
458 | |||
459 | foreach my $feed ($feed, @feeds) { |
||
460 | next unless $feed->[1]; |
||
461 | next unless $feed_cache{$feed->[1]}; |
||
462 | $feed_cache{$feed->[1]}->[2]->{$target} and return $feed; |
||
463 | } |
||
464 | return; |
||
465 | } |
||
466 | |||
467 | sub is_core_src($) { |
||
468 | my $src = shift; |
||
469 | foreach my $file ("tmp/info/.packageinfo-$src", glob("tmp/info/.packageinfo-*_$src")) { |
||
470 | next unless index($file, "tmp/info/.packageinfo-feeds_"); |
||
471 | return 1 if -s $file; |
||
472 | } |
||
473 | return 0; |
||
474 | } |
||
475 | |||
476 | sub install_target { |
||
477 | my $feed = shift; |
||
478 | my $name = shift; |
||
479 | |||
480 | $installed_targets{$name} and return 0; |
||
481 | |||
482 | $feed = $feed_cache{$feed->[1]}->[2]; |
||
483 | $feed or return 0; |
||
484 | |||
485 | my $target = $feed->{$name}; |
||
486 | $target or return 0; |
||
487 | |||
488 | warn "Installing target '$name'\n"; |
||
489 | return do_install_target($target); |
||
490 | } |
||
491 | |||
492 | sub install_src { |
||
493 | my $feed = shift; |
||
494 | my $name = shift; |
||
495 | my $force = shift; |
||
496 | my $ret = 0; |
||
497 | |||
498 | $feed = lookup_src($feed, $name); |
||
499 | unless ($feed) { |
||
500 | $installed{$name} and return 0; |
||
501 | $feed_src->{$name} or warn "WARNING: No feed for source package '$name' found\n"; |
||
502 | return 0; |
||
503 | } |
||
504 | |||
505 | # switch to the metadata for the selected feed |
||
506 | get_feed($feed->[1]); |
||
507 | my $src = $feed_src->{$name} or return 1; |
||
508 | |||
509 | # If it's a core package and we don't want to override, just return |
||
510 | my $override = 0; |
||
511 | if (is_core_src($name)) { |
||
512 | return 0 unless $force; |
||
513 | $override = 1; |
||
514 | } |
||
515 | |||
516 | if ($installed{$name}) { |
||
517 | # newly installed packages set the source package to 1 |
||
518 | return 0 if ($installed{$name} == 1); |
||
519 | return 0 unless ($override); |
||
520 | } |
||
521 | |||
522 | $installed{$name} = 1; |
||
523 | foreach my $pkg (@{$src->{packages}}) { |
||
524 | foreach my $vpkg (@{$pkg->{provides}}) { |
||
525 | $installed_pkg{$vpkg} = 1; |
||
526 | } |
||
527 | } |
||
528 | |||
529 | if ($override) { |
||
530 | warn "Overriding core package '$name' with version from $feed->[1]\n"; |
||
531 | } else { |
||
532 | warn "Installing package '$name' from $feed->[1]\n"; |
||
533 | } |
||
534 | |||
535 | do_install_src($feed, $src) == 0 or do { |
||
536 | warn "failed.\n"; |
||
537 | return 1; |
||
538 | }; |
||
539 | |||
540 | # install all dependencies referenced from the source package |
||
541 | foreach my $dep ( |
||
542 | @{$src->{builddepends}}, |
||
543 | @{$src->{'builddepends/host'}}, |
||
544 | ) { |
||
545 | next if $dep =~ /@/; |
||
546 | $dep =~ s/^.+://; |
||
547 | $dep =~ s/\/.+$//; |
||
548 | next unless $dep; |
||
549 | install_src($feed, $dep, 0) == 0 or $ret = 1; |
||
550 | } |
||
551 | |||
552 | foreach my $pkg (@{$src->{packages}}) { |
||
553 | foreach my $dep (@{$pkg->{depends}}) { |
||
554 | next if $dep =~ /@/; |
||
555 | $dep =~ s/^\+//; |
||
556 | $dep =~ s/^.+://; |
||
557 | next unless $dep; |
||
558 | install_package($feed, $dep, 0) == 0 or $ret = 1; |
||
559 | } |
||
560 | } |
||
561 | |||
562 | return $ret; |
||
563 | } |
||
564 | |||
565 | sub install_package { |
||
566 | my $feed = shift; |
||
567 | my $name = shift; |
||
568 | my $force = shift; |
||
569 | |||
570 | $feed = lookup_package($feed, $name); |
||
571 | unless ($feed) { |
||
572 | $installed_pkg{$name} and return 0; |
||
573 | $feed_vpackage->{$name} or warn "WARNING: No feed for package '$name' found\n"; |
||
574 | return 0; |
||
575 | } |
||
576 | |||
577 | # switch to the metadata for the selected feed |
||
578 | get_feed($feed->[1]); |
||
579 | my $pkg = $feed_vpackage->{$name} or return 1; |
||
580 | return install_src($feed, $pkg->[0]{src}{name}, $force); |
||
581 | } |
||
582 | |||
583 | sub install_target_or_package { |
||
584 | my $feed = shift; |
||
585 | my $name = shift; |
||
586 | my $force = shift; |
||
587 | |||
588 | my $this_feed_target = lookup_target($feed, $name); |
||
589 | $this_feed_target and do { |
||
590 | return install_target($this_feed_target, $name); |
||
591 | }; |
||
592 | |||
593 | my $this_feed_src = lookup_src($feed, $name); |
||
594 | $this_feed_src and do { |
||
595 | return install_src($this_feed_src, $name, $force); |
||
596 | }; |
||
597 | |||
598 | return install_package($feed, $name, $force); |
||
599 | } |
||
600 | |||
601 | sub refresh_config { |
||
602 | my $default = shift; |
||
603 | |||
604 | # Don't create .config if it doesn't already exist so that making a |
||
605 | # config only occurs when the user intends it do (however we do |
||
606 | # want to refresh an existing config). |
||
607 | return if not (-e '.config'); |
||
608 | |||
609 | # workaround for timestamp check |
||
610 | system("rm -f tmp/.packageinfo"); |
||
611 | |||
612 | # refresh the config |
||
613 | if ($default) { |
||
614 | system("$mk oldconfig CONFDEFAULT=\"$default\" Config.in >/dev/null 2>/dev/null"); |
||
615 | } else { |
||
616 | system("$mk defconfig Config.in >/dev/null 2>/dev/null"); |
||
617 | } |
||
618 | } |
||
619 | |||
620 | sub install { |
||
621 | my $name; |
||
622 | my %opts; |
||
623 | my $feed; |
||
624 | my $ret = 0; |
||
625 | |||
626 | getopts('ap:d:fh', \%opts); |
||
627 | |||
628 | if ($opts{h}) { |
||
629 | usage(); |
||
630 | return 0; |
||
631 | } |
||
632 | |||
633 | get_installed(); |
||
634 | |||
635 | foreach my $f (@feeds) { |
||
636 | # fetch all feeds |
||
637 | get_feed($f->[1]); |
||
638 | |||
639 | # look up the preferred feed |
||
640 | $opts{p} and $f->[1] eq $opts{p} and $feed = $f; |
||
641 | } |
||
642 | |||
643 | if($opts{a}) { |
||
644 | foreach my $f (@feeds) { |
||
645 | if (!defined($opts{p}) or $opts{p} eq $f->[1]) { |
||
646 | printf "Installing all packages from feed %s.\n", $f->[1]; |
||
647 | get_feed($f->[1]); |
||
648 | foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_src) { |
||
649 | install_src($feed, $name, exists($opts{f})) == 0 or $ret = 1; |
||
650 | get_feed($f->[1]); |
||
651 | } |
||
652 | } |
||
653 | } |
||
654 | } else { |
||
655 | while ($name = shift @ARGV) { |
||
656 | install_target_or_package($feed, $name, exists($opts{f})) == 0 or $ret = 1; |
||
657 | } |
||
658 | } |
||
659 | |||
660 | # workaround for timestamp check |
||
661 | |||
662 | # set the defaults |
||
663 | if ($opts{d} and $opts{d} =~ /^[ymn]$/) { |
||
664 | refresh_config($opts{d}); |
||
665 | } |
||
666 | |||
667 | return $ret; |
||
668 | } |
||
669 | |||
670 | sub uninstall_target($) { |
||
671 | my $dir = shift; |
||
672 | my $name = $dir; |
||
673 | $name =~ s/.*\///g; |
||
674 | |||
675 | my $dest = readlink $dir; |
||
676 | return unless $dest =~ /..\/..\/feeds/; |
||
677 | warn "Uninstalling target '$name'\n"; |
||
678 | unlink "$dir"; |
||
679 | } |
||
680 | |||
681 | sub uninstall { |
||
682 | my %opts; |
||
683 | my $name; |
||
684 | my $uninstall; |
||
685 | |||
686 | getopts('ah', \%opts); |
||
687 | |||
688 | if ($opts{h}) { |
||
689 | usage(); |
||
690 | return 0; |
||
691 | } |
||
692 | |||
693 | if ($opts{a}) { |
||
694 | system("rm -rvf ./package/feeds"); |
||
695 | foreach my $dir (glob "target/linux/*") { |
||
696 | next unless -l $dir; |
||
697 | uninstall_target($dir); |
||
698 | } |
||
699 | $uninstall = 1; |
||
700 | } else { |
||
701 | if($#ARGV == -1) { |
||
702 | warn "WARNING: no package to uninstall\n"; |
||
703 | return 0; |
||
704 | } |
||
705 | get_installed(); |
||
706 | while ($name = shift @ARGV) { |
||
707 | my $target = "target/linux/$name"; |
||
708 | -l "$target" and do { |
||
709 | uninstall_target($target); |
||
710 | $uninstall = 1; |
||
711 | next; |
||
712 | }; |
||
713 | |||
714 | my $pkg = $installed{$name}; |
||
715 | $pkg or do { |
||
716 | warn "WARNING: $name not installed\n"; |
||
717 | next; |
||
718 | }; |
||
719 | $pkg->{src} and $name = $pkg->{src}{name}; |
||
720 | warn "Uninstalling package '$name'\n"; |
||
721 | system("rm -f ./package/feeds/*/$name"); |
||
722 | $uninstall = 1; |
||
723 | } |
||
724 | } |
||
725 | $uninstall and refresh_config(); |
||
726 | return 0; |
||
727 | } |
||
728 | |||
729 | sub update_feed($$$$$) |
||
730 | { |
||
731 | my $type=shift; |
||
732 | my $name=shift; |
||
733 | my $src=shift; |
||
734 | my $perform_update=shift; |
||
735 | my $force_update=shift; |
||
736 | my $force_relocate=update_location( $name, "@$src" ); |
||
737 | my $rv=0; |
||
738 | |||
739 | if( $force_relocate ) { |
||
740 | warn "Source of feed $name has changed, replacing copy\n"; |
||
741 | } |
||
742 | $update_method{$type} or do { |
||
743 | warn "Unknown type '$type' in feed $name\n"; |
||
744 | return 1; |
||
745 | }; |
||
746 | $perform_update and do { |
||
747 | my $failed = 1; |
||
748 | foreach my $feedsrc (@$src) { |
||
749 | warn "Updating feed '$name' from '$feedsrc' ...\n"; |
||
750 | if (update_feed_via($type, $name, $feedsrc, $force_relocate, $force_update) != 0) { |
||
751 | if ($force_update) { |
||
752 | $rv=1; |
||
753 | $failed=0; |
||
754 | warn "failed, ignore.\n"; |
||
755 | next; |
||
756 | } |
||
757 | last; |
||
758 | } |
||
759 | $failed = 0; |
||
760 | } |
||
761 | $failed and do { |
||
762 | warn "failed.\n"; |
||
763 | return 1; |
||
764 | }; |
||
765 | }; |
||
766 | warn "Create index file './feeds/$name.index' \n"; |
||
767 | update_index($name) == 0 or do { |
||
768 | warn "failed.\n"; |
||
769 | return 1; |
||
770 | }; |
||
771 | return $rv; |
||
772 | } |
||
773 | |||
774 | sub update { |
||
775 | my %opts; |
||
776 | my $feed_name; |
||
777 | my $perform_update=1; |
||
778 | my $failed=0; |
||
779 | |||
780 | $ENV{SCAN_COOKIE} = $$; |
||
781 | $ENV{OPENWRT_VERBOSE} = 's'; |
||
782 | |||
783 | getopts('ahif', \%opts); |
||
784 | |||
785 | if ($opts{h}) { |
||
786 | usage(); |
||
787 | return 0; |
||
788 | } |
||
789 | |||
790 | if ($opts{i}) { |
||
791 | # don't update from (remote) repository |
||
792 | # only re-create index information |
||
793 | $perform_update=0; |
||
794 | } |
||
795 | |||
796 | -d "feeds" or do { |
||
797 | mkdir "feeds" or die "Unable to create the feeds directory"; |
||
798 | }; |
||
799 | |||
800 | if ( ($#ARGV == -1) or $opts{a}) { |
||
801 | foreach my $feed (@feeds) { |
||
802 | my ($type, $name, $src) = @$feed; |
||
803 | update_feed($type, $name, $src, $perform_update, $opts{f}) == 0 or $failed=1; |
||
804 | } |
||
805 | } else { |
||
806 | while ($feed_name = shift @ARGV) { |
||
807 | foreach my $feed (@feeds) { |
||
808 | my ($type, $name, $src) = @$feed; |
||
809 | if($feed_name ne $name) { |
||
810 | next; |
||
811 | } |
||
812 | update_feed($type, $name, $src, $perform_update, $opts{f}) == 0 or $failed=1; |
||
813 | } |
||
814 | } |
||
815 | } |
||
816 | |||
817 | refresh_config(); |
||
818 | |||
819 | return $failed; |
||
820 | } |
||
821 | |||
822 | sub feed_config() { |
||
823 | foreach my $feed (@feeds) { |
||
824 | my $installed = (-f "feeds/$feed->[1].index"); |
||
825 | |||
826 | printf "\tconfig FEED_%s\n", $feed->[1]; |
||
827 | printf "\t\ttristate \"Enable feed %s\"\n", $feed->[1]; |
||
828 | printf "\t\tdepends on PER_FEED_REPO\n"; |
||
829 | printf "\t\tdefault y\n" if $installed; |
||
830 | printf "\t\thelp\n"; |
||
831 | printf "\t\t Enable the \\\"%s\\\" feed in opkg distfeeds.conf.\n", $feed->[1]; |
||
832 | printf "\t\t Say M to add the feed commented out.\n"; |
||
833 | printf "\n"; |
||
834 | } |
||
835 | |||
836 | return 0; |
||
837 | } |
||
838 | |||
839 | sub usage() { |
||
840 | print <<EOF; |
||
841 | Usage: $0 <command> [options] |
||
842 | |||
843 | Commands: |
||
844 | list [options]: List feeds, their content and revisions (if installed) |
||
845 | Options: |
||
846 | -n : List of feed names. |
||
847 | -s : List of feed names and their URL. |
||
848 | -r <feedname>: List packages of specified feed. |
||
849 | -d <delimiter>: Use specified delimiter to distinguish rows (default: spaces) |
||
850 | -f : List feeds in feeds.conf compatible format (when using -s). |
||
851 | |||
852 | install [options] <package>: Install a package |
||
853 | Options: |
||
854 | -a : Install all packages from all feeds or from the specified feed using the -p option. |
||
855 | -p <feedname>: Prefer this feed when installing packages. |
||
856 | -d <y|m|n>: Set default for newly installed packages. |
||
857 | -f : Install will be forced even if the package exists in core OpenWrt (override) |
||
858 | |||
859 | search [options] <substring>: Search for a package |
||
860 | Options: |
||
861 | -r <feedname>: Only search in this feed |
||
862 | |||
863 | uninstall -a|<package>: Uninstall a package |
||
864 | Options: |
||
865 | -a : Uninstalls all packages. |
||
866 | |||
867 | update -a|<feedname(s)>: Update packages and lists of feeds in feeds.conf . |
||
868 | Options: |
||
869 | -a : Update all feeds listed within feeds.conf. Otherwise the specified feeds will be updated. |
||
870 | -i : Recreate the index only. No feed update from repository is performed. |
||
871 | -f : Force updating feeds even if there are changed, uncommitted files. |
||
872 | |||
873 | clean: Remove downloaded/generated files. |
||
874 | |||
875 | EOF |
||
876 | exit(1); |
||
877 | } |
||
878 | |||
879 | my %commands = ( |
||
880 | 'list' => \&list, |
||
881 | 'update' => \&update, |
||
882 | 'install' => \&install, |
||
883 | 'search' => \&search, |
||
884 | 'uninstall' => \&uninstall, |
||
885 | 'feed_config' => \&feed_config, |
||
886 | 'clean' => sub { |
||
887 | system("rm -rf ./feeds ./package/feeds"); |
||
888 | } |
||
889 | ); |
||
890 | |||
891 | my $arg = shift @ARGV; |
||
892 | $arg or usage(); |
||
893 | parse_config; |
||
894 | foreach my $cmd (keys %commands) { |
||
895 | $arg eq $cmd and do { |
||
896 | exit(&{$commands{$cmd}}()); |
||
897 | }; |
||
898 | } |
||
899 | usage(); |