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