~shnatsel/+junk/pkg-kde-tools-backport

« back to all changes in this revision

Viewing changes to qt-kde-team/3/dhmk.pl

  • Committer: Sergey "Shnatsel" Davidoff
  • Date: 2016-04-18 20:56:33 UTC
  • Revision ID: shnatsel@gmail.com-20160418205633-i7sh6o3o6yzm410a
Initial import of version 0.15.16ubuntu2 from vivid

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/perl
 
2
 
 
3
# Copyright (C) 2011 Modestas Vainius <modax@debian.org>
 
4
#
 
5
# This program is free software: you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License as published by
 
7
# the Free Software Foundation, either version 3 of the License, or
 
8
# (at your option) any later version.
 
9
#
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>
 
17
 
 
18
use strict;
 
19
use warnings;
 
20
 
 
21
package Debian::PkgKde::Dhmk::DhCompat;
 
22
 
 
23
my $targets;
 
24
my %extra_cmd_opts;
 
25
 
 
26
sub _find_cmd_and_do {
 
27
    # &$proc($cmd_array_ref, $cmd_index_ref)
 
28
    my ($proc, $command) = @_;
 
29
    foreach my $tname (keys %$targets) {
 
30
        my $tcmds = $targets->{$tname}{cmds};
 
31
        for (my $i = 0; $i < @$tcmds; $i++) {
 
32
            if (!defined($command) || $tcmds->[$i] eq $command) {
 
33
                &$proc($tcmds, \$i);
 
34
            }
 
35
        }
 
36
    }
 
37
}
 
38
 
 
39
sub _escape_shell {
 
40
    my @opts = @_;
 
41
    s/'/'"'"'/g foreach @opts;
 
42
    if (wantarray) {
 
43
        return map({ "'$_'" } @opts);
 
44
    } else {
 
45
        return "'" . join("' '", @opts) . "'";
 
46
    }
 
47
}
 
48
 
 
49
############### Dh Addon API ############################
 
50
 
 
51
# Insert $new_command in sequences before $existing_command
 
52
sub insert_before {
 
53
    my ($existing_command, $new_command) = @_;
 
54
    return _find_cmd_and_do(sub {
 
55
            my ($cmds, $i) = ($_[0], ${$_[1]});
 
56
            if ($i == 0) {
 
57
                unshift @$cmds, $new_command;
 
58
            } else {
 
59
                my @tail = splice(@$cmds, $i);
 
60
                push @$cmds, $new_command, @tail;
 
61
            }
 
62
            ${$_[1]}++;
 
63
        }, $existing_command);
 
64
}
 
65
 
 
66
# Insert $new_command in sequences after $existing_command
 
67
sub insert_after {
 
68
    my ($existing_command, $new_command) = @_;
 
69
    return _find_cmd_and_do(sub {
 
70
            my ($cmds, $i) = ($_[0], ${$_[1]});
 
71
            my @tail = ($i < $#{$cmds}) ? splice(@$cmds, $i+1) : ();
 
72
#            print $#_, join("--", @tail), "\n";
 
73
            push @$cmds, $new_command, @tail;
 
74
            ${$_[1]}++;
 
75
        }, $existing_command);
 
76
}
 
77
 
 
78
# Remove $existing_command from the list of commands to run in all sequences.
 
79
sub remove_command {
 
80
    my ($existing_command) = @_;
 
81
    return _find_cmd_and_do(sub {
 
82
            my ($cmds, $i) = ($_[0], ${$_[1]});
 
83
            splice(@$cmds, $i, 1);
 
84
            ${$_[1]}--;
 
85
        }, $existing_command);
 
86
}
 
87
 
 
88
# Add $new_command to the beginning of the specified sequence. If the sequence
 
89
# does not exist, it will be created.
 
90
sub add_command {
 
91
    my ($new_command, $sequence) = @_;
 
92
    if (exists $targets->{$sequence}) {
 
93
        unshift @{$targets->{$sequence}{cmds}}, $new_command;
 
94
    } else {
 
95
        $targets->{$sequence} = { cmds => [ $new_command ], deps => "" };
 
96
    }
 
97
}
 
98
 
 
99
# Append $opt1, $opt2 etc. to the list of additional options which dh passes
 
100
# when running the specified $command.
 
101
sub add_command_options {
 
102
    my ($command, @opts) = @_;
 
103
    push @{$extra_cmd_opts{$command}}, @opts;
 
104
}
 
105
 
 
106
# Remove @opts from the list of additional options which dh passes when running
 
107
# the specified $command. If @opts is empty, remove all extra options
 
108
sub remove_command_options {
 
109
    my ($command, @opts) = @_;
 
110
    if (exists $extra_cmd_opts{$command}) {
 
111
        if (!@opts) {
 
112
            delete $extra_cmd_opts{$command};
 
113
        } else {
 
114
            my $re = "(" . join("|", map {"\Q$_\E"} @opts) . ")";
 
115
            $extra_cmd_opts{$command} = [ grep { !/^$re$/ } @{$extra_cmd_opts{$command}} ];
 
116
        }
 
117
    }
 
118
}
 
119
 
 
120
########### Main module subroutines ###################
 
121
 
 
122
# Initialize jail
 
123
sub init {
 
124
    my %opts = @_;
 
125
    $targets = $opts{targets};
 
126
}
 
127
 
 
128
# Load addons
 
129
sub load_addons {
 
130
    my @addons = @_;
 
131
    my %env_changes;
 
132
 
 
133
    # Backup current environment in order to export changes which addons have
 
134
    # made to it
 
135
    my %oldenv = %ENV;
 
136
 
 
137
    foreach my $addon (@addons) {
 
138
        my $mod="Debian::Debhelper::Sequence::$addon";
 
139
        $mod=~s/-/_/g;
 
140
        eval "use $mod";
 
141
        if ($@) {
 
142
            die "unable to load addon $addon: $@";
 
143
        }
 
144
    }
 
145
 
 
146
    # Compare environment and note changes
 
147
    foreach my $e (keys %ENV) {
 
148
        if (!exists $oldenv{$e} || (($ENV{$e} || "") ne ($oldenv{$e} || "")))
 
149
        {
 
150
            $env_changes{$e} = { old => $oldenv{$e}, new => $ENV{$e} };
 
151
        }
 
152
    }
 
153
 
 
154
    # Merge $extra_cmd_opts to $targets
 
155
    foreach my $c (keys %extra_cmd_opts) {
 
156
        next if !@{$extra_cmd_opts{$c}};
 
157
        _find_cmd_and_do(sub {
 
158
                my ($cmds, $i) = ($_[0], ${$_[1]});
 
159
                $cmds->[$i] .= " " . _escape_shell(@{$extra_cmd_opts{$c}});
 
160
            }, $c);
 
161
    }
 
162
 
 
163
    return \%env_changes;
 
164
}
 
165
 
 
166
# Generate extra options from command line options
 
167
sub gen_extraopts {
 
168
    my @opts;
 
169
    # Convert "--option value" syntax to --option=value like dh(1) would do
 
170
    foreach my $opt (@_) {
 
171
        if ($opt =~ /^-/) {
 
172
            push @opts, $opt;
 
173
        } elsif (@opts && $opts[$#opts] =~ /^--/) {
 
174
            $opts[$#opts] .= "=" . $opt;
 
175
        } else {
 
176
            push @opts, $opt;
 
177
        }
 
178
    }
 
179
    return join(" ", map({ s/^'-/-O'-/; $_ } _escape_shell(@opts)));
 
180
}
 
181
 
 
182
1;
 
183
 
 
184
package main;
 
185
 
 
186
sub basename {
 
187
    my ($filename) = @_;
 
188
    $filename =~ s,^.*/([^/]+)/*$,$1,;
 
189
    return $filename;
 
190
}
 
191
 
 
192
sub dirname {
 
193
    my ($filename) = @_;
 
194
    $filename =~ s,[^/]+/*$,,;
 
195
    return $filename;
 
196
}
 
197
 
 
198
sub parse_commands_file {
 
199
    my ($filename) = @_;
 
200
    my %targets;
 
201
    my $t;
 
202
 
 
203
    open (my $fh, "<", $filename) or
 
204
        die "unable to open dhmk commands file $filename: $!";
 
205
 
 
206
    # File format is:
 
207
    # target:
 
208
    #   command1
 
209
    #   command2
 
210
    #   command3
 
211
    #   ...
 
212
    # Use $targetname in place of a command to insert commands from the
 
213
    # previously defined target.
 
214
    while (my $line = <$fh>) {
 
215
        chop $line;
 
216
        if ($line =~ /^\s*#/ || $line =~ /^\s*$/) {
 
217
            next; # comment or empty line
 
218
        } elsif ($line =~ /^(\S.+):\s*(.*)$/) {
 
219
            $t = $1;
 
220
            $targets{$t}{deps} = $2 || "";
 
221
            $targets{$t}{cmds} = [];
 
222
        } elsif (defined $t) {
 
223
            if ($line =~ /^\s+(.*)$/) {
 
224
                my $c = $1;
 
225
                # If it's a variable, dereference it
 
226
                if ($c =~ /^\s*\$(\S+)\s*$/) {
 
227
                    if (exists $targets{$1}) {
 
228
                        push @{$targets{$t}{cmds}}, @{$targets{$1}{cmds}};
 
229
                    } else {
 
230
                        die "could not dereference variable \$$1. Target '$1' was not defined yet";
 
231
                    }
 
232
                } else {
 
233
                    push @{$targets{$t}{cmds}}, $c;
 
234
                }
 
235
            } else {
 
236
                die "dangling command '$line'. Missing target definition";
 
237
            }
 
238
        } else {
 
239
            die "invalid commands file syntax";
 
240
        }
 
241
    }
 
242
    close($fh);
 
243
 
 
244
    return \%targets;
 
245
}
 
246
 
 
247
sub parse_cmdline {
 
248
    my @addons;
 
249
    my @extraopts;
 
250
    my $optname = "";
 
251
    my $optval;
 
252
    my $opts_need_values = qr/with(?:out)?/;
 
253
    my $opts_no_values = qr//;
 
254
    foreach my $arg (@ARGV) {
 
255
        if ($optname eq "--") {
 
256
            $optval = $arg;
 
257
        } elsif ($optname && !defined $optval) {
 
258
            $optval = $arg;
 
259
        } elsif ($arg eq "--") {
 
260
            $optname = "--";
 
261
            $optval = undef;
 
262
        } elsif ($arg =~ /^--($opts_need_values)=(.*)$/) {
 
263
            $optname = $1;
 
264
            $optval = $2 || "";
 
265
        } elsif ($arg =~ /^--($opts_need_values)$/) {
 
266
            $optname = $1;
 
267
            $optval = undef;
 
268
        } elsif ($arg =~ /^--($opts_no_values)=(.*)$/) {
 
269
            die "option $1 does not accept a value";
 
270
        } elsif ($arg =~ /^--($opts_no_values)$/) {
 
271
            $optname = $1;
 
272
            $optval = "";
 
273
        } else {
 
274
            $optval = $arg;
 
275
        }
 
276
        if (defined $optval) {
 
277
            if ($optname eq "" || $optname eq "--") {
 
278
                push @extraopts, $optval;
 
279
                # Do not reset $optname
 
280
            } else {
 
281
                if ($optname =~ /^$opts_need_values$/) {
 
282
                    if ($optval eq "") {
 
283
                        die "option $optname requires a value";
 
284
                    }
 
285
                    if ($optname eq "with") {
 
286
                        push @addons, split(/,/, $optval);
 
287
                    } elsif ($optname eq "without") {
 
288
                        @addons = grep { $_ ne $optval } @addons;
 
289
                    } else {
 
290
                        die "internal bug: unrecognized dhmk.pl option: $optname (val: $optval)";
 
291
                    }
 
292
                } elsif ($optname =~ /^$opts_no_values$/) {
 
293
                    # No such options exist yet
 
294
                } else {
 
295
                    die "unrecognized command line option: $optname";
 
296
                }
 
297
                $optname = "";
 
298
                $optval = undef;
 
299
            }
 
300
        }
 
301
    }
 
302
 
 
303
    return ( addons => \@addons, extraopts => \@extraopts );
 
304
}
 
305
 
 
306
sub get_commands {
 
307
    my ($targets) = @_;
 
308
    my %cmds;
 
309
    foreach my $t (values %$targets) {
 
310
        foreach my $c (@{$t->{cmds}}) {
 
311
            $cmds{$1} = 1 if $c =~ /^(\S+)/;
 
312
        }
 
313
    }
 
314
    return sort keys %cmds;
 
315
}
 
316
 
 
317
sub get_override_info {
 
318
    my ($rules_file, @commands) = @_;
 
319
    my $magic = "##dhmk_no_override##";
 
320
 
 
321
    # Initialize all overrides first
 
322
    my %overrides;
 
323
    my @override_targets;
 
324
    foreach my $c (@commands) {
 
325
        $overrides{$c} = 1;
 
326
        push @override_targets, "override_$c";
 
327
    }
 
328
 
 
329
    # Now remove overrides based on the rules file output
 
330
    my $saved_makeflags = $ENV{MAKEFLAGS};
 
331
    delete $ENV{MAKEFLAGS};
 
332
    open(my $make, "-|", "make", "-f", $rules_file, "-j1", "-n",
 
333
        "--no-print-directory",
 
334
        @override_targets,
 
335
        "dhmk_override_info_mode=yes") or
 
336
        die "unable to execute make for override calculation: $!";
 
337
    while (my $line = <$make>) {
 
338
        if ($line =~ /^$magic(.*)$/ && exists $overrides{$1}) {
 
339
            delete $overrides{$1};
 
340
        }
 
341
    }
 
342
    if (!close($make)) {
 
343
        die "make (get_override_info) failed with $?";
 
344
    }
 
345
    $ENV{MAKEFLAGS} = $saved_makeflags if defined $saved_makeflags;
 
346
 
 
347
    return \%overrides;
 
348
}
 
349
 
 
350
sub write_definevar {
 
351
    my ($fh, $name, $value, $escape) = @_;
 
352
    $escape = 1 if !defined $escape;
 
353
 
 
354
    if ($value) {
 
355
        $value =~ s/\$/\$\$/g if $escape;
 
356
        print $fh "define $name", "\n", $value, "\n", "endef", "\n";
 
357
    } else {
 
358
        print $fh "$name =", "\n";
 
359
    }
 
360
}
 
361
 
 
362
sub write_exportvar {
 
363
    my ($fh, $name,$export) = @_;
 
364
    $export = "export" if !defined $export;
 
365
    print $fh "$export $name", "\n";
 
366
}
 
367
 
 
368
sub write_dhmk_rules {
 
369
    my ($dhmk_file, $rules_file, $targets, $overrides,
 
370
        $extraopts, $env_changes) = @_;
 
371
 
 
372
    open (my $fh, ">", $dhmk_file) or
 
373
        die "unable to open dhmk rules file ($dhmk_file) for writing: $!";
 
374
    print $fh "# This file was automatically generated by ", basename($0), "\n";
 
375
    print $fh "# DO NOT edit as your changes will eventually be lost.", "\n";
 
376
    print $fh "# DO NOT include this file in the source package.", "\n";
 
377
    print $fh "\n";
 
378
    print $fh "# Action command sequences", "\n";
 
379
    foreach my $tname (keys %$targets) {
 
380
        my $t = $targets->{$tname};
 
381
        my @commands;
 
382
        foreach my $cline (@{$t->{cmds}}) {
 
383
            my $c = ($cline =~ /^(\S+)/) && $1;
 
384
            push @commands, $c;
 
385
            print $fh $tname, "_", $c, " = ", $cline, "\n";
 
386
        }
 
387
        print $fh "dhmk_", $tname, "_commands = ", join(" ", @commands), "\n";
 
388
        print $fh "dhmk_", $tname, "_depends = ", $t->{deps}, "\n";
 
389
        print $fh "\n";
 
390
    }
 
391
 
 
392
    print $fh "# Overrides", "\n";
 
393
    foreach my $o (sort keys %$overrides) {
 
394
        print $fh "dhmk_override_", $o, " = yes", "\n";
 
395
    }
 
396
    print $fh "\n";
 
397
 
 
398
    # Export specified extra options for debhelper programs (e.g. for use in
 
399
    # overrides)
 
400
    if ($extraopts) {
 
401
        print $fh "# Export specified extra options for debhelper programs", "\n";
 
402
        write_definevar($fh, "DHMK_OPTIONS", $extraopts, 0);
 
403
        write_exportvar($fh, "DHMK_OPTIONS");
 
404
        print $fh "\n";
 
405
    }
 
406
 
 
407
    if (keys %$env_changes) {
 
408
        print $fh "# Export environment changes", "\n";
 
409
        foreach my $e (keys %$env_changes) {
 
410
            print $fh "dhmk_envvar_orig_$e := \$($e)\n";
 
411
            if (defined ($env_changes->{$e}{new})) {
 
412
                write_definevar($fh, $e, $env_changes->{$e}{new});
 
413
            } else {
 
414
                write_export($fh, $e, "unexport");
 
415
            }
 
416
        }
 
417
        # Restore all modified environment variables when remaking $dhmk_file
 
418
        foreach my $e (keys %$env_changes) {
 
419
            print $fh "$dhmk_file: $e = \$(dhmk_envvar_orig_$e)", "\n";
 
420
        }
 
421
        print $fh "\n";
 
422
    }
 
423
 
 
424
    close($fh);
 
425
}
 
426
 
 
427
my $COMMANDS_FILE = dirname($0) . "/commands";
 
428
my $DHMK_RULES_FILE = "debian/dhmk_rules.mk";
 
429
my $RULES_FILE = "debian/rules";
 
430
 
 
431
eval {
 
432
    my $targets = parse_commands_file($COMMANDS_FILE);
 
433
    my %cmdopts = parse_cmdline();
 
434
    my $shextraopts;
 
435
    my $env_changes;
 
436
 
 
437
    Debian::PkgKde::Dhmk::DhCompat::init(targets => $targets);
 
438
    if (@{$cmdopts{addons}}) {
 
439
        $env_changes = Debian::PkgKde::Dhmk::DhCompat::load_addons(@{$cmdopts{addons}});
 
440
        if (!$env_changes) {
 
441
            die "unable to load requested dh addons: " . join(", ", @{$cmdopts{addons}});
 
442
        }
 
443
    }
 
444
    if (@{$cmdopts{extraopts}}) {
 
445
        $shextraopts = Debian::PkgKde::Dhmk::DhCompat::gen_extraopts(@{$cmdopts{extraopts}});
 
446
    }
 
447
    my $overrides = get_override_info($RULES_FILE, get_commands($targets));
 
448
    write_dhmk_rules($DHMK_RULES_FILE, $RULES_FILE, $targets, $overrides,
 
449
        $shextraopts, $env_changes);
 
450
};
 
451
if ($@) {
 
452
    die "error: $@"
 
453
}