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