Fields.pm 16 KB

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