Add qtwebengine 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 --force-hooks
74
75 Force initialization of hooks (even if there are already hooks in checked out
76 submodules).
77
78
79 =item --quiet, -q
80
81 Be quiet.  Will exit cleanly if the repository is already initialized.
82
83 =back
84
85
86 B<Module options:>
87
88 =over
89
90 =item --no-webkit
91
92 Skip webkit and webkit examples submodules.
93 It may be desirable to skip these modules due to the large size of the webkit
94 git repository.
95
96 =item --module-subset=<module1>,<module2>...
97
98 Only initialize the specified subset of modules given as the argument. Specified
99 modules must already exist in .gitmodules.
100 The string "all" results in cloning all known modules. The default is the set of
101 maintained modules.
102
103 =item --no-update
104
105 Skip the `git submodule update' command.
106
107
108 =item --ignore-submodules
109
110 Set git config to ignore submodules by default when doing operations on the
111 qt5 repo, such as `pull', `fetch', `diff' etc.
112
113 After using this option, pass `--ignore-submodules=none' to git to override
114 it as needed.
115
116 =back
117
118
119 B<Repository options:>
120
121 =over
122
123 =item --berlin
124
125 Switch to internal URLs and make use of the Berlin git mirrors.
126 (Implies `--mirror').
127
128 =item --oslo
129
130 Switch to internal URLs and make use of the Oslo git mirrors.
131 (Implies `--mirror').
132
133
134 =item --http
135
136 Use the HTTP protocol for git operations.  This may be useful if the git
137 protocol is blocked by a firewall.  Note that this only works with the
138 external Gitorious server.
139
140 The `--http' option does not affect the gerrit remotes.
141
142
143 =item --codereview-username <Gerrit/JIRA username>
144
145 Specify the user name for the (potentially) writable `gerrit' remote
146 for each module, for use with the Gerrit code review tool.
147
148 If this option is omitted, the gerrit remote is created without a username
149 and port number, and thus relies on a correct SSH configuration.
150
151
152 =item --alternates <path to other Qt5 repo>
153
154 Adds alternates for each submodule to another full qt5 checkout. This makes
155 this qt5 checkout very small, as it will use the object store of the
156 alternates before unique objects are stored in its own object store.
157
158 This option has no effect when using `--no-update'.
159
160 B<NOTE:> This will make this repo dependent on the alternate, which is
161 potentially dangerous!  The dependency can be broken by also using
162 the `--copy-objects' option, or by running C<git repack -a> in each
163 submodule, where required.  Please read the note about the `--shared' option
164 in the documentation of `git clone' for more information.
165
166
167 =item --copy-objects
168
169 When `--alternates' is used, automatically do a C<git repack -a> in each
170 submodule after cloning, to ensure that the repositories are independent
171 from the source used as a reference for cloning.
172
173 Note that this negates the disk usage benefits gained from the use of
174 `--alternates'.
175
176
177 =item --mirror <url-base>
178
179 Uses <url-base> as the base URL for submodule git mirrors.
180
181 For example:
182
183   --mirror user@machine:/foo/bar
184
185 ...will use the following as a mirror for qtbase:
186
187   user@machine:/foo/bar/qt/qtbase.git
188
189 The mirror is permitted to contain a subset of the submodules; any
190 missing modules will fall back to the canonical URLs.
191
192 =back
193
194 =cut
195
196 use Carp         qw( confess             );
197 use English      qw( -no_match_vars      );
198 use Getopt::Long qw( GetOptionsFromArray );
199 use Pod::Usage   qw( pod2usage           );
200 use Cwd          qw( getcwd              );
201
202 my %PROTOCOLS = (
203     'http'      => 'http://git.gitorious.org/'     ,
204 );
205
206 my %GERRIT_REPOS = map { $_ => "qt/$_" } qw(
207     qt3d
208     qt5
209     qtactiveqt
210     qtandroidextras
211     qtbase
212     qtconnectivity
213     qtdeclarative
214     qtdoc
215     qtdocgallery
216     qtenginio
217     qtfeedback
218     qtgraphicaleffects
219     qtimageformats
220     qtjsondb
221     qtlocation
222     qtmacextras
223     qtmultimedia
224     qtpim
225     qtqa
226     qtquick1
227     qtquickcontrols
228     qtrepotools
229     qtscript
230     qtsensors
231     qtserialport
232     qtsvg
233     qtsystems
234     qttools
235     qttranslations
236     qtwayland
237     qtwebchannel
238     qtwebengine
239     qtwebkit
240     qtwebkit-examples
241     qtwebsockets
242     qtwinextras
243     qtx11extras
244     qtxmlpatterns
245 );
246
247 my @DEFAULT_REPOS = qw(
248     qtactiveqt
249     qtandroidextras
250     qtbase
251     qtconnectivity
252     qtdeclarative
253     qtdoc
254     qtenginio
255     qtgraphicaleffects
256     qtimageformats
257     qtmacextras
258     qtmultimedia
259     qtqa
260     qtquick1
261     qtquickcontrols
262     qtlocation
263     qtrepotools
264     qtscript
265     qtsensors
266     qtserialport
267     qtsvg
268     qttools
269     qttranslations
270     qtwayland
271     qtwebchannel
272     qtwebengine
273     qtwebsockets
274     qtwebkit
275     qtwebkit-examples
276     qtwinextras
277     qtx11extras
278     qtxmlpatterns
279 );
280
281 my $GERRIT_SSH_BASE
282     = 'ssh://@USER@codereview.qt-project.org@PORT@/';
283
284 my $BER_MIRROR_URL_BASE
285     = 'git://hegel/';
286
287 my $OSLO_MIRROR_URL_BASE
288     = 'git://qilin/';
289
290 sub new
291 {
292     my ($class, @arguments) = @_;
293
294     my $self = {};
295     bless $self, $class;
296     $self->parse_arguments(@arguments);
297
298     return $self;
299 }
300
301 # Like `system', but possibly log the command, and die on non-zero exit code
302 sub exe
303 {
304     my ($self, @cmd) = @_;
305
306     if (!$self->{quiet}) {
307         print "+ @cmd\n";
308     }
309
310     if (system(@cmd) != 0) {
311         confess "@cmd exited with status $CHILD_ERROR";
312     }
313
314     return;
315 }
316
317 sub parse_arguments
318 {
319     my ($self, @args) = @_;
320
321     %{$self} = (%{$self},
322         'alternates'          => "",
323         'codereview-username' => "",
324         'detach-alternates'   => 0 ,
325         'force'               => 0 ,
326         'force-hooks'         => 0 ,
327         'ignore-submodules'   => 0 ,
328         'mirror-url'          => "",
329         'protocol'            => "",
330         'update'              => 1 ,
331         'webkit'              => 1 ,
332         'module-subset'       => join(",", @DEFAULT_REPOS),
333     );
334
335     GetOptionsFromArray(\@args,
336         'alternates=s'      =>  \$self->{qw{ alternates        }},
337         'codereview-username=s' => \$self->{qw{ codereview-username }},
338         'copy-objects'      =>  \$self->{qw{ detach-alternates }},
339         'force|f'           =>  \$self->{qw{ force             }},
340         'force-hooks'       =>  \$self->{qw{ force-hooks       }},
341         'ignore-submodules' =>  \$self->{qw{ ignore-submodules }},
342         'mirror=s'          =>  \$self->{qw{ mirror-url        }},
343         'quiet'             =>  \$self->{qw{ quiet             }},
344         'update!'           =>  \$self->{qw{ update            }},
345         'webkit!'           =>  \$self->{qw{ webkit            }},
346         'module-subset=s'   =>  \$self->{qw{ module-subset     }},
347
348         'help|?'            =>  sub { pod2usage(1);               },
349         'http'              =>  sub { $self->{protocol} = 'http'; },
350
351         'berlin' => sub {
352             $self->{'mirror-url'}        = $BER_MIRROR_URL_BASE;
353         },
354         'oslo' => sub {
355             $self->{'mirror-url'}        = $OSLO_MIRROR_URL_BASE;
356         },
357     ) || pod2usage(2);
358
359     # Replace any double trailing slashes from end of mirror
360     $self->{'mirror-url'} =~ s{//+$}{/};
361
362     if ($self->{'module-subset'} eq "all") {
363         $self->{'module-subset'} = "";
364     } else {
365         $self->{'module-subset'} = {
366             map { $_ => 1 } split(qr{,}, $self->{'module-subset'})
367         };
368     }
369
370     return;
371 }
372
373 sub check_if_already_initialized
374 {
375     my ($self) = @_;
376
377     # We consider the repo as `initialized' if submodule.qtbase.url is set
378     if (qx(git config --get submodule.qtbase.url)) {
379         if ($self->{force}) {
380             my @configresult = qx(git config -l);
381             foreach (@configresult) {
382                 # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
383                 if (/(submodule\.[^.=]+)\.url=.*/) {
384                     $self->exe('git', 'config', '--remove-section', $1);
385                 }
386             }
387         }
388         else {
389             exit 0 if ($self->{quiet});
390             print "Will not reinitialize already initialized repository (use -f to force)!\n";
391             exit 1;
392         }
393     }
394
395     return;
396 }
397
398 sub git_submodule_init
399 {
400     my ($self) = @_;
401
402     my @init_args;
403     if ($self->{quiet}) {
404         push @init_args, '--quiet';
405     }
406     $self->exe('git', 'submodule', 'init', @init_args);
407
408     my $template = getcwd()."/.commit-template";
409     if (-e $template) {
410         $self->exe('git', 'config', 'commit.template', $template);
411     }
412
413     return;
414 }
415
416 sub git_disable_webkit_submodule
417 {
418     my ($self) = @_;
419
420     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit');
421     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit-examples');
422
423     return;
424 }
425
426 sub git_prune_submodules
427 {
428     my ($self) = @_;
429
430     my @configresult = qx(git config -l);
431     foreach my $line (@configresult) {
432         if ($line =~ /submodule\.([^.=]+)\.url=/) {
433             my $module_name = $1;
434             if (!$self->{'module-subset'}{$module_name}) {
435                 $self->exe('git', 'config', '--remove', "submodule.$module_name");
436             }
437         }
438     }
439 }
440
441 sub git_set_submodule_config
442 {
443     my ($self) = @_;
444
445     my @configresult          = qx(git config -l);
446     my $protocol              = $self->{protocol};
447     my $url_base_for_protocol = $PROTOCOLS{$protocol};
448
449     foreach my $line (@configresult) {
450         # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
451         next if ($line !~ /submodule\.([^.=]+)\.url=(.*)/);
452
453         my $key   = $1;
454         my $value = $2;
455
456         if ($protocol) {
457                 # rewrite URL to chosen protocol
458                 $value =~ s,^git://gitorious\.org/,$url_base_for_protocol,;
459         }
460
461         $self->exe('git', 'config', "submodule.$key.url", $value);
462
463         if ($self->{'ignore-submodules'}) {
464             $self->exe('git', 'config', "submodule.$key.ignore", 'all');
465         }
466     }
467
468     return;
469 }
470
471 sub git_clone_all_submodules
472 {
473     my ($self) = @_;
474
475     # manually clone each repo here, so we can easily use reference repos, mirrors etc
476     my @configresult = qx(git config -l);
477     foreach my $line (@configresult) {
478         if ($line =~ /submodule\.([^.=]+)\.url=(.*)/) {
479             $self->git_clone_one_submodule($1, $2);
480             if ($1 eq "qtwebengine") {
481                 $self->exe('git', 'submodule', 'update', $1);
482                 my $orig_cwd = getcwd();
483                 chdir($1) or confess "chdir $1: $OS_ERROR";
484                 $self->exe('git', 'submodule', 'init');
485                 $self->git_clone_all_submodules;
486                 chdir("$orig_cwd") or confess "chdir $orig_cwd: $OS_ERROR";
487             }
488         }
489     }
490
491     if ($self->{update}) {
492         $self->exe('git', 'submodule', 'update', '--recursive');
493     }
494
495     return;
496 }
497
498 sub git_add_remotes
499 {
500     my ($self, $repo_basename) = @_;
501
502     my $gerrit_repo_basename = $GERRIT_REPOS{$repo_basename};
503     if ($gerrit_repo_basename) {
504         my $gerrit_repo_url;
505
506         # If given a username, make a "verbose" remote.
507         # Otherwise, rely on proper SSH configuration.
508         if ($self->{'codereview-username'}) {
509             $gerrit_repo_url = $GERRIT_SSH_BASE;
510             $gerrit_repo_url =~ s,\@USER\@,$self->{'codereview-username'}\@,;
511             $gerrit_repo_url =~ s,\@PORT\@,:29418,;
512         }
513         else {
514             $gerrit_repo_url = $GERRIT_SSH_BASE;
515             $gerrit_repo_url =~ s,\@[^\@]+\@,,g;
516         }
517
518         $gerrit_repo_url .= $gerrit_repo_basename;
519         $self->exe('git', 'config', 'remote.gerrit.url', $gerrit_repo_url);
520         $self->exe('git', 'config', 'remote.gerrit.fetch', '+refs/heads/*:refs/remotes/gerrit/*', '/heads/');
521     }
522
523     return;
524 }
525
526 sub git_clone_one_submodule
527 {
528     my ($self, $submodule, $url) = @_;
529
530     my $alternates            = $self->{ 'alternates'        };
531     my $mirror_url            = $self->{ 'mirror-url'        };
532     my $protocol              = $self->{ 'protocol'          };
533
534     # `--reference FOO' args for the clone, if any.
535     my @reference_args;
536
537     if ($alternates) {
538         # alternates is a qt5 repo, so the submodule will be under that.
539         if (-d "$alternates/$submodule") {
540             @reference_args = ('--reference', "$alternates/$submodule");
541         }
542         else {
543             print " *** $alternates/$submodule not found, ignoring alternate for this submodule\n";
544         }
545     }
546
547     my $mirror;
548     if ($mirror_url and $url =~ /\/(qt\/[^.]+)\.git/) {
549         $mirror = $mirror_url.$1;
550         $mirror .= ".git" unless (-d $mirror); # Support local disk mirror
551     }
552
553     if ($mirror) {
554         # Only use the mirror if it can be reached.
555         eval { $self->exe('git', 'ls-remote', $mirror, 'test/if/mirror/exists') };
556         if ($@) {
557             warn "mirror [$mirror] is not accessible; $url will be used\n";
558             undef $mirror;
559         }
560     }
561
562     my $do_clone = (! -d "$submodule/.git");
563     if ($do_clone) {
564         $self->exe('git', 'clone', @reference_args, ($mirror ? $mirror : $url), $submodule);
565     }
566
567     my $orig_cwd = getcwd();
568     chdir($submodule) or confess "chdir $submodule: $OS_ERROR";
569
570     $self->exe('git', 'config', 'remote.origin.url', $url);
571     if ($mirror) {
572         $self->exe('git', 'config', 'remote.mirror.url', $mirror);
573         $self->exe('git', 'config', 'remote.mirror.fetch', '+refs/heads/*:refs/remotes/mirror/*');
574     }
575
576     if (!$do_clone) {
577         $self->exe('git', 'fetch', ($mirror ? $mirror : $url));
578     }
579
580     my $template = getcwd()."/../.commit-template";
581     if (-e $template) {
582         $self->exe('git', 'config', 'commit.template', $template);
583     }
584
585     $self->git_add_remotes($submodule);
586
587     if ($self->{'detach-alternates'}) {
588         $self->exe('git', 'repack', '-a');
589
590         my $alternates_path = '.git/objects/info/alternates';
591         if (-e $alternates_path) {
592             unlink($alternates_path) || confess "unlink $alternates_path: $OS_ERROR";
593         }
594     }
595
596     chdir($orig_cwd) or confess "cd $orig_cwd: $OS_ERROR";
597
598     return;
599 }
600
601 sub ensure_link
602 {
603     my ($self, $src, $tgt) = @_;
604     return if (!$self->{'force-hooks'} and -f $tgt);
605     unlink($tgt); # In case we have a dead symlink or pre-existing hook
606     print "Aliasing $src\n      as $tgt ...\n" if (!$self->{quiet});
607     return if eval { symlink($src, $tgt) };
608     # Windows doesn't do (proper) symlinks. As the post_commit script needs
609     # them to locate itself, we write a forwarding script instead.
610     open SCRIPT, ">".$tgt or die "Cannot create forwarding script $tgt: $!\n";
611     print SCRIPT "#!/bin/sh\nexec `dirname \$0`/$src \"\$\@\"\n";
612     close SCRIPT;
613 }
614
615 sub git_install_hooks
616 {
617     my ($self) = @_;
618
619     return if (!-d 'qtrepotools/git-hooks');
620
621     chomp(my @modules = `git submodule foreach :`);
622     push @modules, "";
623     for my $module (@modules) {
624         $module =~ s,^Entering \'([^\']+)\'$,$1/,;
625         my $rel = $module;
626         $rel =~ s,[^/]+,..,g;
627         $rel .= "../../qtrepotools/git-hooks/";
628         $self->ensure_link($rel.'gerrit_commit_msg_hook', $module.'.git/hooks/commit-msg');
629         $self->ensure_link($rel.'git_post_commit_hook', $module.'.git/hooks/post-commit');
630     }
631 }
632
633 sub run
634 {
635     my ($self) = @_;
636
637     $self->check_if_already_initialized;
638     $self->git_submodule_init;
639
640     if (!$self->{webkit}) {
641         $self->git_disable_webkit_submodule;
642     }
643
644     if ($self->{'module-subset'}) {
645         $self->git_prune_submodules;
646     }
647
648     $self->git_set_submodule_config;
649
650     $self->git_clone_all_submodules;
651
652     $self->git_add_remotes('qt5');
653
654     $self->git_install_hooks;
655
656     return;
657 }
658
659 #==============================================================================
660
661 Qt::InitRepository->new(@ARGV)->run if (!caller);
662 1;