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

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

More YAML transformations

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