Add qtmacextras and qtwinextras to qt5.git#stable
[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 This option is default for --nokia-developer.
108
109 After using this option, pass `--ignore-submodules=none' to git to override
110 it as needed.
111
112 =back
113
114
115 B<Repository options:>
116
117 =over
118
119 =item --nokia-developer
120
121 Switch to internal Nokia URLs.
122
123
124 =item --berlin
125
126 Switch to internal Nokia URLs and make use of the Berlin git mirrors.
127 (Implies `--mirror').
128
129
130 =item --ssh
131
132 Use the SSH protocol for git operations.  This may be useful if the git
133 protocol is blocked by a firewall. Note that this requires a user account
134 with an uploaded SSH key on all servers used.  (Implies `--nokia-developer').
135
136 The `--ssh' option does not affect the gerrit remotes.
137
138
139 =item --http
140
141 Use the HTTP protocol for git operations.  This may be useful if the git
142 protocol is blocked by a firewall.  Note that this only works with the
143 external Gitorious server.
144
145 The `--http' option does not affect the gerrit remotes.
146
147
148 =item --codereview-username <Gerrit/JIRA username>
149
150 Specify the user name for the (potentially) writable `gerrit' remote
151 for each module, for use with the Gerrit code review tool.
152
153 If this option is omitted, the gerrit remote is created without a username
154 and port number, and thus relies on a correct SSH configuration.
155
156
157 =item --alternates <path to other Qt5 repo>
158
159 Adds alternates for each submodule to another full qt5 checkout. This makes
160 this qt5 checkout very small, as it will use the object store of the
161 alternates before unique objects are stored in its own object store.
162
163 This option has no effect when using `--no-update'.
164
165 B<NOTE:> This will make this repo dependent on the alternate, which is
166 potentially dangerous!  The dependency can be broken by also using
167 the `--copy-objects' option, or by running C<git repack -a> in each
168 submodule, where required.  Please read the note about the `--shared' option
169 in the documentation of `git clone' for more information.
170
171
172 =item --copy-objects
173
174 When `--alternates' is used, automatically do a C<git repack -a> in each
175 submodule after cloning, to ensure that the repositories are independent
176 from the source used as a reference for cloning.
177
178 Note that this negates the disk usage benefits gained from the use of
179 `--alternates'.
180
181
182 =item --mirror <url-base>
183
184 Uses <url-base> as the base URL for submodule git mirrors.
185
186 For example:
187
188   --mirror user@machine:/foo/bar
189
190 ...will use the following as a mirror for qtbase:
191
192   user@machine:/foo/bar/qt/qtbase.git
193
194 The mirror is permitted to contain a subset of the submodules; any
195 missing modules will fall back to the canonical URLs.
196
197 =back
198
199 =cut
200
201 use Carp         qw( confess             );
202 use English      qw( -no_match_vars      );
203 use Getopt::Long qw( GetOptionsFromArray );
204 use Pod::Usage   qw( pod2usage           );
205 use Cwd          qw( getcwd              );
206
207 my %PROTOCOLS = (
208     'internal'  => 'git://scm.dev.nokia.troll.no/' ,
209     'ssh'       => 'git@scm.dev.nokia.troll.no:'   ,
210     'http'      => 'http://git.gitorious.org/'     ,
211 );
212
213 my %GERRIT_REPOS = map { $_ => "qt/$_" } qw(
214     qt3d
215     qt5
216     qlalr
217     qtactiveqt
218     qtbase
219     qtconnectivity
220     qtdeclarative
221     qtdoc
222     qtdocgallery
223     qtfeedback
224     qtgraphicaleffects
225     qtimageformats
226     qtjsondb
227     qtjsbackend
228     qtlocation
229     qtmacextras
230     qtmultimedia
231     qtpim
232     qtqa
233     qtquick1
234     qtquickcontrols
235     qtrepotools
236     qtscript
237     qtsensors
238     qtserialport
239     qtsvg
240     qtsystems
241     qttools
242     qttranslations
243     qtwayland
244     qtwebkit
245     qtwebkit-examples
246     qtwinextras
247     qtx11extras
248     qtxmlpatterns
249 );
250
251 my @DEFAULT_REPOS = qw(
252     qtactiveqt
253     qtbase
254     qtdeclarative
255     qtdoc
256     qtgraphicaleffects
257     qtimageformats
258     qtjsbackend
259     qtmultimedia
260     qtqa
261     qtquick1
262     qtquickcontrols
263     qtrepotools
264     qtscript
265     qtsensors
266     qtserialport
267     qtsvg
268     qttools
269     qttranslations
270     qtwebkit
271     qtwebkit-examples
272     qtx11extras
273     qtxmlpatterns
274 );
275
276 my $GERRIT_SSH_BASE
277     = 'ssh://@USER@codereview.qt-project.org@PORT@/';
278
279 my $BER_MIRROR_URL_BASE
280     = 'git://hegel/';
281
282 sub new
283 {
284     my ($class, @arguments) = @_;
285
286     my $self = {};
287     bless $self, $class;
288     $self->parse_arguments(@arguments);
289
290     return $self;
291 }
292
293 # Like `system', but possibly log the command, and die on non-zero exit code
294 sub exe
295 {
296     my ($self, @cmd) = @_;
297
298     if (!$self->{quiet}) {
299         print "+ @cmd\n";
300     }
301
302     if (system(@cmd) != 0) {
303         confess "@cmd exited with status $CHILD_ERROR";
304     }
305
306     return;
307 }
308
309 sub parse_arguments
310 {
311     my ($self, @args) = @_;
312
313     %{$self} = (%{$self},
314         'alternates'          => "",
315         'codereview-username' => "",
316         'detach-alternates'   => 0 ,
317         'force'               => 0 ,
318         'ignore-submodules'   => 0 ,
319         'mirror-url'          => "",
320         'nokia-developer'     => 0 ,
321         'protocol'            => "",
322         'update'              => 1 ,
323         'webkit'              => 1 ,
324         'module-subset'       => join(",", @DEFAULT_REPOS),
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=s'          =>  \$self->{qw{ mirror-url        }},
334         'nokia-developer'   =>  \$self->{qw{ nokia-developer   }},
335         'quiet'             =>  \$self->{qw{ quiet             }},
336         'update!'           =>  \$self->{qw{ update            }},
337         'webkit!'           =>  \$self->{qw{ webkit            }},
338         'module-subset=s'   =>  \$self->{qw{ module-subset     }},
339
340         'help|?'            =>  sub { pod2usage(1);               },
341         'http'              =>  sub { $self->{protocol} = 'http'; },
342         'ssh|ssh-protocol'  =>  sub { $self->{protocol} = 'ssh';  },
343
344         'berlin|berlin-nokia-developer' => sub {
345             $self->{'nokia-developer'}   = 1;
346             $self->{'protocol'}          = 'internal';
347             $self->{'mirror-url'}        = $BER_MIRROR_URL_BASE;
348         },
349
350         'nokia-developer' => sub {
351             $self->{'nokia-developer'}   = 1;
352             $self->{'protocol'}          = 'internal';
353             $self->{'ignore-submodules'} = 1;
354         },
355     ) || pod2usage(2);
356
357     if ($self->{'nokia-developer'} && $self->{'protocol'} eq 'http') {
358         print "*** Ignoring use of HTTP protocol, as it's only usable with external server\n";
359         $self->{'protocol'} = '';
360     }
361
362     # Replace any double trailing slashes from end of mirror
363     $self->{'mirror-url'} =~ s{//+$}{/};
364
365     if ($self->{'module-subset'} eq "all") {
366         $self->{'module-subset'} = "";
367     } else {
368         $self->{'module-subset'} = {
369             map { $_ => 1 } split(qr{,}, $self->{'module-subset'})
370         };
371     }
372
373     return;
374 }
375
376 sub check_if_already_initialized
377 {
378     my ($self) = @_;
379
380     # We consider the repo as `initialized' if submodule.qtbase.url is set
381     if (qx(git config --get submodule.qtbase.url)) {
382         if ($self->{force}) {
383             my @configresult = qx(git config -l);
384             foreach (@configresult) {
385                 # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
386                 if (/(submodule\.[^.=]+)\.url=.*/) {
387                     $self->exe('git', 'config', '--remove-section', $1);
388                 }
389             }
390         }
391         else {
392             exit 0 if ($self->{quiet});
393             print "Will not reinitialize already initialized repository (use -f to force)!\n";
394             exit 1;
395         }
396     }
397
398     return;
399 }
400
401 sub git_submodule_init
402 {
403     my ($self) = @_;
404
405     my @init_args;
406     if ($self->{quiet}) {
407         push @init_args, '--quiet';
408     }
409     $self->exe('git', 'submodule', 'init', @init_args);
410
411     my $template = getcwd()."/.commit-template";
412     if (-e $template) {
413         $self->exe('git', 'config', 'commit.template', $template);
414     }
415
416     return;
417 }
418
419 sub git_disable_webkit_submodule
420 {
421     my ($self) = @_;
422
423     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit');
424     $self->exe('git', 'config', '--remove', 'submodule.qtwebkit-examples');
425
426     return;
427 }
428
429 sub git_prune_submodules
430 {
431     my ($self) = @_;
432
433     my @configresult = qx(git config -l);
434     foreach my $line (@configresult) {
435         if ($line =~ /submodule\.([^.=]+)\.url=/) {
436             my $module_name = $1;
437             if (!$self->{'module-subset'}{$module_name}) {
438                 $self->exe('git', 'config', '--remove', "submodule.$module_name");
439             }
440         }
441     }
442 }
443
444 sub git_set_submodule_config
445 {
446     my ($self) = @_;
447
448     my @configresult          = qx(git config -l);
449     my $protocol              = $self->{protocol};
450     my $url_base_for_protocol = $PROTOCOLS{$protocol};
451
452     foreach my $line (@configresult) {
453         # Example line: submodule.qtqa.url=git://gitorious.org/qt/qtqa.git
454         next if ($line !~ /submodule\.([^.=]+)\.url=(.*)/);
455
456         my $key   = $1;
457         my $value = $2;
458
459         if ($protocol) {
460                 # qt-labs projects are still hosted under qt internally.
461                 if ($protocol ne 'http') {
462                     $value =~ s,^git://gitorious\.org/qt-labs/,${url_base_for_protocol}qt/,;
463                 }
464
465                 # assume all other projects hosted under gitorious publicly.
466                 $value =~ s,^git://gitorious\.org/,$url_base_for_protocol,;
467         }
468
469         $self->exe('git', 'config', "submodule.$key.url", $value);
470
471         if ($self->{'ignore-submodules'}) {
472             $self->exe('git', 'config', "submodule.$key.ignore", 'all');
473         }
474     }
475
476     return;
477 }
478
479 sub git_clone_all_submodules
480 {
481     my ($self) = @_;
482
483     # manually clone each repo here, so we can easily use reference repos, mirrors etc
484     my @configresult = qx(git config -l);
485     foreach my $line (@configresult) {
486         if ($line =~ /submodule\.([^.=]+)\.url=(.*)/) {
487             $self->git_clone_one_submodule($1, $2);
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) {
549         $mirror = $mirror_url."qt/$submodule";
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     chdir($submodule) or confess "chdir $submodule: $OS_ERROR";
568
569     $self->exe('git', 'config', 'remote.origin.url', $url);
570     if ($mirror) {
571         $self->exe('git', 'config', 'remote.mirror.url', $mirror);
572         $self->exe('git', 'config', 'remote.mirror.fetch', '+refs/heads/*:refs/remotes/mirror/*');
573     }
574
575     if (!$do_clone) {
576         $self->exe('git', 'fetch', ($mirror ? $mirror : $url));
577     }
578
579     my $template = getcwd()."/../.commit-template";
580     if (-e $template) {
581         $self->exe('git', 'config', 'commit.template', $template);
582     }
583
584     $self->git_add_remotes($submodule);
585
586     if ($self->{'detach-alternates'}) {
587         $self->exe('git', 'repack', '-a');
588
589         my $alternates_path = '.git/objects/info/alternates';
590         if (-e $alternates_path) {
591             unlink($alternates_path) || confess "unlink $alternates_path: $OS_ERROR";
592         }
593     }
594
595     chdir("..") or confess "cd ..: $OS_ERROR";
596
597     return;
598 }
599
600 sub run
601 {
602     my ($self) = @_;
603
604     $self->check_if_already_initialized;
605     $self->git_submodule_init;
606
607     if (!$self->{webkit}) {
608         $self->git_disable_webkit_submodule;
609     }
610
611     if ($self->{'module-subset'}) {
612         $self->git_prune_submodules;
613     }
614
615     $self->git_set_submodule_config;
616
617     $self->git_clone_all_submodules;
618
619     $self->git_add_remotes('qt5');
620
621     return;
622 }
623
624 #==============================================================================
625
626 Qt::InitRepository->new(@ARGV)->run if (!caller);
627 1;