]> rtime.felk.cvut.cz Git - l4.git/blob - repomgr
892e08a97642c059bfb7054a7f5b7a112952b4ba
[l4.git] / repomgr
1 #! /usr/bin/perl -W
2
3 use strict;
4
5 my %modules =
6  (
7    repomgr => { paths => [ qw(repomgr) ] },
8
9    bid => { paths => [ qw(l4/Makefile
10                           l4/BENCHMARKING
11                           l4/COPYING-GPL-2
12                           l4/COPYING-LGPL-2.1
13                           l4/LICENSING
14                           l4/mk
15                           l4/conf
16                           l4/pkg/Makefile
17                           l4/pkg/README
18                           l4/tool/Makefile
19                           l4/tool/gendep
20                           l4/tool/kconfig
21                           l4/tool/vim
22                           l4/tool/lib
23                           l4/tool/elf-patcher
24                          ) ]
25           },
26
27    toolbin => { paths => [ map { "l4/tool/bin/$_" }
28                            qw(isocreator qemu-x86-launch ux-launch
29                               gengrub1iso gengrub2iso entry-selector
30                               mkspafs genexportpack
31                              ) ]
32               },
33
34    l4re => { paths => [ map { "l4/pkg/$_" } qw(
35                          boehm_gc bootstrap libgcc libgcc-pure
36                          crtn cxx cxx_libc_io cxx_thread drivers-frst hello
37                          ldscripts
38                          l4re l4re_c l4re_kernel l4re_vfs l4sys l4util
39                          ldscripts ldso
40                          libc_backends libkproxy libloader
41                          libsigma0
42                          libstdc++-headers libstdc++-v3 libstdc++-v3-minimal
43                          libsupc++ libsupc++-minimal
44                          libvbus libvcpu loader log lua moe ned sigma0
45                          uclibc uclibc-minimal uclibc-headers
46                         ) ],
47              pub_module => 1,
48              modules => [ qw(bid toolbin) ],
49            },
50
51    # ./mk/pkgdeps -A mk/aliases.d pkgdeps pkg ...
52    l4linux_requirements
53         => { paths => [ map { "l4/pkg/$_" } qw(
54                         libedid libio libio-io lxfuxlibc rtc shmc
55                         acpica io drivers fb-drv x86emu input libirq
56                     ) ],
57                     pub_module => 1,
58                     modules => [ qw(l4re) ],
59                   },
60
61    examples_core => {
62      paths => [ qw(l4/pkg/hello),
63                 map { "l4/pkg/examples/$_" }
64                 qw(Makefile
65                    Control
66                    sys
67                    clntsrv
68                    misc/Makefile
69                    misc/cat
70                    misc/shared-hello
71                    libs/Makefile
72                    libs/l4re
73                  ) ],
74    },
75
76
77    examples_all => {
78      modules => [ qw(examples_core) ],
79      paths => [ qw(l4/pkg/hello),
80                 map { "l4/pkg/examples/$_" }
81                 qw(
82                    fb/Makefile
83                    fb/spectrum
84                    misc/eb_leds
85                    misc/fortran-hello
86                    misc/reboot
87                    libs/inputtst
88                    libs/libc_thread_safe
89                    libs/libgomp
90                    libs/libio
91                    libs/libirq
92                    libs/libpng
93                    libs/shmc
94                  ) ],
95    },
96
97    doc => { paths => [ qw(l4/doc/Makefile l4/doc/source) ], },
98
99    l4re_snapshot =>  {
100      paths => [ map { "l4/pkg/$_" }
101                 qw(acpica
102                    ankh
103                    boost-lite
104                    cons
105                    cunit
106                    dash
107                    demangle
108                    dde
109                    dde-libinput
110                    dope
111                    drivers
112                    expat2
113                    fb-drv
114                    fbterminal
115                    ferret
116                    fuxfprov
117                    gnu-efi
118                    hello
119                    input
120                    io
121                    l4con
122                    lib_vt100
123                    libbsd
124                    libbsd-full
125                    libedid
126                    libevent
127                    libc_be_stdin
128                    libcrypto
129                    libevent
130                    libgfxbitmap
131                    libgfortran
132                    libgomp
133                    libfdt
134                    libiniparser
135                    libio
136                    libio-io
137                    libirq
138                    libjpeg
139                    libpng
140                    libsdl
141                    libsdl-image
142                    linux-26-headers
143                    lwip
144                    lxfuxlibc
145                    mag
146                    mag-gfx
147                    ocaml
148                    ocaml_toys
149                    plr
150                    python
151                    readline
152                    rtc
153                    scout
154                    scout-gfx
155                    serial-drv
156                    shmc
157                    slab
158                    spafs
159                    sqlite
160                    tlsf
161                    tmpfs
162                    udis86
163                    valgrind
164                    vmm
165                    x86emu
166                    zlib
167                    ) ],
168      modules => [ qw(l4re examples_all doc toolbin) ] },
169
170    l4re_all => { paths   => [ qw(l4/pkg l4/tool) ],
171                  modules => [ qw(l4re_snapshot) ] },
172
173    fiasco => {
174       pub_module => 1,
175       paths   => [ qw(kernel/fiasco/BENCHMARKING
176                       kernel/fiasco/COPYING
177                       kernel/fiasco/MAINTAINER
178                       kernel/fiasco/Makefile
179                       kernel/fiasco/README
180                       kernel/fiasco/src
181                       kernel/fiasco/tool
182                      ) ],
183    },
184
185    kernel => {
186       paths => [ qw(kernel/Makefile) ],
187    },
188
189    grub => {
190       paths => [ qw(grub) ],
191    },
192
193    remote_repo_l4re => {
194       modules => [ qw(l4re_snapshot) ],
195    },
196
197    remote_repo => { modules => [ qw(fiasco remote_repo_l4re) ],
198                     # those are going away, we need to keep them to get the
199                     # dirs updated and thus removed
200                     paths => [ qw(l4/pkg/libstdc++-v3_r
201                                   l4/pkg/libsupc++_r
202                                   l4/pkg/uclibc_r) ],
203                     },
204
205    all => {
206       modules => [ qw(remote_repo) ],
207    },
208  );
209
210 my %commands;
211 my $svnrev = $ENV{REPOMGR_SVN_REV} || 'HEAD';
212
213 sub get_root_url()
214 {
215   my $o = `svn info -r '$svnrev' --xml .`;
216   die "Failed 'svn info'." if $?;
217   $o =~ /<root>(.+)<\/root>/m;
218   $1;
219 }
220
221 sub merge_modules
222 {
223   my %paths;
224
225   sub do_merge
226   {
227     my $pathsref = shift;
228     my $count = shift;
229
230     die "Possible looping in modules structure detected!" unless $count;
231
232     foreach my $m (@_)
233       {
234         die "Unknown module '$m' referenced!" unless defined $modules{$m};
235         $$pathsref{$_} = 1 foreach @{$modules{$m}{paths}};
236         do_merge($pathsref, $count - 1, @{$modules{$m}{modules}});
237       }
238   }
239
240   do_merge(\%paths, 20, scalar @_ ? @_ : 'all');
241
242   sort keys %paths;
243 }
244
245 sub show_pub_modules()
246 {
247   print "Available modules:\n";
248   foreach (sort keys %modules)
249     {
250        print "  $_\n" if $modules{$_}{pub_module};
251     }
252 }
253
254 sub usage
255 {
256   my $command = shift;
257
258   # check alias
259   $command = $commands{$command}{alias}
260     if defined $command and defined $commands{$command}{alias};
261
262   if (!defined $command or $command eq 'help')
263     {
264       print "$0 command [option]\n";
265
266       print "Available commands, use '$0 help command' for help on the command:\n";
267       foreach (sort keys %commands)
268         {
269           print "  $_\n" if defined $commands{$_}{public};
270         }
271     }
272   elsif ($command eq 'update')
273     {
274       print "  'update' will update in the following way:\n".
275             "      update itself and re-exec if necessary\n".
276             "      call 'make update' in l4/pkg\n".
277             "      call 'svn update' every directory in kernel\n";
278     }
279   elsif ($command eq 'checkout')
280     {
281       print "  'checkout' will check out the given modules.\n";
282       show_pub_modules();
283     }
284   elsif ($command eq 'modules')
285     {
286       show_pub_modules();
287     }
288   else
289     {
290       print "  No such command '$command'.\n";
291     }
292 }
293
294 sub check_module_structure()
295 {
296   # make sure the paths look ok
297   foreach (merge_modules())
298     {
299       die "Trailing /'s in modules structure" if /\/$/;
300       die "Double // detected in modules structure" if /\/\//;
301     }
302 }
303
304 sub command_help
305 {
306   usage(@_);
307 }
308
309 sub command_update
310 {
311   print "XXX: todo\n";
312 }
313
314 sub command_root
315 {
316   my $url = shift;
317   my $dirname = shift;
318   die "Need to give URL" unless defined $url and defined $dirname;
319   system("svn co -r '$svnrev' $url --depth empty $dirname");
320 }
321
322 sub init_config($)
323 {
324   my $config_blob = shift;
325   $config_blob = '{}' unless defined $config_blob;
326   my $c;
327   unless ($c = eval($config_blob))
328     {
329       die "Couldn't parse config file: $@" if $@;
330       die "Couldn't do config file: $!" if $!;
331       die "Couldn't run config file";
332     }
333
334   my %a = %$c;
335
336   $a{base} = "trunk" unless defined $a{base};
337
338   return %a;
339 }
340
341 sub convert_path($$%)
342 {
343   my $p = shift;
344   my $partmatch = shift;
345   my %path_roots = @_;
346
347   $p =~ s/^\.\///;
348   $p .= '/';
349   foreach my $key (keys %path_roots)
350     {
351       my $r = $key;
352       $r .= '/' unless $r =~ /\/$/;
353       if ($partmatch)
354         {
355           # for partly matches we also need to return the modified path
356           # because otherwise we can't really know
357           if ($p =~ /^($r)(.*)$/)
358             {
359                my $s = $path_roots{$key}.'/'.$2;
360                # strip off last / again, it's just used for matching
361                return substr($s, 0, length($s) - 1);
362             }
363         }
364       else
365         {
366           return $path_roots{$key} if $p =~ /^$r$/;
367         }
368     }
369   undef;
370 }
371
372 sub do_checkout(%)
373 {
374   my %args = @_;
375   unless (defined ${$args{mods}}[0])
376     {
377       print "Supply module to check out.\n";
378       usage("checkout");
379       exit 1;
380     }
381
382   die "Current directory is no SVN WC" unless -d ".svn";
383
384   my $root_url = get_root_url();
385
386   my @paths = merge_modules(@{$args{mods}});
387
388   foreach my $paths (@paths)
389     {
390       my @path_elems = split /\/+/, $paths;
391       my $last_elem = pop @path_elems;
392       my $path = '.';
393
394       foreach my $pe (@path_elems)
395         {
396           if (! -d "$path/$pe")
397             {
398               # if we find something from path_roots then switch to that
399               my $changed_path = convert_path("$path/$pe", 0,
400                                               %{$args{conf}{path_roots}});
401
402               print "Creating $path/$pe\n";
403               print "   from $changed_path\n" if defined $changed_path;
404
405               # there's some other little problem with the 'depth' thing
406               # when we do checkout some specific list of files (and dirs),
407               # we need to use depth=empty so that we only get those
408               # specific files out of the directory, on the other side we'd
409               # (probably) like to have updates on the directory contents
410               # when we do 'svn up' which would would with depth=files (or
411               # infinite)
412               # As the first thing is merely only needed when doing a
413               # checkout for another repo... let's have a config option.
414               my $depth = 'files';
415               $depth = 'empty' if defined $ENV{REPOMGR_EXACT_CHECKOUT};
416
417               if (defined $changed_path)
418                   {
419                     my $cmd = "cd $path && svn co -r '$svnrev' --depth empty $root_url/$changed_path $pe";
420                     #print "cmd: $cmd\n";
421                     system($cmd);
422                     die "svn co failed" if $?;
423                   }
424                 else
425                   {
426                     my $cmd = "cd $path && svn update -q -r '$svnrev' --depth empty $pe";
427                     #print "cmd: $cmd\n";
428                     system($cmd);
429                     die "svn update failed" if $?;
430                   }
431             }
432           $path .= '/'.$pe;
433         }
434     }
435
436   print "Getting sources\n";
437   my $c = "svn update -r '$svnrev' --set-depth infinity ".join(' ', map { s/^\/+//; $_; } @paths);
438   #print "cmd: $c\n";
439   system($c);
440   die "svn update failed" if $?;
441 }
442
443 sub read_file($)
444 {
445   my $fn = shift;
446   return undef unless defined $fn;
447   my $blob;
448   if ($fn =~ /^(file|svn|ssh\+svn):\/\//)
449     {
450       $blob = `svn -r '$svnrev' cat $fn`;
451       undef $blob if $?;
452     }
453   elsif (open(A, $fn))
454     {
455       local undef $/;
456       $blob = <A>;
457       close A;
458     }
459   $blob;
460 }
461
462 sub command_checkout
463 {
464   my %conf = init_config(read_file("l4/conf/repomgr.conf"));
465   do_checkout(conf => { %conf }, mods => [ @_ ]);
466 }
467
468 sub fix_repomgr_path(%)
469 {
470   my %conf = @_;
471   # fix the path to the repomgr...
472   @{$modules{repomgr}{paths}} = map { "$conf{repomgr_prefix}/$_" } @{$modules{repomgr}{paths}}
473     if defined $conf{repomgr_prefix};
474 }
475
476 sub command_init
477 {
478   my $repo_root = shift;
479   my $repo_conf = '';
480   my $localdir  = 'src';
481
482   while (defined $_[0] && ($_[0] eq '-c' or $_[0] eq '-l'))
483     {
484       if ($_[0] eq '-c')
485         {
486           $repo_conf = $_[1];
487           shift; shift;
488         }
489       elsif ($_[0] eq '-l')
490         {
491           $localdir = $_[1];
492           shift; shift;
493         }
494     }
495
496   die "Usage: $0 init <REPOROOTURL> [-c <REPOCONFPATH>] [-l <LOCALDIR>] modules..."
497     if    not defined $repo_root or not defined $repo_conf
498        or not defined $localdir;
499
500   # for absolute path we assume a local config file, good for testing
501   my $confblob;
502   if ($repo_conf ne '')
503     {
504       if ($repo_conf =~ /^\//)
505         {
506           $confblob = read_file($repo_conf);
507           die "Cannot open '$repo_conf': $!" unless defined $confblob;
508         }
509       else
510         {
511           my $cmd = "svn cat -r '$svnrev' $repo_root\/$repo_conf";
512           $confblob = `$cmd`;
513           die "Command '$cmd' failed" if $?;
514         }
515     }
516
517   my %conf = init_config($confblob);
518
519   ($localdir = $conf{base}) =~ s/.*\/// unless defined $localdir;
520   print "localdir: $localdir\n";
521
522   my $cmd = "svn co -r '$svnrev' --depth empty $repo_root/$conf{base} $localdir";
523   system($cmd);
524   die "Command '$cmd' failed" if $?;
525   chdir $localdir;
526
527   fix_repomgr_path(%conf);
528   do_checkout(conf => { %conf }, mods => [ "repomgr", @_ ]);
529 }
530
531 sub command_modules
532 {
533   foreach (sort keys %modules)
534     {
535       print "$_\n" if defined $modules{$_}{pub_module};
536     }
537 }
538
539 sub command_list
540 {
541   print "$_\n" foreach merge_modules(@_);
542 }
543
544 sub command_listmapped
545 {
546   my $blob = read_file(shift);
547   die "Need config" unless defined $blob;
548   my %conf = init_config($blob);
549   fix_repomgr_path(%conf);
550   print join("\n", map {
551                          my $p = convert_path($_, 1, %{$conf{path_roots}});
552                          defined $p ? $p : $_;
553                        } merge_modules(@_));
554   print "\n";
555 }
556
557 %commands =
558  (
559    help      => { func => \&command_help, },
560    init      => { func => \&command_init, },
561    update    => { func => \&command_update, },
562    up        => { func => \&command_update, alias => 'update' },
563    checkout  => { func => \&command_checkout, public => 1},
564    co        => { func => \&command_checkout, alias => 'checkout'},
565    modules   => { func => \&command_modules, public => 1},
566    list      => { func => \&command_list, },
567    listmapped=> { func => \&command_listmapped, },
568    root      => { func => \&command_root, },
569  );
570
571 # ----------------------------------------------------------------
572
573 check_module_structure();
574
575 my $command = shift;
576
577 unless (defined $command)
578   {
579     usage();
580     exit 1;
581   }
582
583 if (defined $commands{$command})
584   {
585     &{$commands{$command}{func}}(@ARGV);
586   }
587 else
588   {
589     print "Unknown command '$command'.\n";
590     usage();
591     exit 1;
592   }