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