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