Fields.pm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. # Copyright © 2007-2009 Raphaël Hertzog <hertzog@debian.org>
  2. #
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation; either version 2 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. package Dpkg::Control::Fields;
  16. use strict;
  17. use warnings;
  18. use base qw(Exporter);
  19. use Dpkg::Gettext;
  20. use Dpkg::ErrorHandling;
  21. use Dpkg::Control::Types;
  22. use Dpkg::Checksums qw(@check_supported %check_supported);
  23. use Dpkg::Vendor qw(run_vendor_hook);
  24. our @EXPORT = qw(field_capitalize field_is_official field_is_allowed_in
  25. field_transfer_single field_transfer_all
  26. field_list_src_dep field_list_pkg_dep field_get_dep_type
  27. field_ordered_list field_register
  28. field_insert_after field_insert_before);
  29. use constant {
  30. ALL_PKG => CTRL_INFO_PKG | CTRL_INDEX_PKG | CTRL_PKG_DEB | CTRL_FILE_STATUS,
  31. ALL_SRC => CTRL_INFO_SRC | CTRL_INDEX_SRC | CTRL_PKG_SRC,
  32. ALL_CHANGES => CTRL_FILE_CHANGES | CTRL_CHANGELOG,
  33. };
  34. # The canonical list of fields
  35. # Note that fields used only in dpkg's available file are not listed
  36. # Deprecated fields of dpkg's status file are also not listed
  37. our %FIELDS = (
  38. 'Architecture' => {
  39. allowed => (ALL_PKG | ALL_SRC | CTRL_FILE_CHANGES) & (~CTRL_INFO_SRC),
  40. },
  41. 'Binary' => {
  42. allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES,
  43. },
  44. 'Breaks' => {
  45. allowed => ALL_PKG,
  46. dependency => 'union',
  47. dep_order => 7,
  48. },
  49. 'Bugs' => {
  50. allowed => (ALL_PKG | CTRL_INFO_SRC | CTRL_FILE_VENDOR) & (~CTRL_INFO_PKG),
  51. },
  52. 'Build-Conflicts' => {
  53. allowed => ALL_SRC,
  54. dependency => 'union',
  55. dep_order => 3,
  56. },
  57. 'Build-Conflicts-Indep' => {
  58. allowed => ALL_SRC,
  59. dependency => 'union',
  60. dep_order => 4,
  61. },
  62. 'Build-Depends' => {
  63. allowed => ALL_SRC,
  64. dependency => 'normal',
  65. dep_order => 1,
  66. },
  67. 'Build-Depends-Indep' => {
  68. allowed => ALL_SRC,
  69. dependency => 'normal',
  70. dep_order => 2,
  71. },
  72. 'Changed-By' => {
  73. allowed => CTRL_FILE_CHANGES,
  74. },
  75. 'Changes' => {
  76. allowed => ALL_CHANGES,
  77. },
  78. 'Closes' => {
  79. allowed => ALL_CHANGES,
  80. },
  81. 'Conffiles' => {
  82. allowed => CTRL_FILE_STATUS,
  83. },
  84. 'Config-Version' => {
  85. allowed => CTRL_FILE_STATUS,
  86. },
  87. 'Conflicts' => {
  88. allowed => ALL_PKG,
  89. dependency => 'union',
  90. dep_order => 6,
  91. },
  92. 'Date' => {
  93. allowed => ALL_CHANGES,
  94. },
  95. 'Depends' => {
  96. allowed => ALL_PKG,
  97. dependency => 'normal',
  98. dep_order => 2,
  99. },
  100. 'Description' => {
  101. allowed => ALL_PKG | CTRL_FILE_CHANGES,
  102. },
  103. 'Directory' => {
  104. allowed => CTRL_INDEX_SRC,
  105. },
  106. 'Distribution' => {
  107. allowed => ALL_CHANGES,
  108. },
  109. 'Enhances' => {
  110. allowed => ALL_PKG,
  111. dependency => 'union',
  112. dep_order => 5,
  113. },
  114. 'Essential' => {
  115. allowed => ALL_PKG,
  116. },
  117. 'Filename' => {
  118. allowed => CTRL_INDEX_PKG,
  119. },
  120. 'Files' => {
  121. allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES,
  122. },
  123. 'Format' => {
  124. allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES,
  125. },
  126. 'Homepage' => {
  127. allowed => ALL_SRC | ALL_PKG,
  128. },
  129. 'Installed-Size' => {
  130. allowed => ALL_PKG & ~CTRL_INFO_PKG,
  131. },
  132. 'Installer-Menu-Item' => {
  133. allowed => ALL_PKG,
  134. },
  135. 'Kernel-Version' => {
  136. allowed => ALL_PKG,
  137. },
  138. 'Origin' => {
  139. allowed => (ALL_PKG | ALL_SRC) & (~CTRL_INFO_PKG),
  140. },
  141. 'Maintainer' => {
  142. allowed => CTRL_PKG_DEB | ALL_SRC | ALL_CHANGES,
  143. },
  144. 'Multi-Arch' => {
  145. allowed => ALL_PKG,
  146. },
  147. 'Package' => {
  148. allowed => ALL_PKG,
  149. },
  150. 'Package-Type' => {
  151. allowed => ALL_PKG,
  152. },
  153. 'Parent' => {
  154. allowed => CTRL_FILE_VENDOR,
  155. },
  156. 'Pre-Depends' => {
  157. allowed => ALL_PKG,
  158. dependency => 'normal',
  159. dep_order => 1,
  160. },
  161. 'Priority' => {
  162. allowed => CTRL_INFO_SRC | CTRL_INDEX_SRC | ALL_PKG,
  163. },
  164. 'Provides' => {
  165. allowed => ALL_PKG,
  166. dependency => 'union',
  167. dep_order => 9,
  168. },
  169. 'Recommends' => {
  170. allowed => ALL_PKG,
  171. dependency => 'normal',
  172. dep_order => 3,
  173. },
  174. 'Replaces' => {
  175. allowed => ALL_PKG,
  176. dependency => 'union',
  177. dep_order => 8,
  178. },
  179. 'Section' => {
  180. allowed => CTRL_INFO_SRC | CTRL_INDEX_SRC | ALL_PKG,
  181. },
  182. 'Size' => {
  183. allowed => CTRL_INDEX_PKG,
  184. },
  185. 'Source' => {
  186. allowed => (ALL_PKG | ALL_SRC | ALL_CHANGES) &
  187. (~(CTRL_INDEX_SRC | CTRL_INFO_PKG)),
  188. },
  189. 'Standards-Version' => {
  190. allowed => ALL_SRC,
  191. },
  192. 'Status' => {
  193. allowed => CTRL_FILE_STATUS,
  194. },
  195. 'Subarchitecture' => {
  196. allowed => ALL_PKG,
  197. },
  198. 'Suggests' => {
  199. allowed => ALL_PKG,
  200. dependency => 'normal',
  201. dep_order => 4,
  202. },
  203. 'Tag' => {
  204. allowed => ALL_PKG,
  205. },
  206. 'Task' => {
  207. allowed => ALL_PKG,
  208. },
  209. 'Triggers-Awaited' => {
  210. allowed => CTRL_FILE_STATUS,
  211. },
  212. 'Triggers-Pending' => {
  213. allowed => CTRL_FILE_STATUS,
  214. },
  215. 'Uploaders' => {
  216. allowed => ALL_SRC,
  217. },
  218. 'Urgency' => {
  219. allowed => ALL_CHANGES,
  220. },
  221. 'Vcs-Browser' => {
  222. allowed => ALL_SRC,
  223. },
  224. 'Vcs-Arch' => {
  225. allowed => ALL_SRC,
  226. },
  227. 'Vcs-Bzr' => {
  228. allowed => ALL_SRC,
  229. },
  230. 'Vcs-Cvs' => {
  231. allowed => ALL_SRC,
  232. },
  233. 'Vcs-Darcs' => {
  234. allowed => ALL_SRC,
  235. },
  236. 'Vcs-Git' => {
  237. allowed => ALL_SRC,
  238. },
  239. 'Vcs-Hg' => {
  240. allowed => ALL_SRC,
  241. },
  242. 'Vcs-Mtn' => {
  243. allowed => ALL_SRC,
  244. },
  245. 'Vcs-Svn' => {
  246. allowed => ALL_SRC,
  247. },
  248. 'Vendor' => {
  249. allowed => CTRL_FILE_VENDOR,
  250. },
  251. 'Vendor-Url' => {
  252. allowed => CTRL_FILE_VENDOR,
  253. },
  254. 'Version' => {
  255. allowed => (ALL_PKG | ALL_SRC | ALL_CHANGES) &
  256. (~(CTRL_INFO_SRC | CTRL_INFO_PKG)),
  257. },
  258. );
  259. my @checksum_fields = map { field_capitalize("Checksums-$_") } @check_supported;
  260. my @sum_fields = map { $_ eq "md5" ? "MD5sum" : field_capitalize($_) }
  261. @check_supported;
  262. &field_register($_, CTRL_PKG_SRC | CTRL_FILE_CHANGES) foreach @checksum_fields;
  263. &field_register($_, CTRL_INDEX_PKG) foreach @sum_fields;
  264. our %FIELD_ORDER = (
  265. CTRL_PKG_DEB() => [
  266. qw(Package Package-Type Source Version Kernel-Version Architecture
  267. Subarchitecture Installer-Menu-Item Essential Origin Bugs
  268. Maintainer Installed-Size), &field_list_pkg_dep(),
  269. qw(Section Priority Multi-Arch Homepage Description Tag Task)
  270. ],
  271. CTRL_PKG_SRC() => [
  272. qw(Format Source Binary Architecture Version Origin Maintainer
  273. Uploaders Homepage Standards-Version Vcs-Browser
  274. Vcs-Arch Vcs-Bzr Vcs-Cvs Vcs-Darcs Vcs-Git Vcs-Hg Vcs-Mtn
  275. Vcs-Svn), &field_list_src_dep(), @checksum_fields, qw(Files)
  276. ],
  277. CTRL_FILE_CHANGES() => [
  278. qw(Format Date Source Binary Architecture Version Distribution
  279. Urgency Maintainer Changed-By Description Closes Changes),
  280. @checksum_fields, qw(Files)
  281. ],
  282. CTRL_CHANGELOG() => [
  283. qw(Source Version Distribution Urgency Maintainer Date Closes
  284. Changes Timestamp Header Items Trailer Urgency_comment
  285. Urgency_lc)
  286. ],
  287. CTRL_FILE_STATUS() => [ # Same as fieldinfos in lib/dpkg/parse.c
  288. qw(Package Essential Status Priority Section Installed-Size Origin
  289. Maintainer Bugs Architecture Source Version Config-Version
  290. Replaces Provides Depends Pre-Depends Recommends Suggests Breaks
  291. Conflicts Enhances Conffiles Description Triggers-Pending
  292. Triggers-Awaited)
  293. ],
  294. );
  295. # Order for CTRL_INDEX_PKG is derived from CTRL_PKG_DEB
  296. $FIELD_ORDER{CTRL_INDEX_PKG()} = [ @{$FIELD_ORDER{CTRL_PKG_DEB()}} ];
  297. &field_insert_before(CTRL_INDEX_PKG, 'Section', 'Filename', 'Size', @sum_fields);
  298. # Order for CTRL_INDEX_SRC is derived from CTRL_PKG_SRC
  299. $FIELD_ORDER{CTRL_INDEX_SRC()} = [ @{$FIELD_ORDER{CTRL_PKG_SRC()}} ];
  300. @{$FIELD_ORDER{CTRL_INDEX_SRC()}} = map { $_ eq "Source" ? "Package" : $_ }
  301. @{$FIELD_ORDER{CTRL_PKG_SRC()}};
  302. &field_insert_after(CTRL_INDEX_SRC, "Version", "Priority", "Section");
  303. &field_insert_before(CTRL_INDEX_SRC, "Checksums-Md5", "Directory");
  304. # Register vendor specifics fields
  305. foreach my $op (run_vendor_hook("register-custom-fields")) {
  306. next if not (defined $op and ref $op); # Skip when not implemented by vendor
  307. my $func = shift @$op;
  308. if ($func eq "register") {
  309. &field_register(@$op);
  310. } elsif ($func eq "insert_before") {
  311. &field_insert_before(@$op);
  312. } elsif ($func eq "insert_after") {
  313. &field_insert_after(@$op);
  314. } else {
  315. error("vendor hook register-custom-fields sent bad data: @$op");
  316. }
  317. }
  318. =head1 NAME
  319. Dpkg::Control::Fields - manage (list of official) control fields
  320. =head1 DESCRIPTION
  321. The modules contains a list of fieldnames with associated meta-data explaining
  322. in which type of control information they are allowed. The types are the
  323. CTRL_* constants exported by Dpkg::Control.
  324. =head1 FUNCTIONS
  325. =over 4
  326. =item my $f = field_capitalize($field_name)
  327. Returns the field name properly capitalized. All characters are lowercase,
  328. except the first of each word (words are separated by a dash in field names).
  329. =cut
  330. sub field_capitalize($) {
  331. my $field = lc(shift);
  332. # Some special cases due to history
  333. return "MD5sum" if $field eq "md5sum";
  334. return uc($field) if exists $check_supported{$field};
  335. # Generic case
  336. return join '-', map { ucfirst } split /-/, $field;
  337. }
  338. =item field_is_official($fname)
  339. Returns true if the field is official and known.
  340. =cut
  341. sub field_is_official($) {
  342. return exists $FIELDS{field_capitalize($_[0])};
  343. }
  344. =item field_is_allowed_in($fname, @types)
  345. Returns true (1) if the field $fname is allowed in all the types listed in
  346. the list. Note that you can use type sets instead of individual types (ex:
  347. CTRL_FILE_CHANGES | CTRL_CHANGELOG).
  348. field_allowed_in(A|B, C) returns true only if the field is allowed in C
  349. and either A or B.
  350. Undef is returned for non-official fields.
  351. =cut
  352. sub field_is_allowed_in($@) {
  353. my ($field, @types) = @_;
  354. $field = field_capitalize($field);
  355. return undef unless field_is_official($field);
  356. return 0 if not scalar(@types);
  357. foreach my $type (@types) {
  358. next if $type == CTRL_UNKNOWN; # Always allowed
  359. return 0 unless $FIELDS{$field}{'allowed'} & $type;
  360. }
  361. return 1;
  362. }
  363. =item field_transfer_single($from, $to, $field)
  364. If appropriate, copy the value of the field named $field taken from the
  365. $from Dpkg::Control object to the $to Dpkg::Control object.
  366. Official fields are copied only if the field is allowed in both types of
  367. objects. Custom fields are treated in a specific manner. When the target
  368. is not among CTRL_PKG_SRC, CTRL_PKG_DEB or CTRL_FILE_CHANGES, then they
  369. are alway copied as is (the X- prefix is kept). Otherwise they are not
  370. copied except if the target object matches the target destination encoded
  371. in the field name. The initial X denoting custom fields can be followed by
  372. one or more letters among "S" (Source: corresponds to CTRL_PKG_SRC), "B"
  373. (Binary: corresponds to CTRL_PKG_DEB) or "C" (Changes: corresponds to
  374. CTRL_FILE_CHANGES).
  375. Returns undef if nothing has been copied or the name of the new field
  376. added to $to otherwise.
  377. =cut
  378. sub field_transfer_single($$_) {
  379. my ($from, $to, $field) = @_;
  380. my ($from_type, $to_type) = ($from->get_type(), $to->get_type());
  381. $field = field_capitalize($field);
  382. if (field_is_allowed_in($field, $from_type, $to_type)) {
  383. $to->{$field} = $from->{$field};
  384. return $field;
  385. } elsif ($field =~ /^X([SBC]*)-/i) {
  386. my $dest = $1;
  387. if (($dest =~ /B/i and $to_type == CTRL_PKG_DEB) or
  388. ($dest =~ /S/i and $to_type == CTRL_PKG_SRC) or
  389. ($dest =~ /C/i and $to_type == CTRL_FILE_CHANGES))
  390. {
  391. my $new = $field;
  392. $new =~ s/^X([SBC]*)-//i;
  393. $to->{$new} = $from->{$field};
  394. return $new;
  395. } elsif ($to_type != CTRL_PKG_DEB and
  396. $to_type != CTRL_PKG_SRC and
  397. $to_type != CTRL_FILE_CHANGES)
  398. {
  399. $to->{$field} = $from->{$field};
  400. return $field;
  401. }
  402. } elsif (not field_is_allowed_in($field, $from_type)) {
  403. warning(_g("unknown information field '%s' in input data in %s"),
  404. $field, $from->get_option("name") || _g("control information"));
  405. }
  406. return undef;
  407. }
  408. =item field_transfer_all($from, $to)
  409. Transfer all appropriate fields from $from to $to. Calls
  410. field_transfer_single() on all fields available in $from.
  411. Returns the list of fields that have been added to $to.
  412. =cut
  413. sub field_transfer_all($$) {
  414. my ($from, $to) = @_;
  415. my (@res, $res);
  416. foreach my $k (keys %$from) {
  417. $res = field_transfer_single($from, $to, $k);
  418. push @res, $res if $res and defined wantarray;
  419. }
  420. return @res;
  421. }
  422. =item field_ordered_list($type)
  423. Returns an ordered list of fields for a given type of control information.
  424. This list can be used to output the fields in a predictable order.
  425. The list might be empty for types where the order does not matter much.
  426. =cut
  427. sub field_ordered_list($) {
  428. my ($type) = @_;
  429. return @{$FIELD_ORDER{$type}} if exists $FIELD_ORDER{$type};
  430. return ();
  431. }
  432. =item field_list_src_dep()
  433. List of fields that contains dependencies-like information in a source
  434. Debian package.
  435. =cut
  436. sub field_list_src_dep() {
  437. return sort {
  438. $FIELDS{$a}{'dep_order'} <=> $FIELDS{$b}{'dep_order'}
  439. } grep {
  440. field_is_allowed_in($_, CTRL_PKG_SRC) and
  441. exists $FIELDS{$_}{'dependency'}
  442. } keys %FIELDS;
  443. }
  444. =item field_list_pkg_dep()
  445. List of fields that contains dependencies-like information in a binary
  446. Debian package. The fields that express real dependencies are sorted from
  447. the stronger to the weaker.
  448. =cut
  449. sub field_list_pkg_dep() {
  450. my @keys = keys %FIELDS;
  451. return sort {
  452. $FIELDS{$a}{'dep_order'} <=> $FIELDS{$b}{'dep_order'}
  453. } grep {
  454. field_is_allowed_in($_, CTRL_PKG_DEB) and
  455. exists $FIELDS{$_}{'dependency'}
  456. } @keys;
  457. }
  458. =item field_get_dep_type($field)
  459. Return the type of the dependency expressed by the given field. Can
  460. either be "normal" for a real dependency field (Pre-Depends, Depends, ...)
  461. or "union" for other relation fields sharing the same syntax (Conflicts,
  462. Breaks, ...). Returns undef for fields which are not dependencies.
  463. =cut
  464. sub field_get_dep_type($) {
  465. my $field = field_capitalize($_[0]);
  466. return undef unless field_is_official($field);
  467. return $FIELDS{$field}{'dependency'} if exists $FIELDS{$field}{'dependency'};
  468. return undef;
  469. }
  470. =item field_register($field, $allowed_types, %opts)
  471. Register a new field as being allowed in control information of specified
  472. types. %opts is optional
  473. =cut
  474. sub field_register($$;@) {
  475. my ($field, $types, %opts) = @_;
  476. $field = field_capitalize($field);
  477. $FIELDS{$field} = {
  478. allowed => $types,
  479. %opts
  480. };
  481. }
  482. =item field_insert_after($type, $ref, @fields)
  483. Place field after another one ($ref) in output of control information of
  484. type $type.
  485. =cut
  486. sub field_insert_after($$@) {
  487. my ($type, $field, @fields) = @_;
  488. return 0 if not exists $FIELD_ORDER{$type};
  489. ($field, @fields) = map { field_capitalize($_) } ($field, @fields);
  490. @{$FIELD_ORDER{$type}} = map {
  491. ($_ eq $field) ? ($_, @fields) : $_
  492. } @{$FIELD_ORDER{$type}};
  493. return 1;
  494. }
  495. =item field_insert_before($type, $ref, @fields)
  496. Place field before another one ($ref) in output of control information of
  497. type $type.
  498. =cut
  499. sub field_insert_before($$@) {
  500. my ($type, $field, @fields) = @_;
  501. return 0 if not exists $FIELD_ORDER{$type};
  502. ($field, @fields) = map { field_capitalize($_) } ($field, @fields);
  503. @{$FIELD_ORDER{$type}} = map {
  504. ($_ eq $field) ? (@fields, $_) : $_
  505. } @{$FIELD_ORDER{$type}};
  506. return 1;
  507. }
  508. =back
  509. =head1 AUTHOR
  510. Raphaël Hertzog <hertzog@debian.org>.
  511. =cut
  512. 1;