Remove QtMultimediaKit - all content has moved to QtMultimedia.
[mirror/qt/qt5.git] / init-repository
1 #!/usr/bin/env perl
2 #############################################################################
3 ##
4 ## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
5 ## All rights reserved.
6 ## Contact: Nokia Corporation (qt-info@nokia.com)
7 ##
8 ## This file is part of the utilities of the Qt Toolkit.
9 ##
10 ## $QT_BEGIN_LICENSE:LGPL$
11 ## GNU Lesser General Public License Usage
12 ## This file may be used under the terms of the GNU Lesser General Public
13 ## License version 2.1 as published by the Free Software Foundation and
14 ## appearing in the file LICENSE.LGPL included in the packaging of this
15 ## file. Please review the following information to ensure the GNU Lesser
16 ## General Public License version 2.1 requirements will be met:
17 ## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ##
19 ## In addition, as a special exception, Nokia gives you certain additional
20 ## rights. These rights are described in the Nokia Qt LGPL Exception
21 ## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ##
23 ## GNU General Public License Usage
24 ## Alternatively, this file may be used under the terms of the GNU General
25 ## Public License version 3.0 as published by the Free Software Foundation
26 ## and appearing in the file LICENSE.GPL included in the packaging of this
27 ## file. Please review the following information to ensure the GNU General
28 ## Public License version 3.0 requirements will be met:
29 ## http://www.gnu.org/copyleft/gpl.html.
30 ##
31 ## Other Usage
32 ## Alternatively, this file may be used in accordance with the terms and
33 ## conditions contained in a signed written agreement between you and Nokia.
34 ##
35 ##
36 ##
37 ##
38 ##
39 ## $QT_END_LICENSE$
40 ##
41 #############################################################################
42
43 use v5.10;
44 use strict;
45 use warnings;
46
47 package Qt::InitRepository;
48
49
50 =head1 NAME
51
52 init-repository - initialize the Qt5 repository and all submodules
53
54 =head1 SYNOPSIS
55
56   ./init-repository [options]
57
58 This script may be run after an initial `git clone' of Qt5 in order to check
59 out all submodules.
60
61
62 =head1 OPTIONS
63
64 B<Global options:>
65
66 =over
67
68 =item --force, -f
69
70 Force initialization (even if the submodules are already checked out).
71
72
73 =item --quiet, -q
74
75 Be quiet.  Will exit cleanly if the repository is already initialized.
76
77 =back
78
79
80 B<Module options:>
81
82 =over
83
84 =item --no-webkit
85
86 Skip webkit and webkit examples submodules.
87 It may be desirable to skip these modules due to the large size of the webkit
88 git repository.
89
90 =item --module-subset=<module1>,<module2>...
91
92 Only initialize the specified subset of modules given as the argument. Specified
93 modules must already exist in .gitmodules.
94
95 =item --no-update
96
97 Skip the `git submodule update' command.
98
99
100 =item --ignore-submodules
101
102 Set git config to ignore submodules by default when doing operations on the
103 qt5 repo, such as `pull', `fetch', `diff' etc.
104
105 This option is default for --nokia-developer/--brisbane.
106
107 After using this option, pass `--ignore-submodules=none' to git to override
108 it as needed.
109
110 =back
111
112
113 B<Repository options:>
114
115 =over
116
117 =item --nokia-developer
118
119 Switch to internal Nokia URLs.
120
121
122 =item --brisbane
123
124 Switch to internal Nokia URLs and make use of the Brisbane git mirrors.
125 (Implies `--mirror' and `--mirror-webkit').
126
127 =item --berlin
128
129 Switch to internal Nokia URLs and make use of the Berlin git mirrors.
130 (Implies `--mirror' and `--mirror-webkit').
131
132
133 =item --ssh
134
135 Use the SSH protocol for git operations.  This may be useful if the git
136 protocol is blocked by a firewall. Note that this requires a user account
137 with an uploaded SSH key on all servers used.  (Implies `--nokia-developer').
138
139 The `--ssh' option does not affect the gerrit remotes.
140
141
142 =item --http
143
144 Use the HTTP protocol for git operations.  This may be useful if the git
145 protocol is blocked by a firewall.  Note that this only works with the
146 external Gitorious server.
147
148 The `--http' option does not affect the gerrit remotes.
149
150
151 =item --codereview-username <Gerrit/JIRA username>
152
153 Adds a (potentially) writable remote named `gerrit' for each module,
154 for use with the Gerrit code review tool.
155 This requires a username for SSH access to the codereview.qt-project.org
156 server, which will be the same username you have for the bugtracker at
157 bugreports.qt.nokia.com.
158
159 If this option is omitted, the gerrit remote is created with read-only
160 access (using HTTP protocol).
161
162
163 =item --alternates <path to other Qt5 repo>
164
165 Adds alternates for each submodule to another full qt5 checkout. This makes
166 this qt5 checkout very small, as it will use the object store of the
167 alternates before unique objects are stored in its own object store.
168
169 This option has no effect when using `--no-update'.
170
171 B<NOTE:> This will make this repo dependent on the alternate, which is
172 potentially dangerous!  The dependency can be broken by also using
173 the `--copy-objects' option, or by running C<git repack -a> in each
174 submodule, where required.  Please read the note about the `--shared' option
175 in the documentation of `git clone' for more information.
176
177
178 =item --copy-objects
179
180 When `--alternates' is used, automatically do a C<git repack -a> in each
181 submodule after cloning, to ensure that the repositories are independent
182 from the source used as a reference for cloning.
183
184 Note that this negates the disk usage benefits gained from the use of
185 `--alternates'.
186
187
188 =item --mirror <url-base>
189
190 Uses <url-base> as the base URL for submodule git mirrors.
191
192 For example:
193
194   --mirror user@machine:/foo/bar
195
196 ...will use the following as a mirror for qtbase:
197
198   user@machine:/foo/bar/qtbase.git
199
200
201 =item --mirror-webkit <url>
202
203 Uses <url> as the URL for the webkit git mirror.
204
205 =back
206
207 =cut
208
209 use Carp         qw( confess             );
210 use English      qw( -no_match_vars      );
211 use Getopt::Long qw( GetOptionsFromArray );
212 use Pod::Usage   qw( pod2usage           );
213 use Cwd          qw( getcwd              );
214
215 my %PROTOCOLS = (
216     'internal'  => 'git://scm.dev.nokia.troll.no/' ,
217     'ssh'       => 'git@scm.dev.nokia.troll.no:'   ,
218     'http'      => 'http://git.gitorious.org/'     ,
219 );
220
221 my %GERRIT_REPOS = map { $_ => "qt/$_" } qw(
222     qt5
223     qlalr
224     qtactiveqt
225     qtbase
226     qtconnectivity
227     qtdeclarative
228     qtdoc
229     qtdocgallery
230     qtfeedback
231     qtlocation
232     qtmultimedia
233     qtphonon
234     qtpim
235     qtqa
236     qtrepotools
237     qtscript
238     qtsensors
239     qtsvg
240     qtsystems
241     qttools
242     qttranslations
243     qtwayland
244     qtwebkit-examples-and-demos
245     qtxmlpatterns
246 );
247 $GERRIT_REPOS{qtquick3d} = "qt/quick3d";
248
249 # Protocol-specific repo overrides, if they differ from the values set in the git submodule config
250 # (e.g. because public vs private names differ for whatever reason)
251 my %PROTOCOL_REPOS = (
252     qtquick3d   =>  {
253         internal    =>  "qt/quick3d",   # instead of qt-quick3d/qt-quick3d on gitorious
254         ssh         =>  "qt/quick3d",
255     },
256 );
257
258 my $GERRIT_SSH_BASE
259     = 'ssh://codereview.qt-project.org:29418/';
260
261 my $GERRIT_HTTP_BASE
262     = 'http://codereview.qt-project.org/p/';
263
264 my $BNE_MIRROR_URL_BASE
265     = 'git://bq-git.apac.nokia.com/qtsoftware/';
266
267 my $BNE_MIRROR_WEBKIT_URL
268     = 'git://bq-git.apac.nokia.com/qtsoftware/research/gitorious-org-webkit-qtwebkit-mirror.git';
269
270 my $BNE_MIRROR_V8_URL
271     = 'git://bq-git.apac.nokia.com/github/v8.git';
272
273 my $BER_MIRROR_URL_BASE
274     = 'git://ber-git.europe.nokia.com/';
275
276 my $BER_MIRROR_WEBKIT_URL
277     = 'git://ber-git.europe.nokia.com/qtwebkit/qtwebkit.git';
278
279
280 sub new
281 {
282     my ($class, @arguments) = @_;
283
284     my $self = {};
285     bless $self, $class;
286     $self->parse_arguments(@arguments);
287
288     return $self;
289 }
290
291 # Like `system', but possibly log the command, and die on non-zero exit code
292 sub exe
293 {
294     my ($self, @cmd) = @_;
295
296     if (!$self->{quiet}) {
297         print "+ @cmd\n";
298     }
299
300     if (system(@cmd) != 0) {
301         confess "@cmd exited with status $CHILD_ERROR";
302     }
303
304     return;
305 }
306
307 sub parse_arguments
308 {
309     my ($self, @args) = @_;
310
311     %{$self} = (%{$self},
312         'alternates'          => "",
313         'codereview-username' => "",
314         'detach-alternates'   => 0 ,
315         'force'               => 0 ,
316         'ignore-submodules'   => 0 ,
317         'mirror-url'          => "",
318         'mirror-webkit-url'   => "",
319         'mirror-v8-url'       => "",
320         'nokia-developer'     => 0 ,
321         'protocol'            => "",
322         'update'              => 1 ,
323         'webkit'              => 1 ,
324         'module-subset'       => "",
325     );
326
327     GetOptionsFromArray(\@args,
328         'alternates=s'      =>  \$self->{qw{ alternates        }},
329         'codereview-username=s' => \$self->{qw{ codereview-username }},
330         'copy-objects'      =>  \$self->{qw{ detach-alternates }},
331         'force'             =>  \$self->{qw{ force             }},
332         'ignore-submodules' =>  \$self->{qw{ ignore-submodules }},
333         'mirror-webkit=s'   =>  \$self->{qw{ mirror-webkit-url }},
334         'mirror=s'          =>  \$self->{qw{ mirror-url        }},
335         'nokia-developer'   =>  \$self->{qw{ nokia-developer   }},
336         'quiet'             =>  \$self->{qw{ quiet             }},
337         'update!'           =>  \$self->{qw{ update            }},
338         'webkit!'           =>  \$self->{qw{ webkit            }},
339         'module-subset=s'   =>  \$self->{qw{ module-subset     }},
340
341         'help|?'            =>  sub { pod2usage(1);               },
342         'http'              =>  sub { $self->{protocol} = 'http'; },
343         'ssh|ssh-protocol'  =>  sub { $self->{protocol} = 'ssh';  },
344
345         'brisbane|brisbane-nokia-developer' => sub {
346             $self->{'nokia-developer'}   = 1;
347             $self->{'protocol'}          = 'internal';
348             $self->{'mirror-url'}        = $BNE_MIRROR_URL_BASE;
349             $self->{'mirror-v8-url'}     = $BNE_MIRROR_V8_URL;
350             $self->{'mirror-webkit-url'} = $BNE_MIRROR_WEBKIT_URL;
351             $self->{'ignore-submodules'} = 1;
352         },
353
354         'berlin|berlin-nokia-developer' => sub {
355             $self->{'nokia-developer'}   = 1;
356             $self->{'protocol'}          = 'internal';
357             $self->{'mirror-url'}        = $BER_MIRROR_URL_BASE;
358             $self->{'mirror-webkit-url'} = $BER_MIRROR_WEBKIT_URL;
359         },
360
361         'nokia-developer' => sub {
362             $self->{'nokia-developer'}   = 1;
363             $self->{'protocol'}          = 'internal';
364             $self->{'ignore-submodules'} = 1;
365         },
366     ) || pod2usage(2);
367
368     if ($self->{'nokia-developer'} && $self->{'protocol'} eq 'http') {
369         print "*** Ignoring use of HTTP protocol, as it's only usable with external server\n";
370         $self->{'protocol'} = '';
371     }
372
373     # Replace any double trailing slashes from end of mirror
374     $self->{'mirror-url'} =~ s{//+$}{/};
375
376     if ($self->{'module-subset'}) {
377         $self->{'module-subset'} = {
378             map { $_ => 1 } split(qr{,}, $self->{'module-subset'})
379         };
380     }
381
382     return;
383 }
384
385 sub check_if_already_initialized
386 {
387     my ($self) = @_;
388
389     # We consider the repo as `initialized' if submodule.qtbase.url is set
390     if (qx(git config --get submodule.qtbase.url)) {
391         if ($self->{force}) {
392             my @configresult = qx(git config -l);
393             foreach (@configresult) {
394                 # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
395                 if (/(submodule\.[^.=]+)\.url=.*/) {
396                     $self->exe('git', 'config', '--remove-section', $1);
397                 }
398             }
399         }
400         else {
401             exit 0 if ($self->{quiet});
402             print "Will not reinitialize already initialized repository (use -f to force)!\n";
403             exit 1;
404         }
405     }
406
407     return;
408 }
409
410 sub git_submodule_init
411 {
412     my ($self) = @_;
413
414     my @init_args;
415     if ($self->{quiet}) {
416         push @init_args, '--quiet';
417     }
418     $self->exe('git', 'submodule', 'init', @init_args);
419
420     my $template = getcwd()."/.commit-template";
421     if (-e $template) {
422         $self->exe('git', 'config', 'commit.template', $template);
423     }
424
425     return;
426 }
427
428 sub git_disable_webkit_submodule
429 {
430     my ($self) = @_;
431
432     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit');
433     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit-examples-and-demos');
434
435     return;
436 }
437
438 sub git_prune_submodules
439 {
440     my ($self) = @_;
441
442     my @configresult = qx(git config -l);
443     foreach my $line (@configresult) {
444         if ($line =~ /submodule\.([^.=]+)\.url=/) {
445             my $module_name = $1;
446             if (!$self->{'module-subset'}{$module_name}) {
447                 $self->exe('git', 'config', '--remove', "submodule.$module_name");
448             }
449         }
450     }
451 }
452
453 sub git_set_submodule_config
454 {
455     my ($self) = @_;
456
457     my @configresult          = qx(git config -l);
458     my $protocol              = $self->{protocol};
459     my $url_base_for_protocol = $PROTOCOLS{$protocol};
460
461     foreach my $line (@configresult) {
462         # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
463         next if ($line !~ /submodule\.([^.=]+)\.url=(.*)/);
464
465         my $key   = $1;
466         my $value = $2;
467
468         if ($protocol) {
469             # WebKit is special, and has only external link.
470             if ($key ne 'qtwebkit') {
471                 # qt-labs projects are still hosted under qt internally.
472                 if ($protocol ne 'http') {
473                     $value =~ s,^git://gitorious\.org/qt-labs/,${url_base_for_protocol}qt/,;
474                 }
475
476                 if ($PROTOCOL_REPOS{$key}->{$protocol}) {
477                     # If this repo has an explicitly set basename for this protocol, use it...
478                     # e.g.   'git@example.com:'     . 'qt/quick3d'
479                     $value = $url_base_for_protocol . $PROTOCOL_REPOS{$key}->{$protocol};
480                 }
481                 else {
482                     # ...otherwise, assume the selected protocol uses same naming structure
483                     # as gitorious.org
484                     # e.g. git://gitorious.org/qt/qt5 => git@example.com:qt/qt5
485                     $value =~ s,^git://gitorious\.org/,$url_base_for_protocol,;
486                 }
487             }
488         }
489
490         $self->exe('git', 'config', "submodule.$key.url", $value);
491
492         if ($self->{'ignore-submodules'}) {
493             $self->exe('git', 'config', "submodule.$key.ignore", 'all');
494         }
495     }
496
497     return;
498 }
499
500 sub git_clone_all_submodules
501 {
502     my ($self) = @_;
503
504     # manually clone each repo here, so we can easily use reference repos, mirrors etc
505     my @configresult = qx(git config -l);
506     foreach my $line (@configresult) {
507         if ($line =~ /submodule\.([^.=]+)\.url=(.*)/) {
508             $self->git_clone_one_submodule($1, $2);
509         }
510     }
511
512     $self->exe('git', 'submodule', 'update');
513
514     return;
515 }
516
517 sub git_add_remotes
518 {
519     my ($self, $repo_basename) = @_;
520
521     my $protocol              = $self->{protocol};
522     my $url_base_for_protocol = $PROTOCOLS{$protocol};
523
524     my %current_remotes;
525     for my $line (qx(git remote show)) {
526         chomp $line;
527         $current_remotes{$line} = 1;
528     }
529
530     my $gerrit_repo_basename = $GERRIT_REPOS{$repo_basename};
531     if ($gerrit_repo_basename && !$current_remotes{'gerrit'}) {
532         my $gerrit_repo_url;
533
534         # If given a username, we use writable remote (ssh).
535         # Otherwise, we use read-only (http).
536         if ($self->{'codereview-username'}) {
537             $gerrit_repo_url = $GERRIT_SSH_BASE;
538             $gerrit_repo_url =~ s[^ssh://][ssh://$self->{'codereview-username'}@];
539         }
540         else {
541             $gerrit_repo_url = $GERRIT_HTTP_BASE;
542         }
543
544         $gerrit_repo_url .= $gerrit_repo_basename;
545         $self->exe('git', 'remote', 'add', 'gerrit', $gerrit_repo_url);
546
547         $current_remotes{'gerrit'} = 1;
548     }
549
550     # if repo still has no gerrit repo defined, alias it to origin
551     if (!$current_remotes{'gerrit'}) {
552         my @configresult = qx(git remote -v);
553         foreach (@configresult) {
554             if (/^origin\s+(\S+) \(fetch\)/) {
555                 $self->exe('git', 'remote', 'add', 'gerrit', $1);
556             }
557         }
558     }
559
560     return;
561 }
562
563 sub git_clone_one_submodule
564 {
565     my ($self, $submodule, $url) = @_;
566
567     my $alternates            = $self->{ 'alternates'        };
568     my $mirror_url            = $self->{ 'mirror-url'        };
569     my $mirror_webkit_url     = $self->{ 'mirror-webkit-url' };
570     my $mirror_v8_url         = $self->{ 'mirror-v8-url'     };
571     my $protocol              = $self->{ 'protocol'          };
572
573     # `--reference FOO' args for the clone, if any.
574     my @reference_args;
575
576     if ($alternates) {
577         # alternates is a qt5 repo, so the submodule will be under that.
578         if (-d "$alternates/$submodule") {
579             @reference_args = ('--reference', "$alternates/$submodule");
580         }
581         else {
582             print " *** $alternates/$submodule not found, ignoring alternate for this submodule\n";
583         }
584     }
585
586     my $mirror;
587     if ($mirror_url && ($submodule ne 'qtwebkit')) {
588         $mirror = $mirror_url.( $PROTOCOL_REPOS{$submodule}->{internal} // "qt/$submodule" );
589         $mirror .= ".git" unless (-d $mirror); # Support local disk mirror
590     }
591     elsif ($mirror_webkit_url && ($submodule eq 'qtwebkit')) {
592         $mirror = $mirror_webkit_url;
593     }
594
595     my $do_clone = (! -d "$submodule/.git");
596     if ($do_clone) {
597         $self->exe('git', 'clone', @reference_args, ($mirror ? $mirror : $url), $submodule);
598     }
599
600     chdir($submodule) or confess "chdir $submodule: $OS_ERROR";
601
602     if (!$do_clone) {
603         $self->exe('git', 'fetch', ($mirror ? $mirror : $url));
604     }
605
606     my $template = getcwd()."/../.commit-template";
607     if (-e $template) {
608         $self->exe('git', 'config', 'commit.template', $template);
609     }
610
611     if ($mirror) {
612         $self->exe('git', 'config', 'remote.origin.url', $url);
613
614         # In `force' mode, remove the mirror if it already exists,
615         # since we may be reinitializing the module.
616         if ($self->{force}) {
617             eval { $self->exe('git', 'remote', 'rm', 'mirror'); }; # failure is OK
618         }
619
620         $self->exe('git', 'remote', 'add', 'mirror', $mirror);
621     }
622
623     $self->git_add_remotes($submodule);
624
625     if ($self->{'detach-alternates'}) {
626         $self->exe('git', 'repack', '-a');
627
628         my $alternates_path = '.git/objects/info/alternates';
629         unlink($alternates_path) || confess "unlink $alternates_path: $OS_ERROR";
630     }
631
632     if ($submodule eq "qtbase" || $submodule eq "qtdeclarative") { #Extra steps needed to setup base and declarative
633         $self->exe('git', 'submodule', 'init'); 
634         if ($mirror_v8_url || $protocol eq 'http') {
635             my @configresult = qx(git config -l);
636             my $v8url;
637             foreach my $line (@configresult) {
638                 # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
639                 next if ($line !~ /submodule.src\/3rdparty\/v8.url=(.*)/);
640                 $v8url = $1;
641             }
642
643             if ($v8url) {
644                 if ($protocol eq 'http') {
645                     # rewrite the git:// url to https://
646                     if ($v8url =~ s{^git://github}{https://github}) {
647                         $self->exe('git', 'config', 'submodule.src/3rdparty/v8.url', $v8url);
648                     }
649                     else {
650                         warn 'You requested git over http, but I could not figure out how to '
651                             ."rewrite v8's giturl of $v8url";
652                     }
653                 }
654
655                 if ($mirror_v8_url && $do_clone) {
656                     chdir('src/3rdparty/') or confess "chdir $submodule/src/3rdparty: $OS_ERROR";
657                     $self->exe('git', 'clone', $mirror_v8_url, 'v8');
658                     chdir('v8') or confess "chdir $submodule/src/3rdparty/v8: $OS_ERROR";
659                     $self->exe('git', 'config', 'remote.origin.url', $v8url);
660                     chdir('../../..') or confess "cd ../../..: $OS_ERROR";
661                 }
662             }
663         }
664         $self->exe('git', 'submodule', 'update'); 
665     } 
666
667     chdir("..") or confess "cd ..: $OS_ERROR";
668
669     return;
670 }
671
672 sub run
673 {
674     my ($self) = @_;
675
676     $self->check_if_already_initialized;
677     $self->git_submodule_init;
678
679     if (!$self->{webkit}) {
680         $self->git_disable_webkit_submodule;
681     }
682
683     if ($self->{'module-subset'}) {
684         $self->git_prune_submodules;
685     }
686
687     $self->git_set_submodule_config;
688
689     if ($self->{update}) {
690         $self->git_clone_all_submodules;
691     }
692
693     $self->git_add_remotes('qt5');
694
695     return;
696 }
697
698 #==============================================================================
699
700 Qt::InitRepository->new(@ARGV)->run if (!caller);
701 1;