source: ProjectBuilder/devel/pb/lib/ProjectBuilder/Filter.pm@ 2263

Last change on this file since 2263 was 2263, checked in by Bruno Cornec, 7 years ago

Fix the merge of YAML conf files in pb_conf_cache
(Up to 3 levels of keys for now)

File size: 9.4 KB
Line 
1#!/usr/bin/perl -w
2#
3# ProjectBuilder Filter module
4# Filtering subroutines brought by the the Project-Builder project
5# which can be easily used by pbinit
6#
7# $Id$
8#
9# Copyright B. Cornec 2007-2016
10# Eric Anderson's changes are (c) Copyright 2012 Hewlett Packard
11# Provided under the GPL v2
12
13package ProjectBuilder::Filter;
14
15use strict 'vars';
16use Data::Dumper;
17use English;
18use File::Basename;
19use File::Copy;
20use lib qw (lib);
21use ProjectBuilder::Version;
22use ProjectBuilder::Base;
23use ProjectBuilder::Conf;
24use ProjectBuilder::Distribution;
25use ProjectBuilder::Changelog;
26use ProjectBuilder::VCS;
27
28# Inherit from the "Exporter" module which handles exporting functions.
29
30use vars qw($VERSION $REVISION @ISA @EXPORT);
31use Exporter;
32
33# Export, by default, all the functions into the namespace of
34# any code which uses this module.
35
36our @ISA = qw(Exporter);
37our @EXPORT = qw(pb_get_filters pb_filter_file_pb pb_filter_file_inplace pb_filter_file pb_filter_var_print);
38($VERSION,$REVISION) = pb_version_init();
39
40=pod
41
42=head1 NAME
43
44ProjectBuilder::Filter, part of the project-builder.org
45
46=head1 DESCRIPTION
47
48This module provides filtering functions suitable for pbinit calls.
49
50=over 4
51
52=item B<pb_get_filters>
53
54This function gets all filters to apply. They're cumulative from the less specific to the most specific.
55
56Suffix of those filters is .yml. Filter all.yml applies to whatever distribution. The pbfilter directory may be global under pbconf or per package, for overloading values. Then in order filters are loaded for distribution type, distribution family, distribution name, distribution name-version.
57
58The first parameter is the package name.
59The second parameter is OS hash
60
61The function returns a pointer on a hash of filters.
62
63=cut
64
65sub pb_get_filters {
66
67my @ffiles;
68my @ffilestoconvert;
69my $pbpkg = shift || die "No package specified";
70my $pbos = shift;
71my $ptr = undef; # returned value pointer on the hash of filters
72my $lh;
73
74pb_log(2,"Entering pb_get_filters - pbpkg: $pbpkg - pbos: ".Dumper($pbos)."\n");
75
76# Global filter files first, then package specific
77my @file_basenames = ('all');
78@file_basenames = reverse pb_distro_to_keylist($pbos, 'all') if (defined $pbos);
79# Build list of all filter files
80foreach my $dir ("$ENV{PBROOTDIR}/pbfilter", "$ENV{PBROOTDIR}/$pbpkg/pbfilter") {
81 foreach my $file_basename (@file_basenames) {
82 my $path = "$dir/${file_basename}.yml";
83 if (-f $path) {
84 push(@ffiles, $path);
85 } else {
86 my $path2 = "$dir/${file_basename}.pbf";
87 push(@ffilestoconvert, $path2) if (-f $path2);
88 }
89 }
90}
91
92# Convert all old filter files into new ones
93if (@ffilestoconvert) {
94 foreach my $f (@ffilestoconvert) {
95 my $fyml = $f;
96 $fyml =~ s/\.pbf/.yml/;
97 pb_conf_update_v0($f,$fyml);
98 my ($pburl) = pb_conf_get("pburl");
99 my ($scheme, $account, $host, $port, $path) = pb_get_uri($pburl->{$ENV{'PBPROJ'}});
100 pb_vcs_add_if_not_in($scheme,$fyml);
101 push(@ffiles, $fyml);
102 }
103}
104
105if (@ffiles) {
106 pb_log(2,"DEBUG ffiles: ".Dumper(\@ffiles)."\n");
107
108 foreach my $f (@ffiles) {
109 pb_log(3,"DEBUG processing filter file $f\n");
110 $lh = pb_conf_cache($f,$lh);
111 pb_log(2, "filter hash is:\n".Dumper($lh)."\n");
112 }
113 $ptr = $lh->{"filter"};
114
115 # TODO: find a place to document it. Why not in this file as pod and also documenting filters ?
116 # Handle transform
117 if (defined $lh->{transform}) {
118 while (my ($out_key,$spec) = each %{$lh->{transform}}) {
119 die "Unknown transform for $out_key '$spec' expected <out-key> <transform>" unless $spec =~ /^([\w\-]+)\s+(.+)$/;
120 my ($in_key, $expr) = ($1, $2);
121 local $_ = $ptr->{$in_key} || '';
122 eval $expr;
123 die "Error evaluating tranform for $out_key ($expr): $@" if $@;
124 $ptr->{$out_key} = $_;
125 pb_log(2, "Transform $in_key to $out_key\n$ptr->{$in_key}\n$ptr->{$out_key}\n");
126 }
127 }
128}
129pb_log(2,"DEBUG f:".Dumper($ptr)."\n") if (defined $ptr);
130return($ptr);
131}
132
133=item B<pb_filter_file>
134
135This function applies all filters to files.
136
137It takes 4 parameters.
138
139The first parameter is the file to filter.
140The second parameter is the pointer on the hash of filters. If undefined no filtering will occur.
141The third parameter is the destination file after filtering.
142The fourth parameter is the pointer on the hash of variables to filter (tag, ver, ...)
143
144=cut
145
146sub pb_filter_file {
147
148my $f=shift;
149my $ptr=shift;
150my %filter;
151if (defined $ptr) {
152 %filter=%$ptr;
153} else {
154 %filter = ();
155}
156my $destfile=shift;
157my $pb=shift;
158my $tuple = "unknown";
159$tuple = "$pb->{'pbos'}->{'name'}-$pb->{'pbos'}->{'version'}-$pb->{'pbos'}->{'arch'}" if (defined $pb->{'pbos'});
160
161pb_log(2,"DEBUG: From $f to $destfile (tuple: $tuple)\n");
162pb_log(3,"DEBUG($tuple): pb ".Dumper($pb)."\n");
163pb_mkdir_p(dirname($destfile)) if (! -d dirname($destfile));
164open(DEST,"> $destfile") || die "Unable to create $destfile: $!";
165open(FILE,"$f") || die "Unable to open $f: $!";
166while (<FILE>) {
167 my $line = $_;
168 foreach my $s (keys %filter) {
169 # Process single variables
170 my $tmp = $filter{$s};
171 next if (not defined $tmp);
172 pb_log(3,"DEBUG filter{$s}: $filter{$s}\n");
173 # Expand variables if any single one found
174 if ($tmp =~ /\$/) {
175 pb_log(3,"*** Filtering variable in $tmp ***\n");
176 # Order is important as we need to handle hashes refs before simple vars
177 # (?: introduce a Non-capturing groupings cf man perlretut
178 # We need to avoid handling other VARs (Makefile e.g) so restrict here to $pb type of vars.
179 eval { $tmp =~ s/(\$\w+(?:-\>\{\'\w+\'\})*)/$1/eeg };
180 if (($s =~ /^PBDESC$/) && ($line =~ /^ PBDESC/)) {
181 # if on debian, we need to preserve the space before each desc line
182 pb_log(3,"*** DEBIAN CASE ADDING SPACE ***\n");
183 $tmp =~ s/\$\//\$\/ /g;
184 pb_log(3,"*** tmp:$tmp ***\n");
185 }
186 # Support $/ vars
187 eval { $tmp =~ s/(\$\/)/$1/eeg };
188 } elsif (($s =~ /^PBLOG$/) && ($line =~ /^PBLOG$/)) {
189 # special case for ChangeLog only for pb
190 pb_log(3,"DEBUG filtering PBLOG\n");
191 pb_changelog($pb, \*DEST, $tmp);
192 $tmp = "";
193 } elsif (($s =~ /^PBPATCHSRC$/) && ($line =~ /^PBPATCHSRC$/)) {
194 pb_log(3,"DEBUG($tuple) filtering PBPATCHSRC\n");
195 my $i = 0;
196 pb_log(3,"DEBUG($tuple): pb ".Dumper($pb)."\n");
197 pb_log(3,"DEBUG($tuple): pb/patches/tuple $pb->{'patches'}->{$tuple}\n");
198 if (defined $pb->{'patches'}->{$tuple}) {
199 foreach my $p (split(/,/,$pb->{'patches'}->{$tuple})) {
200 pb_log(3,"DEBUG($tuple) Adding patch $i ".basename($p)."\n");
201 print DEST "Patch$i: ".basename($p).".gz\n";
202 $i++;
203 }
204 }
205 $tmp = "";
206 } elsif (($s =~ /^PBMULTISRC$/) && ($line =~ /^PBMULTISRC$/)) {
207 pb_log(3,"DEBUG($tuple) filtering PBMULTISRC\n");
208 my $i = 1;
209 if (defined $pb->{'sources'}->{$tuple}) {
210 foreach my $p (split(/,/,$pb->{'sources'}->{$tuple})) {
211 pb_log(3,"DEBUG($tuple) Adding source $i ".basename($p)."\n");
212 print DEST "Source$i: ".basename($p)."\n";
213 $i++;
214 }
215 }
216 $tmp = "";
217 } elsif (($s =~ /^PBPATCHCMD$/) && ($line =~ /^PBPATCHCMD$/)) {
218 pb_log(3,"DEBUG($tuple) filtering PBPATCHCMD\n");
219 my $i = 0;
220 if (defined $pb->{'patches'}->{$tuple}) {
221 my ($patchcmd,$patchopt) = pb_distro_get_param($pb->{'pbos'},pb_conf_get_if("ospatchcmd","ospatchopt"));
222 foreach my $p (split(/,/,$pb->{'patches'}->{$tuple})) {
223 pb_log(3,"DEBUG($tuple) Adding patch command $i ($patchopt)\n");
224 print DEST "%patch$i $patchopt\n";
225 $i++;
226 }
227 }
228 print DEST "\n";
229 $tmp = "";
230 }
231 $line =~ s|$s|$tmp|g;
232 }
233 print DEST $line;
234}
235close(FILE);
236close(DEST);
237}
238
239=item B<pb_filter_file_inplace>
240
241This function applies all filters to a file in place.
242
243It takes 3 parameters.
244
245The first parameter is the pointer on the hash of filters.
246The second parameter is the destination file after filtering.
247The third parameter is the pointer on the hash of variables to filter (tag, ver, ...)
248
249=cut
250
251# Function which applies filter on files (external call)
252sub pb_filter_file_inplace {
253
254my $ptr=shift;
255my $destfile=shift;
256my $pb=shift;
257
258my $cp = "$ENV{'PBTMP'}/".basename($destfile).".$$";
259copy($destfile,$cp) || die "Unable to copy $destfile to $cp";
260
261pb_filter_file($cp,$ptr,$destfile,$pb);
262unlink $cp;
263}
264
265
266=item B<pb_filter_var_print>
267
268This function prints every variable expanded in order to help debug stacking issues with conf files. If a VM/VE/RM is given restrict display to this distribution. If parameters are passed, restrict again the display to that package only.
269
270=cut
271
272sub pb_filter_var_print {
273
274my $pbos = shift;
275my @keys = @_;
276my $ptr = undef;
277
278if ($#keys == -1) {
279 pb_log(0,"Full pb variables for project $ENV{'PBPROJ'}\n");
280 pb_log(0,"============================================\n");
281}
282if (defined $ENV{'PBV'}) {
283 pb_log(0,"Distribution $ENV{'PBV'}\n");
284 pb_log(0,"========================\n");
285} else {
286 pb_log(0,"Local Distribution\n");
287 pb_log(0,"==================\n");
288}
289
290foreach my $k (@keys) {
291 $ptr = pb_get_filters($k,$pbos);
292 pb_log(0,"Package $k\n");
293 pb_log(0,"==================\n");
294 foreach my $f (sort keys %$ptr) {
295 pb_log(0,"Filter $f => $ptr->{$f}\n");
296 }
297 pb_log(0,"==================\n");
298}
299}
300
301
302=back
303
304=head1 WEB SITES
305
306The main Web site of the project is available at L<http://www.project-builder.org/>. Bug reports should be filled using the trac instance of the project at L<http://trac.project-builder.org/>.
307
308=head1 USER MAILING LIST
309
310None exists for the moment.
311
312=head1 AUTHORS
313
314The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
315
316=head1 COPYRIGHT
317
318Project-Builder.org is distributed under the GPL v2.0 license
319described in the file C<COPYING> included with the distribution.
320
321=cut
322
3231;
Note: See TracBrowser for help on using the repository browser.