Add qtwebsockets 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     qtwebsockets
235     qtwinextras
236     qtx11extras
237     qtxmlpatterns
238 );
239
240 my @DEFAULT_REPOS = qw(
241     qtactiveqt
242     qtandroidextras
243     qtbase
244     qtconnectivity
245     qtdeclarative
246     qtdoc
247     qtgraphicaleffects
248     qtimageformats
249     qtmacextras
250     qtmultimedia
251     qtqa
252     qtquick1
253     qtquickcontrols
254     qtlocation
255     qtrepotools
256     qtscript
257     qtsensors
258     qtserialport
259     qtsvg
260     qttools
261     qttranslations
262     qtwebsockets
263     qtwebkit
264     qtwebkit-examples
265     qtwinextras
266     qtx11extras
267     qtxmlpatterns
268 );
269
270 my $GERRIT_SSH_BASE
271     = 'ssh://@USER@codereview.qt-project.org@PORT@/';
272
273 my $BER_MIRROR_URL_BASE
274     = 'git://hegel/';
275
276 my $OSLO_MIRROR_URL_BASE
277     = 'git://qilin/';
278
279 sub new
280 {
281     my ($class, @arguments) = @_;
282
283     my $self = {};
284     bless $self, $class;
285     $self->parse_arguments(@arguments);
286
287     return $self;
288 }
289
290 # Like `system', but possibly log the command, and die on non-zero exit code
291 sub exe
292 {
293     my ($self, @cmd) = @_;
294
295     if (!$self->{quiet}) {
296         print "+ @cmd\n";
297     }
298
299     if (system(@cmd) != 0) {
300         confess "@cmd exited with status $CHILD_ERROR";
301     }
302
303     return;
304 }
305
306 sub parse_arguments
307 {
308     my ($self, @args) = @_;
309
310     %{$self} = (%{$self},
311         'alternates'          => "",
312         'codereview-username' => "",
313         'detach-alternates'   => 0 ,
314         'force'               => 0 ,
315         'ignore-submodules'   => 0 ,
316         'mirror-url'          => "",
317         'protocol'            => "",
318         'update'              => 1 ,
319         'webkit'              => 1 ,
320         'module-subset'       => join(",", @DEFAULT_REPOS),
321     );
322
323     GetOptionsFromArray(\@args,
324         'alternates=s'      =>  \$self->{qw{ alternates        }},
325         'codereview-username=s' => \$self->{qw{ codereview-username }},
326         'copy-objects'      =>  \$self->{qw{ detach-alternates }},
327         'force'             =>  \$self->{qw{ force             }},
328         'ignore-submodules' =>  \$self->{qw{ ignore-submodules }},
329         'mirror=s'          =>  \$self->{qw{ mirror-url        }},
330         'quiet'             =>  \$self->{qw{ quiet             }},
331         'update!'           =>  \$self->{qw{ update            }},
332         'webkit!'           =>  \$self->{qw{ webkit            }},
333         'module-subset=s'   =>  \$self->{qw{ module-subset     }},
334
335         'help|?'            =>  sub { pod2usage(1);               },
336         'http'              =>  sub { $self->{protocol} = 'http'; },
337
338         'berlin' => sub {
339             $self->{'mirror-url'}        = $BER_MIRROR_URL_BASE;
340         },
341         'oslo' => sub {
342             $self->{'mirror-url'}        = $OSLO_MIRROR_URL_BASE;
343         },
344     ) || pod2usage(2);
345
346     # Replace any double trailing slashes from end of mirror
347     $self->{'mirror-url'} =~ s{//+$}{/};
348
349     if ($self->{'module-subset'} eq "all") {
350         $self->{'module-subset'} = "";
351     } else {
352         $self->{'module-subset'} = {
353             map { $_ => 1 } split(qr{,}, $self->{'module-subset'})
354         };
355     }
356
357     return;
358 }
359
360 sub check_if_already_initialized
361 {
362     my ($self) = @_;
363
364     # We consider the repo as `initialized' if submodule.qtbase.url is set
365     if (qx(git config --get submodule.qtbase.url)) {
366         if ($self->{force}) {
367             my @configresult = qx(git config -l);
368             foreach (@configresult) {
369                 # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
370                 if (/(submodule\.[^.=]+)\.url=.*/) {
371                     $self->exe('git', 'config', '--remove-section', $1);
372                 }
373             }
374         }
375         else {
376             exit 0 if ($self->{quiet});
377             print "Will not reinitialize already initialized repository (use -f to force)!\n";
378             exit 1;
379         }
380     }
381
382     return;
383 }
384
385 sub git_submodule_init
386 {
387     my ($self) = @_;
388
389     my @init_args;
390     if ($self->{quiet}) {
391         push @init_args, '--quiet';
392     }
393     $self->exe('git', 'submodule', 'init', @init_args);
394
395     my $template = getcwd()."/.commit-template";
396     if (-e $template) {
397         $self->exe('git', 'config', 'commit.template', $template);
398     }
399
400     return;
401 }
402
403 sub git_disable_webkit_submodule
404 {
405     my ($self) = @_;
406
407     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit');
408     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit-examples');
409
410     return;
411 }
412
413 sub git_prune_submodules
414 {
415     my ($self) = @_;
416
417     my @configresult = qx(git config -l);
418     foreach my $line (@configresult) {
419         if ($line =~ /submodule\.([^.=]+)\.url=/) {
420             my $module_name = $1;
421             if (!$self->{'module-subset'}{$module_name}) {
422                 $self->exe('git', 'config', '--remove', "submodule.$module_name");
423             }
424         }
425     }
426 }
427
428 sub git_set_submodule_config
429 {
430     my ($self) = @_;
431
432     my @configresult          = qx(git config -l);
433     my $protocol              = $self->{protocol};
434     my $url_base_for_protocol = $PROTOCOLS{$protocol};
435
436     foreach my $line (@configresult) {
437         # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
438         next if ($line !~ /submodule\.([^.=]+)\.url=(.*)/);
439
440         my $key   = $1;
441         my $value = $2;
442
443         if ($protocol) {
444                 # rewrite URL to chosen protocol
445                 $value =~ s,^git://gitorious\.org/,$url_base_for_protocol,;
446         }
447
448         $self->exe('git', 'config', "submodule.$key.url", $value);
449
450         if ($self->{'ignore-submodules'}) {
451             $self->exe('git', 'config', "submodule.$key.ignore", 'all');
452         }
453     }
454
455     return;
456 }
457
458 sub git_clone_all_submodules
459 {
460     my ($self) = @_;
461
462     # manually clone each repo here, so we can easily use reference repos, mirrors etc
463     my @configresult = qx(git config -l);
464     foreach my $line (@configresult) {
465         if ($line =~ /submodule\.([^.=]+)\.url=(.*)/) {
466             $self->git_clone_one_submodule($1, $2);
467         }
468     }
469
470     if ($self->{update}) {
471         $self->exe('git', 'submodule', 'update', '--recursive');
472     }
473
474     return;
475 }
476
477 sub git_add_remotes
478 {
479     my ($self, $repo_basename) = @_;
480
481     my $gerrit_repo_basename = $GERRIT_REPOS{$repo_basename};
482     if ($gerrit_repo_basename) {
483         my $gerrit_repo_url;
484
485         # If given a username, make a "verbose" remote.
486         # Otherwise, rely on proper SSH configuration.
487         if ($self->{'codereview-username'}) {
488             $gerrit_repo_url = $GERRIT_SSH_BASE;
489             $gerrit_repo_url =~ s,\@USER\@,$self->{'codereview-username'}\@,;
490             $gerrit_repo_url =~ s,\@PORT\@,:29418,;
491         }
492         else {
493             $gerrit_repo_url = $GERRIT_SSH_BASE;
494             $gerrit_repo_url =~ s,\@[^\@]+\@,,g;
495         }
496
497         $gerrit_repo_url .= $gerrit_repo_basename;
498         $self->exe('git', 'config', 'remote.gerrit.url', $gerrit_repo_url);
499         $self->exe('git', 'config', 'remote.gerrit.fetch', '+refs/heads/*:refs/remotes/gerrit/*', '/heads/');
500     }
501
502     return;
503 }
504
505 sub git_clone_one_submodule
506 {
507     my ($self, $submodule, $url) = @_;
508
509     my $alternates            = $self->{ 'alternates'        };
510     my $mirror_url            = $self->{ 'mirror-url'        };
511     my $protocol              = $self->{ 'protocol'          };
512
513     # `--reference FOO' args for the clone, if any.
514     my @reference_args;
515
516     if ($alternates) {
517         # alternates is a qt5 repo, so the submodule will be under that.
518         if (-d "$alternates/$submodule") {
519             @reference_args = ('--reference', "$alternates/$submodule");
520         }
521         else {
522             print " *** $alternates/$submodule not found, ignoring alternate for this submodule\n";
523         }
524     }
525
526     my $mirror;
527     if ($mirror_url) {
528         $mirror = $mirror_url."qt/$submodule";
529         $mirror .= ".git" unless (-d $mirror); # Support local disk mirror
530     }
531
532     if ($mirror) {
533         # Only use the mirror if it can be reached.
534         eval { $self->exe('git', 'ls-remote', $mirror, 'test/if/mirror/exists') };
535         if ($@) {
536             warn "mirror [$mirror] is not accessible; $url will be used\n";
537             undef $mirror;
538         }
539     }
540
541     my $do_clone = (! -d "$submodule/.git");
542     if ($do_clone) {
543         $self->exe('git', 'clone', @reference_args, ($mirror ? $mirror : $url), $submodule);
544     }
545
546     chdir($submodule) or confess "chdir $submodule: $OS_ERROR";
547
548     $self->exe('git', 'config', 'remote.origin.url', $url);
549     if ($mirror) {
550         $self->exe('git', 'config', 'remote.mirror.url', $mirror);
551         $self->exe('git', 'config', 'remote.mirror.fetch', '+refs/heads/*:refs/remotes/mirror/*');
552     }
553
554     if (!$do_clone) {
555         $self->exe('git', 'fetch', ($mirror ? $mirror : $url));
556     }
557
558     my $template = getcwd()."/../.commit-template";
559     if (-e $template) {
560         $self->exe('git', 'config', 'commit.template', $template);
561     }
562
563     $self->git_add_remotes($submodule);
564
565     if ($self->{'detach-alternates'}) {
566         $self->exe('git', 'repack', '-a');
567
568         my $alternates_path = '.git/objects/info/alternates';
569         if (-e $alternates_path) {
570             unlink($alternates_path) || confess "unlink $alternates_path: $OS_ERROR";
571         }
572     }
573
574     chdir("..") or confess "cd ..: $OS_ERROR";
575
576     return;
577 }
578
579 sub run
580 {
581     my ($self) = @_;
582
583     $self->check_if_already_initialized;
584     $self->git_submodule_init;
585
586     if (!$self->{webkit}) {
587         $self->git_disable_webkit_submodule;
588     }
589
590     if ($self->{'module-subset'}) {
591         $self->git_prune_submodules;
592     }
593
594     $self->git_set_submodule_config;
595
596     $self->git_clone_all_submodules;
597
598     $self->git_add_remotes('qt5');
599
600     return;
601 }
602
603 #==============================================================================
604
605 Qt::InitRepository->new(@ARGV)->run if (!caller);
606 1;