Fields.pm 16 KB

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