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