Fields.pm 17 KB

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