1package metadata;
2use base 'Exporter';
3use strict;
4use warnings;
5our @EXPORT = qw(%package %srcpackage %category %subdir %preconfig %features %overrides clear_packages parse_package_metadata parse_target_metadata get_multiline @ignore);
6
7our %package;
8our %preconfig;
9our %srcpackage;
10our %category;
11our %subdir;
12our %features;
13our %overrides;
14our @ignore;
15
16sub get_multiline {
17	my $fh = shift;
18	my $prefix = shift;
19	my $str;
20	while (<$fh>) {
21		last if /^@@/;
22		$str .= (($_ and $prefix) ? $prefix . $_ : $_);
23	}
24
25	return $str ? $str : "";
26}
27
28sub confstr($) {
29	my $conf = shift;
30	$conf =~ tr#/\.\-/#___#;
31	return $conf;
32}
33
34sub parse_target_metadata($) {
35	my $file = shift;
36	my ($target, @target, $profile);
37	my %target;
38	my $makefile;
39
40	open FILE, "<$file" or do {
41		warn "Can't open file '$file': $!\n";
42		return;
43	};
44	while (<FILE>) {
45		chomp;
46		/^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and $makefile = $1;
47		/^Target:\s*(.+)\s*$/ and do {
48			my $name = $1;
49			$target = {
50				id => $name,
51				board => $name,
52				makefile => $makefile,
53				boardconf => confstr($name),
54				conf => confstr($name),
55				profiles => [],
56				features => [],
57				depends => [],
58				subtargets => []
59			};
60			push @target, $target;
61			$target{$name} = $target;
62			if ($name =~ /([^\/]+)\/([^\/]+)/) {
63				push @{$target{$1}->{subtargets}}, $2;
64				$target->{board} = $1;
65				$target->{boardconf} = confstr($1);
66				$target->{subtarget} = 1;
67				$target->{parent} = $target{$1};
68			}
69		};
70		/^Target-Name:\s*(.+)\s*$/ and $target->{name} = $1;
71		/^Target-Path:\s*(.+)\s*$/ and $target->{path} = $1;
72		/^Target-Arch:\s*(.+)\s*$/ and $target->{arch} = $1;
73		/^Target-Arch-Packages:\s*(.+)\s*$/ and $target->{arch_packages} = $1;
74		/^Target-Features:\s*(.+)\s*$/ and $target->{features} = [ split(/\s+/, $1) ];
75		/^Target-Depends:\s*(.+)\s*$/ and $target->{depends} = [ split(/\s+/, $1) ];
76		/^Target-Description:/ and $target->{desc} = get_multiline(*FILE);
77		/^Target-Optimization:\s*(.+)\s*$/ and $target->{cflags} = $1;
78		/^CPU-Type:\s*(.+)\s*$/ and $target->{cputype} = $1;
79		/^Linux-Version:\s*(.+)\s*$/ and $target->{version} = $1;
80		/^Linux-Release:\s*(.+)\s*$/ and $target->{release} = $1;
81		/^Linux-Kernel-Arch:\s*(.+)\s*$/ and $target->{karch} = $1;
82		/^Default-Subtarget:\s*(.+)\s*$/ and $target->{def_subtarget} = $1;
83		/^Default-Packages:\s*(.+)\s*$/ and $target->{packages} = [ split(/\s+/, $1) ];
84		/^Target-Profile:\s*(.+)\s*$/ and do {
85			$profile = {
86				id => $1,
87				name => $1,
88				packages => []
89			};
90			push @{$target->{profiles}}, $profile;
91		};
92		/^Target-Profile-Name:\s*(.+)\s*$/ and $profile->{name} = $1;
93		/^Target-Profile-Packages:\s*(.*)\s*$/ and $profile->{packages} = [ split(/\s+/, $1) ];
94		/^Target-Profile-Description:\s*(.*)\s*/ and $profile->{desc} = get_multiline(*FILE);
95		/^Target-Profile-Config:/ and $profile->{config} = get_multiline(*FILE, "\t");
96		/^Target-Profile-Kconfig:/ and $profile->{kconfig} = 1;
97	}
98	close FILE;
99	foreach my $target (@target) {
100		if (@{$target->{subtargets}} > 0) {
101			$target->{profiles} = [];
102			next;
103		}
104		@{$target->{profiles}} > 0 or $target->{profiles} = [
105			{
106				id => 'Default',
107				name => 'Default',
108				packages => []
109			}
110		];
111	}
112	return @target;
113}
114
115sub clear_packages() {
116	%subdir = ();
117	%preconfig = ();
118	%package = ();
119	%srcpackage = ();
120	%category = ();
121	%features = ();
122	%overrides = ();
123}
124
125sub parse_package_metadata($) {
126	my $file = shift;
127	my $pkg;
128	my $feature;
129	my $makefile;
130	my $preconfig;
131	my $subdir;
132	my $src;
133	my $override;
134	my %ignore = map { $_ => 1 } @ignore;
135
136	open FILE, "<$file" or do {
137		warn "Cannot open '$file': $!\n";
138		return undef;
139	};
140	while (<FILE>) {
141		chomp;
142		/^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and do {
143			$makefile = $1;
144			$subdir = $2;
145			$src = $3;
146			$subdir =~ s/^package\///;
147			$subdir{$src} = $subdir;
148			$srcpackage{$src} = [];
149			$override = "";
150			undef $pkg;
151		};
152		/^Override: \s*(.+?)\s*$/ and do {
153			$override = $1;
154			$overrides{$src} = 1;
155		};
156		next unless $src;
157		next if $ignore{$src};
158		/^Package:\s*(.+?)\s*$/ and do {
159			undef $feature;
160			$pkg = {};
161			$pkg->{src} = $src;
162			$pkg->{makefile} = $makefile;
163			$pkg->{name} = $1;
164			$pkg->{title} = "";
165			$pkg->{depends} = [];
166			$pkg->{mdepends} = [];
167			$pkg->{builddepends} = [];
168			$pkg->{buildtypes} = [];
169			$pkg->{subdir} = $subdir;
170			$pkg->{tristate} = 1;
171			$pkg->{override} = $override;
172			$package{$1} = $pkg;
173			push @{$srcpackage{$src}}, $pkg;
174		};
175		/^Feature:\s*(.+?)\s*$/ and do {
176			undef $pkg;
177			$feature = {};
178			$feature->{name} = $1;
179			$feature->{priority} = 0;
180		};
181		$feature and do {
182			/^Target-Name:\s*(.+?)\s*$/ and do {
183				$features{$1} or $features{$1} = [];
184				push @{$features{$1}}, $feature;
185			};
186			/^Target-Title:\s*(.+?)\s*$/ and $feature->{target_title} = $1;
187			/^Feature-Priority:\s*(\d+)\s*$/ and $feature->{priority} = $1;
188			/^Feature-Name:\s*(.+?)\s*$/ and $feature->{title} = $1;
189			/^Feature-Description:/ and $feature->{description} = get_multiline(\*FILE, "\t\t\t");
190			next;
191		};
192		next unless $pkg;
193		/^Version: \s*(.+)\s*$/ and $pkg->{version} = $1;
194		/^Title: \s*(.+)\s*$/ and $pkg->{title} = $1;
195		/^Menu: \s*(.+)\s*$/ and $pkg->{menu} = $1;
196		/^Submenu: \s*(.+)\s*$/ and $pkg->{submenu} = $1;
197		/^Submenu-Depends: \s*(.+)\s*$/ and $pkg->{submenudep} = $1;
198		/^Source: \s*(.+)\s*$/ and $pkg->{source} = $1;
199		/^License: \s*(.+)\s*$/ and $pkg->{license} = $1;
200		/^LicenseFiles: \s*(.+)\s*$/ and $pkg->{licensefiles} = $1;
201		/^Default: \s*(.+)\s*$/ and $pkg->{default} = $1;
202		/^Provides: \s*(.+)\s*$/ and do {
203			my @vpkg = split /\s+/, $1;
204			foreach my $vpkg (@vpkg) {
205				$package{$vpkg} or $package{$vpkg} = {
206					name => $vpkg,
207					vdepends => [],
208					src => $src,
209					subdir => $subdir,
210					makefile => $makefile
211				};
212				push @{$package{$vpkg}->{vdepends}}, $pkg->{name};
213			}
214		};
215		/^Menu-Depends: \s*(.+)\s*$/ and $pkg->{mdepends} = [ split /\s+/, $1 ];
216		/^Depends: \s*(.+)\s*$/ and $pkg->{depends} = [ split /\s+/, $1 ];
217		/^Conflicts: \s*(.+)\s*$/ and $pkg->{conflicts} = [ split /\s+/, $1 ];
218		/^Hidden: \s*(.+)\s*$/ and $pkg->{hidden} = 1;
219		/^Build-Variant: \s*([\w\-]+)\s*/ and $pkg->{variant} = $1;
220		/^Default-Variant: .*/ and $pkg->{variant_default} = 1;
221		/^Build-Only: \s*(.+)\s*$/ and $pkg->{buildonly} = 1;
222		/^Build-Depends: \s*(.+)\s*$/ and $pkg->{builddepends} = [ split /\s+/, $1 ];
223		/^Build-Depends\/(\w+): \s*(.+)\s*$/ and $pkg->{"builddepends/$1"} = [ split /\s+/, $2 ];
224		/^Build-Types:\s*(.+)\s*$/ and $pkg->{buildtypes} = [ split /\s+/, $1 ];
225		/^Package-Subdir:\s*(.+?)\s*$/ and $pkg->{package_subdir} = $1;
226		/^Category: \s*(.+)\s*$/ and do {
227			$pkg->{category} = $1;
228			defined $category{$1} or $category{$1} = {};
229			defined $category{$1}->{$src} or $category{$1}->{$src} = [];
230			push @{$category{$1}->{$src}}, $pkg;
231		};
232		/^Description: \s*(.*)\s*$/ and $pkg->{description} = "\t\t $1\n". get_multiline(*FILE, "\t\t ");
233		/^Type: \s*(.+)\s*$/ and do {
234			$pkg->{type} = [ split /\s+/, $1 ];
235			undef $pkg->{tristate};
236			foreach my $type (@{$pkg->{type}}) {
237				$type =~ /ipkg/ and $pkg->{tristate} = 1;
238			}
239		};
240		/^Config:\s*(.*)\s*$/ and $pkg->{config} = "$1\n".get_multiline(*FILE, "\t");
241		/^Prereq-Check:/ and $pkg->{prereq} = 1;
242		/^Preconfig:\s*(.+)\s*$/ and do {
243			my $pkgname = $pkg->{name};
244			$preconfig{$pkgname} or $preconfig{$pkgname} = {};
245			if (exists $preconfig{$pkgname}->{$1}) {
246				$preconfig = $preconfig{$pkgname}->{$1};
247			} else {
248				$preconfig = {
249					id => $1
250				};
251				$preconfig{$pkgname}->{$1} = $preconfig;
252			}
253		};
254		/^Preconfig-Type:\s*(.*?)\s*$/ and $preconfig->{type} = $1;
255		/^Preconfig-Label:\s*(.*?)\s*$/ and $preconfig->{label} = $1;
256		/^Preconfig-Default:\s*(.*?)\s*$/ and $preconfig->{default} = $1;
257	}
258	close FILE;
259	return 1;
260}
261
2621;
263