File Coverage

File:Dpkg/Vendor.pm
Coverage:87.8%

linestmtbrancondsubpodtimecode
1# Copyright © 2008-2009 Raphaël Hertzog <hertzog@debian.org>
2# Copyright © 2008-2009, 2012-2017, 2022 Guillem Jover <guillem@debian.org>
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17package Dpkg::Vendor;
18
19
44
44
44
88
29
506
use strict;
20
44
44
44
66
28
755
use warnings;
21
44
44
44
67
31
2028
use feature qw(state);
22
23our $VERSION = '1.02';
24our @EXPORT_OK = qw(
25    get_current_vendor
26    get_vendor_info
27    get_vendor_file
28    get_vendor_dir
29    get_vendor_object
30    run_vendor_hook
31);
32
33
44
44
44
83
148
514
use Exporter qw(import);
34
44
44
44
79
29
1093
use List::Util qw(uniq);
35
36
44
44
44
200
17
276
use Dpkg ();
37
44
44
44
178
57
1120
use Dpkg::ErrorHandling;
38
44
44
44
76
18
834
use Dpkg::Gettext;
39
44
44
44
3089
32
622
use Dpkg::Build::Env;
40
44
44
44
6844
40
21398
use Dpkg::Control::HashCore;
41
42my $origins = "$Dpkg::CONFDIR/origins";
43$origins = $ENV{DPKG_ORIGINS_DIR} if $ENV{DPKG_ORIGINS_DIR};
44
45=encoding utf8
46
47 - 80
=head1 NAME

Dpkg::Vendor - get access to some vendor specific information

=head1 DESCRIPTION

The files in $Dpkg::CONFDIR/origins/ can provide information about various
vendors who are providing Debian packages. Currently those files look like
this:

  Vendor: Debian
  Vendor-URL: https://www.debian.org/
  Bugs: debbugs://bugs.debian.org

If the vendor derives from another vendor, the file should document
the relationship by listing the base distribution in the Parent field:

  Parent: Debian

The file should be named according to the vendor name. The usual convention
is to name the vendor file using the vendor name in all lowercase, but some
variation is permitted. Namely, spaces are mapped to dashes ('-'), and the
file can have the same casing as the Vendor field, or it can be capitalized.

=head1 FUNCTIONS

=over 4

=item $dir = get_vendor_dir()

Returns the current dpkg origins directory name, where the vendor files
are stored.

=cut
81
82sub get_vendor_dir {
83
1
1
3
    return $origins;
84}
85
86 - 94
=item $fields = get_vendor_info($name)

Returns a Dpkg::Control object with the information parsed from the
corresponding vendor file in $Dpkg::CONFDIR/origins/. If $name is omitted,
it will use $Dpkg::CONFDIR/origins/default which is supposed to be a symlink
to the vendor of the currently installed operating system. Returns undef
if there's no file for the given vendor.

=cut
95
96my $vendor_sep_regex = qr{[^A-Za-z0-9]+};
97
98sub get_vendor_info(;$) {
99
530
1
586
    my $vendor = shift || 'default';
100
530
749
    my $vendor_key = lc $vendor =~ s{$vendor_sep_regex}{}gr;
101
530
257
    state %VENDOR_CACHE;
102
530
532
    return $VENDOR_CACHE{$vendor_key} if exists $VENDOR_CACHE{$vendor_key};
103
104
22
22
    my $file = get_vendor_file($vendor);
105
22
20
    return unless $file;
106
22
38
    my $fields = Dpkg::Control::HashCore->new();
107
22
62
    $fields->load($file, compression => 0) or error(g_('%s is empty'), $file);
108
22
20
    $VENDOR_CACHE{$vendor_key} = $fields;
109
22
21
    return $fields;
110}
111
112 - 133
=item $name = get_vendor_file($name)

Check if there's a file for the given vendor and returns its
name.

The vendor filename will be derived from the vendor name, by replacing any
number of non-alphanumeric characters (that is B<[^A-Za-z0-9]>) into "B<->",
then the resulting name will be tried in sequence by lower-casing it,
keeping it as is, lower-casing then capitalizing it, and capitalizing it.

In addition, for historical and backwards compatibility, the name will
be tried keeping it as is without non-alphanumeric characters remapping,
then the resulting name will be tried in sequence by lower-casing it,
keeping it as is, lower-casing then capitalizing it, and capitalizing it.
And finally the name will be tried by replacing only spaces to "B<->",
then the resulting name will be tried in sequence by lower-casing it,
keeping it as is, lower-casing then capitalizing it, and capitalizing it.

But these backwards compatible name lookups will be removed during
the dpkg 1.22.x release cycle.

=cut
134
135sub get_vendor_file(;$) {
136
22
1
22
    my $vendor = shift || 'default';
137
138
22
10
    my @names;
139
22
24
    my $vendor_sep = $vendor =~ s{$vendor_sep_regex}{-}gr;
140
22
38
    push @names, lc $vendor_sep, $vendor_sep, ucfirst lc $vendor_sep, ucfirst $vendor_sep;
141
142    # XXX: Backwards compatibility, remove on 1.22.x.
143
22
88
21
83
    my %name_seen = map { $_ => 1 } @names;
144    my @obsolete_names = uniq grep {
145
22
88
53
57
        my $seen = exists $name_seen{$_};
146
88
45
        $name_seen{$_} = 1;
147
88
81
        not $seen;
148    } (
149        (lc $vendor, $vendor, ucfirst lc $vendor, ucfirst $vendor),
150        ($vendor =~ s{\s+}{-}g) ?
151        (lc $vendor, $vendor, ucfirst lc $vendor, ucfirst $vendor) : ()
152    );
153
22
0
40
0
    my %obsolete_name = map { $_ => 1 } @obsolete_names;
154
22
14
    push @names, @obsolete_names;
155
156
22
47
    foreach my $name (uniq @names) {
157
22
124
        next unless -e "$origins/$name";
158
22
21
        if (exists $obsolete_name{$name}) {
159
0
0
            warning(g_('%s origin filename is deprecated; ' .
160                       'it should have only alphanumeric or dash characters'),
161                    $name);
162        }
163
22
53
        return "$origins/$name";
164    }
165
0
0
    return;
166}
167
168 - 174
=item $name = get_current_vendor()

Returns the name of the current vendor. If DEB_VENDOR is set, it uses
that first, otherwise it falls back to parsing $Dpkg::CONFDIR/origins/default.
If that file doesn't exist, it returns undef.

=cut
175
176sub get_current_vendor() {
177
529
1
267
    my $f;
178
529
417
    if (Dpkg::Build::Env::has('DEB_VENDOR')) {
179
254
190
        $f = get_vendor_info(Dpkg::Build::Env::get('DEB_VENDOR'));
180
254
257
        return $f->{'Vendor'} if defined $f;
181    }
182
275
176
    $f = get_vendor_info();
183
275
339
    return $f->{'Vendor'} if defined $f;
184
0
0
    return;
185}
186
187 - 205
=item $object = get_vendor_object($name)

Return the Dpkg::Vendor::* object of the corresponding vendor.
If $name is omitted, return the object of the current vendor.
If no vendor can be identified, then return the Dpkg::Vendor::Default
object.

The module name will be derived from the vendor name, by splitting parts
around groups of non alphanumeric character (that is B<[^A-Za-z0-9]>)
separators, by either capitalizing or lower-casing and capitalizing each part
and then joining them without the separators. So the expected casing is based
on the one from the B<Vendor> field in the F<origins> file.

In addition, for historical and backwards compatibility, the module name
will also be looked up without non-alphanumeric character stripping, by
capitalizing, lower-casing then capitalizing, as-is or lower-casing.
But these name lookups will be removed during the 1.22.x release cycle.

=cut
206
207sub get_vendor_object {
208
527
1
602
    my $vendor = shift || get_current_vendor() || 'Default';
209
527
559
    my $vendor_key = lc $vendor =~ s{$vendor_sep_regex}{}gr;
210
527
262
    state %OBJECT_CACHE;
211
527
494
    return $OBJECT_CACHE{$vendor_key} if exists $OBJECT_CACHE{$vendor_key};
212
213
21
18
    my ($obj, @names);
214
215
21
31
    my @vendor_parts = split m{$vendor_sep_regex}, $vendor;
216
21
21
18
34
    push @names, join q{}, map { ucfirst } @vendor_parts;
217
21
21
14
21
    push @names, join q{}, map { ucfirst lc } @vendor_parts;
218
219    # XXX: Backwards compatibility, remove on 1.22.x.
220
21
42
17
47
    my %name_seen = map { $_ => 1 } @names;
221    my @obsolete_names = uniq grep {
222
21
84
24
46
        my $seen = exists $name_seen{$_};
223
84
54
        $name_seen{$_} = 1;
224
84
78
        not $seen;
225    } (ucfirst $vendor, ucfirst lc $vendor, $vendor, lc $vendor);
226
21
22
17
24
    my %obsolete_name = map { $_ => 1 } @obsolete_names;
227
21
22
    push @names, @obsolete_names;
228
229
21
33
    foreach my $name (uniq @names) {
230
24
1123
        eval qq{
231            pop \@INC if \$INC[-1] eq '.';
232            require Dpkg::Vendor::$name;
233            \$obj = Dpkg::Vendor::$name->new();
234        };
235
24
70
        unless ($@) {
236
20
24
            $OBJECT_CACHE{$vendor_key} = $obj;
237
20
25
            if (exists $obsolete_name{$name}) {
238
0
0
                warning(g_('%s module name is deprecated; ' .
239                           'it should be capitalized with only alphanumeric characters'),
240                        "Dpkg::Vendor::$name");
241            }
242
20
45
            return $obj;
243        }
244    }
245
246
1
2
    my $info = get_vendor_info($vendor);
247
1
3
    if (defined $info and defined $info->{'Parent'}) {
248
1
1
        return get_vendor_object($info->{'Parent'});
249    } else {
250
0
0
        return get_vendor_object('Default');
251    }
252}
253
254 - 258
=item run_vendor_hook($hookid, @params)

Run a hook implemented by the current vendor object.

=cut
259
260sub run_vendor_hook {
261
523
1
374
    my $vendor_obj = get_vendor_object();
262
523
518
    $vendor_obj->run_hook(@_);
263}
264
265=back
266
267 - 287
=head1 CHANGES

=head2 Version 1.02 (dpkg 1.21.10)

Deprecated behavior: get_vendor_file() loading vendor files with no special
characters remapping. get_vendor_object() loading vendor module names with
no special character stripping.

=head2 Version 1.01 (dpkg 1.17.0)

New function: get_vendor_dir().

=head2 Version 1.00 (dpkg 1.16.1)

Mark the module as public.

=head1 SEE ALSO

deb-origin(5).

=cut
288
2891;