OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | package metadata; |
2 | use base 'Exporter'; |
||
3 | use strict; |
||
4 | use warnings; |
||
5 | our @EXPORT = qw(%package %vpackage %srcpackage %category %overrides clear_packages parse_package_metadata parse_target_metadata get_multiline @ignore %usernames %groupnames); |
||
6 | |||
7 | our %package; |
||
8 | our %vpackage; |
||
9 | our %srcpackage; |
||
10 | our %category; |
||
11 | our %overrides; |
||
12 | our @ignore; |
||
13 | |||
14 | our %usernames; |
||
15 | our %groupnames; |
||
16 | our %userids; |
||
17 | our %groupids; |
||
18 | |||
19 | sub get_multiline { |
||
20 | my $fh = shift; |
||
21 | my $prefix = shift; |
||
22 | my $str; |
||
23 | while (<$fh>) { |
||
24 | last if /^@@/; |
||
25 | $str .= (($_ and $prefix) ? $prefix . $_ : $_); |
||
26 | } |
||
27 | |||
28 | return $str ? $str : ""; |
||
29 | } |
||
30 | |||
31 | sub confstr($) { |
||
32 | my $conf = shift; |
||
33 | $conf =~ tr#/\.\-/#___#; |
||
34 | return $conf; |
||
35 | } |
||
36 | |||
37 | sub parse_package_metadata_usergroup($$$$$) { |
||
38 | my $makefile = shift; |
||
39 | my $typename = shift; |
||
40 | my $names = shift; |
||
41 | my $ids = shift; |
||
42 | my $spec = shift; |
||
43 | my $name; |
||
44 | my $id; |
||
45 | |||
46 | # the regex for name is taken from is_valid_name() of package shadow |
||
47 | if ($spec =~ /^([a-z_][a-z0-9_-]*\$?)$/) { |
||
48 | $name = $spec; |
||
49 | $id = -1; |
||
50 | } elsif ($spec =~ /^([a-z_][a-z0-9_-]*\$?)=(\d+)$/) { |
||
51 | $name = $1; |
||
52 | $id = $2; |
||
53 | } else { |
||
54 | warn "$makefile: invalid $typename spec $spec\n"; |
||
55 | return 0; |
||
56 | } |
||
57 | |||
58 | if ($id =~ /^[1-9]\d*$/) { |
||
59 | if ($id >= 65536) { |
||
60 | warn "$makefile: $typename $name id $id >= 65536"; |
||
61 | return 0; |
||
62 | } |
||
63 | if (not exists $ids->{$id}) { |
||
64 | $ids->{$id} = { |
||
65 | name => $name, |
||
66 | makefile => $makefile, |
||
67 | }; |
||
68 | } elsif ($ids->{$id}{name} ne $name) { |
||
69 | warn "$makefile: $typename $name id $id is already taken by $ids->{$id}{makefile}\n"; |
||
70 | return 0; |
||
71 | } |
||
72 | } elsif ($id != -1) { |
||
73 | warn "$makefile: $typename $name has invalid id $id\n"; |
||
74 | return 0; |
||
75 | } |
||
76 | |||
77 | if (not exists $names->{$name}) { |
||
78 | $names->{$name} = { |
||
79 | id => $id, |
||
80 | makefile => $makefile, |
||
81 | }; |
||
82 | } elsif ($names->{$name}{id} != $id) { |
||
83 | warn "$makefile: id of $typename $name collides with that defined defined in $names->{$name}{makefile}\n"; |
||
84 | return 0; |
||
85 | } |
||
86 | return 1; |
||
87 | } |
||
88 | |||
89 | sub parse_target_metadata($) { |
||
90 | my $file = shift; |
||
91 | my ($target, @target, $profile); |
||
92 | my %target; |
||
93 | my $makefile; |
||
94 | |||
95 | open FILE, "<$file" or do { |
||
96 | warn "Can't open file '$file': $!\n"; |
||
97 | return; |
||
98 | }; |
||
99 | while (<FILE>) { |
||
100 | chomp; |
||
101 | /^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and $makefile = $1; |
||
102 | /^Target:\s*(.+)\s*$/ and do { |
||
103 | my $name = $1; |
||
104 | $target = { |
||
105 | id => $name, |
||
106 | board => $name, |
||
107 | makefile => $makefile, |
||
108 | boardconf => confstr($name), |
||
109 | conf => confstr($name), |
||
110 | profiles => [], |
||
111 | features => [], |
||
112 | depends => [], |
||
113 | subtargets => [] |
||
114 | }; |
||
115 | push @target, $target; |
||
116 | $target{$name} = $target; |
||
117 | if ($name =~ /([^\/]+)\/([^\/]+)/) { |
||
118 | push @{$target{$1}->{subtargets}}, $2; |
||
119 | $target->{board} = $1; |
||
120 | $target->{boardconf} = confstr($1); |
||
121 | $target->{subtarget} = 1; |
||
122 | $target->{parent} = $target{$1}; |
||
123 | } |
||
124 | }; |
||
125 | /^Target-Name:\s*(.+)\s*$/ and $target->{name} = $1; |
||
126 | /^Target-Arch:\s*(.+)\s*$/ and $target->{arch} = $1; |
||
127 | /^Target-Arch-Packages:\s*(.+)\s*$/ and $target->{arch_packages} = $1; |
||
128 | /^Target-Features:\s*(.+)\s*$/ and $target->{features} = [ split(/\s+/, $1) ]; |
||
129 | /^Target-Depends:\s*(.+)\s*$/ and $target->{depends} = [ split(/\s+/, $1) ]; |
||
130 | /^Target-Description:/ and $target->{desc} = get_multiline(*FILE); |
||
131 | /^Target-Optimization:\s*(.+)\s*$/ and $target->{cflags} = $1; |
||
132 | /^CPU-Type:\s*(.+)\s*$/ and $target->{cputype} = $1; |
||
133 | /^Linux-Version:\s*(.+)\s*$/ and $target->{version} = $1; |
||
134 | /^Linux-Release:\s*(.+)\s*$/ and $target->{release} = $1; |
||
135 | /^Linux-Kernel-Arch:\s*(.+)\s*$/ and $target->{karch} = $1; |
||
136 | /^Default-Subtarget:\s*(.+)\s*$/ and $target->{def_subtarget} = $1; |
||
137 | /^Default-Packages:\s*(.+)\s*$/ and $target->{packages} = [ split(/\s+/, $1) ]; |
||
138 | /^Target-Profile:\s*(.+)\s*$/ and do { |
||
139 | $profile = { |
||
140 | id => $1, |
||
141 | name => $1, |
||
142 | priority => 999, |
||
143 | packages => [] |
||
144 | }; |
||
145 | $1 =~ /^DEVICE_/ and $target->{has_devices} = 1; |
||
146 | push @{$target->{profiles}}, $profile; |
||
147 | }; |
||
148 | /^Target-Profile-Name:\s*(.+)\s*$/ and $profile->{name} = $1; |
||
149 | /^Target-Profile-Priority:\s*(\d+)\s*$/ and do { |
||
150 | $profile->{priority} = $1; |
||
151 | $target->{sort} = 1; |
||
152 | }; |
||
153 | /^Target-Profile-Packages:\s*(.*)\s*$/ and $profile->{packages} = [ split(/\s+/, $1) ]; |
||
154 | /^Target-Profile-Description:\s*(.*)\s*/ and $profile->{desc} = get_multiline(*FILE); |
||
155 | } |
||
156 | close FILE; |
||
157 | foreach my $target (@target) { |
||
158 | if (@{$target->{subtargets}} > 0) { |
||
159 | $target->{profiles} = []; |
||
160 | next; |
||
161 | } |
||
162 | @{$target->{profiles}} > 0 or $target->{profiles} = [ |
||
163 | { |
||
164 | id => 'Default', |
||
165 | name => 'Default', |
||
166 | packages => [] |
||
167 | } |
||
168 | ]; |
||
169 | |||
170 | $target->{sort} and @{$target->{profiles}} = sort { |
||
171 | $a->{priority} <=> $b->{priority} or |
||
172 | $a->{name} cmp $b->{name}; |
||
173 | } @{$target->{profiles}}; |
||
174 | } |
||
175 | return @target; |
||
176 | } |
||
177 | |||
178 | sub clear_packages() { |
||
179 | %package = (); |
||
180 | %vpackage = (); |
||
181 | %srcpackage = (); |
||
182 | %category = (); |
||
183 | %overrides = (); |
||
184 | %usernames = (); |
||
185 | %groupnames = (); |
||
186 | } |
||
187 | |||
188 | sub parse_package_metadata($) { |
||
189 | my $file = shift; |
||
190 | my $pkg; |
||
191 | my $src; |
||
192 | my $override; |
||
193 | my %ignore = map { $_ => 1 } @ignore; |
||
194 | |||
195 | open FILE, "<$file" or do { |
||
196 | warn "Cannot open '$file': $!\n"; |
||
197 | return undef; |
||
198 | }; |
||
199 | while (<FILE>) { |
||
200 | chomp; |
||
201 | /^Source-Makefile: \s*((?:package\/)?((?:.+\/)?([^\/]+))\/Makefile)\s*$/ and do { |
||
202 | $src = { |
||
203 | makefile => $1, |
||
204 | path => $2, |
||
205 | name => $3, |
||
206 | ignore => $ignore{$3}, |
||
207 | packages => [], |
||
208 | buildtypes => [], |
||
209 | builddepends => [], |
||
210 | }; |
||
211 | $srcpackage{$3} = $src; |
||
212 | $override = ""; |
||
213 | undef $pkg; |
||
214 | }; |
||
215 | /^Override: \s*(.+?)\s*$/ and do { |
||
216 | $override = $1; |
||
217 | $overrides{$src->{name}} = 1; |
||
218 | }; |
||
219 | next unless $src; |
||
220 | /^Package:\s*(.+?)\s*$/ and do { |
||
221 | $pkg = {}; |
||
222 | $pkg->{src} = $src; |
||
223 | $pkg->{name} = $1; |
||
224 | $pkg->{title} = ""; |
||
225 | $pkg->{depends} = []; |
||
226 | $pkg->{mdepends} = []; |
||
227 | $pkg->{provides} = [$1]; |
||
228 | $pkg->{tristate} = 1; |
||
229 | $pkg->{override} = $override; |
||
230 | $package{$1} = $pkg; |
||
231 | push @{$src->{packages}}, $pkg; |
||
232 | |||
233 | $vpackage{$1} or $vpackage{$1} = []; |
||
234 | unshift @{$vpackage{$1}}, $pkg; |
||
235 | }; |
||
236 | /^Build-Depends: \s*(.+)\s*$/ and $src->{builddepends} = [ split /\s+/, $1 ]; |
||
237 | /^Build-Depends\/(\w+): \s*(.+)\s*$/ and $src->{"builddepends/$1"} = [ split /\s+/, $2 ]; |
||
238 | /^Build-Types:\s*(.+)\s*$/ and $src->{buildtypes} = [ split /\s+/, $1 ]; |
||
239 | next unless $pkg; |
||
240 | /^Version: \s*(.+)\s*$/ and $pkg->{version} = $1; |
||
241 | /^Title: \s*(.+)\s*$/ and $pkg->{title} = $1; |
||
242 | /^Menu: \s*(.+)\s*$/ and $pkg->{menu} = $1; |
||
243 | /^Submenu: \s*(.+)\s*$/ and $pkg->{submenu} = $1; |
||
244 | /^Submenu-Depends: \s*(.+)\s*$/ and $pkg->{submenudep} = $1; |
||
245 | /^Source: \s*(.+)\s*$/ and $pkg->{source} = $1; |
||
246 | /^License: \s*(.+)\s*$/ and $pkg->{license} = $1; |
||
247 | /^LicenseFiles: \s*(.+)\s*$/ and $pkg->{licensefiles} = $1; |
||
248 | /^Default: \s*(.+)\s*$/ and $pkg->{default} = $1; |
||
249 | /^Provides: \s*(.+)\s*$/ and do { |
||
250 | my @vpkg = split /\s+/, $1; |
||
251 | @{$pkg->{provides}} = ($pkg->{name}, @vpkg); |
||
252 | foreach my $vpkg (@vpkg) { |
||
253 | $vpackage{$vpkg} or $vpackage{$vpkg} = []; |
||
254 | push @{$vpackage{$vpkg}}, $pkg; |
||
255 | } |
||
256 | }; |
||
257 | /^Menu-Depends: \s*(.+)\s*$/ and $pkg->{mdepends} = [ split /\s+/, $1 ]; |
||
258 | /^Depends: \s*(.+)\s*$/ and $pkg->{depends} = [ split /\s+/, $1 ]; |
||
259 | /^Conflicts: \s*(.+)\s*$/ and $pkg->{conflicts} = [ split /\s+/, $1 ]; |
||
260 | /^Hidden: \s*(.+)\s*$/ and $pkg->{hidden} = 1; |
||
261 | /^Build-Variant: \s*([\w\-]+)\s*/ and $pkg->{variant} = $1; |
||
262 | /^Default-Variant: .*/ and $pkg->{variant_default} = 1; |
||
263 | /^Build-Only: \s*(.+)\s*$/ and $pkg->{buildonly} = 1; |
||
264 | /^Repository:\s*(.+?)\s*$/ and $pkg->{repository} = $1; |
||
265 | /^Category: \s*(.+)\s*$/ and do { |
||
266 | $pkg->{category} = $1; |
||
267 | defined $category{$1} or $category{$1} = {}; |
||
268 | defined $category{$1}{$src->{name}} or $category{$1}{$src->{name}} = []; |
||
269 | push @{$category{$1}{$src->{name}}}, $pkg; |
||
270 | }; |
||
271 | /^Description: \s*(.*)\s*$/ and $pkg->{description} = "\t\t $1\n". get_multiline(*FILE, "\t\t "); |
||
272 | /^Type: \s*(.+)\s*$/ and do { |
||
273 | $pkg->{type} = [ split /\s+/, $1 ]; |
||
274 | undef $pkg->{tristate}; |
||
275 | foreach my $type (@{$pkg->{type}}) { |
||
276 | $type =~ /ipkg/ and $pkg->{tristate} = 1; |
||
277 | } |
||
278 | }; |
||
279 | /^Config:\s*(.*)\s*$/ and $pkg->{config} = "$1\n".get_multiline(*FILE, "\t"); |
||
280 | /^Prereq-Check:/ and $pkg->{prereq} = 1; |
||
281 | /^Require-User:\s*(.*?)\s*$/ and do { |
||
282 | my @ugspecs = split /\s+/, $1; |
||
283 | |||
284 | for my $ugspec (@ugspecs) { |
||
285 | my @ugspec = split /:/, $ugspec, 2; |
||
286 | if ($ugspec[0]) { |
||
287 | parse_package_metadata_usergroup($src->{makefile}, "user", \%usernames, \%userids, $ugspec[0]) or return 0; |
||
288 | } |
||
289 | if ($ugspec[1]) { |
||
290 | parse_package_metadata_usergroup($src->{makefile}, "group", \%groupnames, \%groupids, $ugspec[1]) or return 0; |
||
291 | } |
||
292 | } |
||
293 | }; |
||
294 | } |
||
295 | close FILE; |
||
296 | return 1; |
||
297 | } |
||
298 | |||
299 | 1; |