Add qtenginio as submodule
[mirror/qt/qt5.git] / init-repository
1 #!/usr/bin/env perl
2 #############################################################################
3 ##
4 ## Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
5 ## Contact: http://www.qt-project.org/legal
6 ##
7 ## This file is part of the utilities of the Qt Toolkit.
8 ##
9 ## $QT_BEGIN_LICENSE:LGPL$
10 ## Commercial License Usage
11 ## Licensees holding valid commercial Qt licenses may use this file in
12 ## accordance with the commercial license agreement provided with the
13 ## Software or, alternatively, in accordance with the terms contained in
14 ## a written agreement between you and Digia.  For licensing terms and
15 ## conditions see http://qt.digia.com/licensing.  For further information
16 ## use the contact form at http://qt.digia.com/contact-us.
17 ##
18 ## GNU Lesser General Public License Usage
19 ## Alternatively, this file may be used under the terms of the GNU Lesser
20 ## General Public License version 2.1 as published by the Free Software
21 ## Foundation and appearing in the file LICENSE.LGPL included in the
22 ## packaging of this file.  Please review the following information to
23 ## ensure the GNU Lesser General Public License version 2.1 requirements
24 ## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ##
26 ## In addition, as a special exception, Digia gives you certain additional
27 ## rights.  These rights are described in the Digia Qt LGPL Exception
28 ## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ##
30 ## GNU General Public License Usage
31 ## Alternatively, this file may be used under the terms of the GNU
32 ## General Public License version 3.0 as published by the Free Software
33 ## Foundation and appearing in the file LICENSE.GPL included in the
34 ## packaging of this file.  Please review the following information to
35 ## ensure the GNU General Public License version 3.0 requirements will be
36 ## met: http://www.gnu.org/copyleft/gpl.html.
37 ##
38 ##
39 ## $QT_END_LICENSE$
40 ##
41 #############################################################################
42
43 use v5.8;
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 The string "all" results in cloning all known modules. The default is the set of
95 maintained modules.
96
97 =item --no-update
98
99 Skip the `git submodule update' command.
100
101
102 =item --ignore-submodules
103
104 Set git config to ignore submodules by default when doing operations on the
105 qt5 repo, such as `pull', `fetch', `diff' etc.
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 --berlin
118
119 Switch to internal URLs and make use of the Berlin git mirrors.
120 (Implies `--mirror').
121
122 =item --oslo
123
124 Switch to internal URLs and make use of the Oslo git mirrors.
125 (Implies `--mirror').
126
127
128 =item --http
129
130 Use the HTTP protocol for git operations.  This may be useful if the git
131 protocol is blocked by a firewall.  Note that this only works with the
132 external Gitorious server.
133
134 The `--http' option does not affect the gerrit remotes.
135
136
137 =item --codereview-username <Gerrit/JIRA username>
138
139 Specify the user name for the (potentially) writable `gerrit' remote
140 for each module, for use with the Gerrit code review tool.
141
142 If this option is omitted, the gerrit remote is created without a username
143 and port number, and thus relies on a correct SSH configuration.
144
145
146 =item --alternates <path to other Qt5 repo>
147
148 Adds alternates for each submodule to another full qt5 checkout. This makes
149 this qt5 checkout very small, as it will use the object store of the
150 alternates before unique objects are stored in its own object store.
151
152 This option has no effect when using `--no-update'.
153
154 B<NOTE:> This will make this repo dependent on the alternate, which is
155 potentially dangerous!  The dependency can be broken by also using
156 the `--copy-objects' option, or by running C<git repack -a> in each
157 submodule, where required.  Please read the note about the `--shared' option
158 in the documentation of `git clone' for more information.
159
160
161 =item --copy-objects
162
163 When `--alternates' is used, automatically do a C<git repack -a> in each
164 submodule after cloning, to ensure that the repositories are independent
165 from the source used as a reference for cloning.
166
167 Note that this negates the disk usage benefits gained from the use of
168 `--alternates'.
169
170
171 =item --mirror <url-base>
172
173 Uses <url-base> as the base URL for submodule git mirrors.
174
175 For example:
176
177   --mirror user@machine:/foo/bar
178
179 ...will use the following as a mirror for qtbase:
180
181   user@machine:/foo/bar/qt/qtbase.git
182
183 The mirror is permitted to contain a subset of the submodules; any
184 missing modules will fall back to the canonical URLs.
185
186 =back
187
188 =cut
189
190 use Carp         qw( confess             );
191 use English      qw( -no_match_vars      );
192 use Getopt::Long qw( GetOptionsFromArray );
193 use Pod::Usage   qw( pod2usage           );
194 use Cwd          qw( getcwd              );
195
196 my %PROTOCOLS = (
197     'http'      => 'http://git.gitorious.org/'     ,
198 );
199
200 my %GERRIT_REPOS = map { $_ => "qt/$_" } qw(
201     qt3d
202     qt5
203     qlalr
204     qtactiveqt
205     qtandroidextras
206     qtbase
207     qtconnectivity
208     qtdeclarative
209     qtdoc
210     qtdocgallery
211     qtenginio
212     qtfeedback
213     qtgraphicaleffects
214     qtimageformats
215     qtjsondb
216     qtlocation
217     qtmacextras
218     qtmultimedia
219     qtpim
220     qtqa
221     qtquick1
222     qtquickcontrols
223     qtrepotools
224     qtscript
225     qtsensors
226     qtserialport
227     qtsvg
228     qtsystems
229     qttools
230     qttranslations
231     qtwayland
232     qtwebkit
233     qtwebkit-examples
234     qtwinextras
235     qtx11extras
236     qtxmlpatterns
237 );
238
239 my @DEFAULT_REPOS = qw(
240     qtactiveqt
241     qtandroidextras
242     qtbase
243     qtconnectivity
244     qtdeclarative
245     qtdoc
246     qtgraphicaleffects
247     qtimageformats
248     qtmacextras
249     qtmultimedia
250     qtqa
251     qtquick1
252     qtquickcontrols
253     qtlocation
254     qtrepotools
255     qtscript
256     qtsensors
257     qtserialport
258     qtsvg
259     qttools
260     qttranslations
261     qtwebkit
262     qtwebkit-examples
263     qtwinextras
264     qtx11extras
265     qtxmlpatterns
266 );
267
268 my $GERRIT_SSH_BASE
269     = 'ssh://@USER@codereview.qt-project.org@PORT@/';
270
271 my $BER_MIRROR_URL_BASE
272     = 'git://hegel/';
273
274 my $OSLO_MIRROR_URL_BASE
275     = 'git://qilin/';
276
277 sub new
278 {
279     my ($class, @arguments) = @_;
280
281     my $self = {};
282     bless $self, $class;
283     $self->parse_arguments(@arguments);
284
285     return $self;
286 }
287
288 # Like `system', but possibly log the command, and die on non-zero exit code
289 sub exe
290 {
291     my ($self, @cmd) = @_;
292
293     if (!$self->{quiet}) {
294         print "+ @cmd\n";
295     }
296
297     if (system(@cmd) != 0) {
298         confess "@cmd exited with status $CHILD_ERROR";
299     }
300
301     return;
302 }
303
304 sub parse_arguments
305 {
306     my ($self, @args) = @_;
307
308     %{$self} = (%{$self},
309         'alternates'          => "",
310         'codereview-username' => "",
311         'detach-alternates'   => 0 ,
312         'force'               => 0 ,
313         'ignore-submodules'   => 0 ,
314         'mirror-url'          => "",
315         'protocol'            => "",
316         'update'              => 1 ,
317         'webkit'              => 1 ,
318         'module-subset'       => join(",", @DEFAULT_REPOS),
319     );
320
321     GetOptionsFromArray(\@args,
322         'alternates=s'      =>  \$self->{qw{ alternates        }},
323         'codereview-username=s' => \$self->{qw{ codereview-username }},
324         'copy-objects'      =>  \$self->{qw{ detach-alternates }},
325         'force'             =>  \$self->{qw{ force             }},
326         'ignore-submodules' =>  \$self->{qw{ ignore-submodules }},
327         'mirror=s'          =>  \$self->{qw{ mirror-url        }},
328         'quiet'             =>  \$self->{qw{ quiet             }},
329         'update!'           =>  \$self->{qw{ update            }},
330         'webkit!'           =>  \$self->{qw{ webkit            }},
331         'module-subset=s'   =>  \$self->{qw{ module-subset     }},
332
333         'help|?'            =>  sub { pod2usage(1);               },
334         'http'              =>  sub { $self->{protocol} = 'http'; },
335
336         'berlin' => sub {
337             $self->{'mirror-url'}        = $BER_MIRROR_URL_BASE;
338         },
339         'oslo' => sub {
340             $self->{'mirror-url'}        = $OSLO_MIRROR_URL_BASE;
341         },
342     ) || pod2usage(2);
343
344     # Replace any double trailing slashes from end of mirror
345     $self->{'mirror-url'} =~ s{//+$}{/};
346
347     if ($self->{'module-subset'} eq "all") {
348         $self->{'module-subset'} = "";
349     } else {
350         $self->{'module-subset'} = {
351             map { $_ => 1 } split(qr{,}, $self->{'module-subset'})
352         };
353     }
354
355     return;
356 }
357
358 sub check_if_already_initialized
359 {
360     my ($self) = @_;
361
362     # We consider the repo as `initialized' if submodule.qtbase.url is set
363     if (qx(git config --get submodule.qtbase.url)) {
364         if ($self->{force}) {
365             my @configresult = qx(git config -l);
366             foreach (@configresult) {
367                 # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
368                 if (/(submodule\.[^.=]+)\.url=.*/) {
369                     $self->exe('git', 'config', '--remove-section', $1);
370                 }
371             }
372         }
373         else {
374             exit 0 if ($self->{quiet});
375             print "Will not reinitialize already initialized repository (use -f to force)!\n";
376             exit 1;
377         }
378     }
379
380     return;
381 }
382
383 sub git_submodule_init
384 {
385     my ($self) = @_;
386
387     my @init_args;
388     if ($self->{quiet}) {
389         push @init_args, '--quiet';
390     }
391     $self->exe('git', 'submodule', 'init', @init_args);
392
393     my $template = getcwd()."/.commit-template";
394     if (-e $template) {
395         $self->exe('git', 'config', 'commit.template', $template);
396     }
397
398     return;
399 }
400
401 sub git_disable_webkit_submodule
402 {
403     my ($self) = @_;
404
405     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit');
406     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit-examples');
407
408     return;
409 }
410
411 sub git_prune_submodules
412 {
413     my ($self) = @_;
414
415     my @configresult = qx(git config -l);
416     foreach my $line (@configresult) {
417         if ($line =~ /submodule\.([^.=]+)\.url=/) {
418             my $module_name = $1;
419             if (!$self->{'module-subset'}{$module_name}) {
420                 $self->exe('git', 'config', '--remove', "submodule.$module_name");
421             }
422         }
423     }
424 }
425
426 sub git_set_submodule_config
427 {
428     my ($self) = @_;
429
430     my @configresult          = qx(git config -l);
431     my $protocol              = $self->{protocol};
432     my $url_base_for_protocol = $PROTOCOLS{$protocol};
433
434     foreach my $line (@configresult) {
435         # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
436         next if ($line !~ /submodule\.([^.=]+)\.url=(.*)/);
437
438         my $key   = $1;
439         my $value = $2;
440
441         if ($protocol) {
442                 # rewrite URL to chosen protocol
443                 $value =~ s,^git://gitorious\.org/,$url_base_for_protocol,;
444         }
445
446         $self->exe('git', 'config', "submodule.$key.url", $value);
447
448         if ($self->{'ignore-submodules'}) {
449             $self->exe('git', 'config', "submodule.$key.ignore", 'all');
450         }
451     }
452
453     return;
454 }
455
456 sub git_clone_all_submodules
457 {
458     my ($self) = @_;
459
460     # manually clone each repo here, so we can easily use reference repos, mirrors etc
461     my @configresult = qx(git config -l);
462     foreach my $line (@configresult) {
463         if ($line =~ /submodule\.([^.=]+)\.url=(.*)/) {
464             $self->git_clone_one_submodule($1, $2);
465         }
466     }
467
468     if ($self->{update}) {
469         $self->exe('git', 'submodule', 'update', '--recursive');
470     }
471
472     return;
473 }
474
475 sub git_add_remotes
476 {
477     my ($self, $repo_basename) = @_;
478
479     my $gerrit_repo_basename = $GERRIT_REPOS{$repo_basename};
480     if ($gerrit_repo_basename) {
481         my $gerrit_repo_url;
482
483         # If given a username, make a "verbose" remote.
484         # Otherwise, rely on proper SSH configuration.
485         if ($self->{'codereview-username'}) {
486             $gerrit_repo_url = $GERRIT_SSH_BASE;
487             $gerrit_repo_url =~ s,\@USER\@,$self->{'codereview-username'}\@,;
488             $gerrit_repo_url =~ s,\@PORT\@,:29418,;
489         }
490         else {
491             $gerrit_repo_url = $GERRIT_SSH_BASE;
492             $gerrit_repo_url =~ s,\@[^\@]+\@,,g;
493         }
494
495         $gerrit_repo_url .= $gerrit_repo_basename;
496         $self->exe('git', 'config', 'remote.gerrit.url', $gerrit_repo_url);
497         $self->exe('git', 'config', 'remote.gerrit.fetch', '+refs/heads/*:refs/remotes/gerrit/*', '/heads/');
498     }
499
500     return;
501 }
502
503 sub git_clone_one_submodule
504 {
505     my ($self, $submodule, $url) = @_;
506
507     my $alternates            = $self->{ 'alternates'        };
508     my $mirror_url            = $self->{ 'mirror-url'        };
509     my $protocol              = $self->{ 'protocol'          };
510
511     # `--reference FOO' args for the clone, if any.
512     my @reference_args;
513
514     if ($alternates) {
515         # alternates is a qt5 repo, so the submodule will be under that.
516         if (-d "$alternates/$submodule") {
517             @reference_args = ('--reference', "$alternates/$submodule");
518         }
519         else {
520             print " *** $alternates/$submodule not found, ignoring alternate for this submodule\n";
521         }
522     }
523
524     my $mirror;
525     if ($mirror_url) {
526         $mirror = $mirror_url."qt/$submodule";
527         $mirror .= ".git" unless (-d $mirror); # Support local disk mirror
528     }
529
530     if ($mirror) {
531         # Only use the mirror if it can be reached.
532         eval { $self->exe('git', 'ls-remote', $mirror, 'test/if/mirror/exists') };
533         if ($@) {
534             warn "mirror [$mirror] is not accessible; $url will be used\n";
535             undef $mirror;
536         }
537     }
538
539     my $do_clone = (! -d "$submodule/.git");
540     if ($do_clone) {
541         $self->exe('git', 'clone', @reference_args, ($mirror ? $mirror : $url), $submodule);
542     }
543
544     chdir($submodule) or confess "chdir $submodule: $OS_ERROR";
545
546     $self->exe('git', 'config', 'remote.origin.url', $url);
547     if ($mirror) {
548         $self->exe('git', 'config', 'remote.mirror.url', $mirror);
549         $self->exe('git', 'config', 'remote.mirror.fetch', '+refs/heads/*:refs/remotes/mirror/*');
550     }
551
552     if (!$do_clone) {
553         $self->exe('git', 'fetch', ($mirror ? $mirror : $url));
554     }
555
556     my $template = getcwd()."/../.commit-template";
557     if (-e $template) {
558         $self->exe('git', 'config', 'commit.template', $template);
559     }
560
561     $self->git_add_remotes($submodule);
562
563     if ($self->{'detach-alternates'}) {
564         $self->exe('git', 'repack', '-a');
565
566         my $alternates_path = '.git/objects/info/alternates';
567         if (-e $alternates_path) {
568             unlink($alternates_path) || confess "unlink $alternates_path: $OS_ERROR";
569         }
570     }
571
572     chdir("..") or confess "cd ..: $OS_ERROR";
573
574     return;
575 }
576
577 sub run
578 {
579     my ($self) = @_;
580
581     $self->check_if_already_initialized;
582     $self->git_submodule_init;
583
584     if (!$self->{webkit}) {
585         $self->git_disable_webkit_submodule;
586     }
587
588     if ($self->{'module-subset'}) {
589         $self->git_prune_submodules;
590     }
591
592     $self->git_set_submodule_config;
593
594     $self->git_clone_all_submodules;
595
596     $self->git_add_remotes('qt5');
597
598     return;
599 }
600
601 #==============================================================================
602
603 Qt::InitRepository->new(@ARGV)->run if (!caller);
604 1;