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