[Pkg-ocaml-maint-commits] r1214 - trunk/tools/dh_ocaml

Stefano Zacchiroli zack@costa.debian.org
Thu, 07 Apr 2005 13:45:22 +0000


Author: zack
Date: 2005-04-07 13:45:21 +0000 (Thu, 07 Apr 2005)
New Revision: 1214

Modified:
   trunk/tools/dh_ocaml/dh_ocaml
Log:
- uses ocaml-md5sums (code really lighter now)
- try to guess objects related to ocaml bytecode binaries (still to be tested)
- wrote (first draft of) pod documentation


Modified: trunk/tools/dh_ocaml/dh_ocaml
===================================================================
--- trunk/tools/dh_ocaml/dh_ocaml	2005-04-06 15:01:26 UTC (rev 1213)
+++ trunk/tools/dh_ocaml/dh_ocaml	2005-04-07 13:45:21 UTC (rev 1214)
@@ -6,7 +6,7 @@
 # Copyright (C) 2005, Stefano Zacchiroli <zack@debian.org>
 #
 # Created:	  Fri, 01 Apr 2005 19:50:48 +0200 zack
-# Last-Modified:  Mon, 04 Apr 2005 20:52:23 +0200 zack
+# Last-Modified:  Thu, 07 Apr 2005 09:40:15 +0200 zack
 #
 # This is free software, you can redistribute it and/or modify it under the
 # terms of the GNU General Public License version 2 as published by the Free
@@ -22,17 +22,18 @@
 # Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
-# TODO ask Joey Hess about how much dh_ocaml follows debhelper guidelines
 # TODO check how dh_ocaml work when multiple binary packages are being built
 # TODO for libraries: add proper dependencies on ocaml (and findlib?)
 # TODO for binaries: check if package is shipping any bytecode binaries (head -1
 #	should be enough) and add proper dependencies on ocaml
 # TODO complete POD documentation
-# TODO add comment headers for uncommented subs
+# TODO check if dh_ocaml md5sums calculation works with -pack -ed units (e.g.
+#      Foo.Bar)
 
 =head1 NAME
 
-dh_ocaml - compute OCaml md5sums and calculate OCaml dependencies
+dh_ocaml - calculates ocaml dependencies and adds postinst and prerm ocaml
+scripts
 
 =cut
 
@@ -40,211 +41,116 @@
 use Debian::Debhelper::Dh_Lib;
 init();
 
-# dh_perl documentation follows, cut and pasted here since I don't know POD
-# syntax
-# -- Zack
-# 
-# =head1 SYNOPSIS
-# 
-# B<dh_ocaml> [S<I<debhelper options>>] [B<-d>] [S<I<library dirs ...>>]
-# 
-# =head1 DESCRIPTION
-# 
-# dh_perl is a debhelper program that is responsible for generating
-# the ${perl:Depends} substitutions and adding them to substvars files.
-# 
-# The program will look at perl scripts and modules in your package,
-# and will use this information to generate a dependency on perl or
-# perlapi. The dependency will be substituted into your package's control
-# file wherever you place the token "${perl:Depends}".
-# 
-# =head1 OPTIONS
-# 
-# =over 4
-# 
-# =item B<-d>
-# 
-# In some specific cases you may want to depend on perl-base rather than the
-# full perl package. If so, you can pass the -d option to make dh_perl generate
-# a dependency on the correct base package. This is only necessary for some
-# packages that are included in the base system.
-# 
-# Note that this flag may cause no dependency on perl-base to be generated at
-# all. perl-base is Essential, so its dependency can be left out, unless a
-# versioned dependency is needed.
-# 
-# =item B<-V>
-# 
-# By default, scripts and architecture independent modules don't depend
-# on any specific version of perl.  The -V option causes the current
-# version of the perl (or perl-base with -d) package to be specified.
-# 
-# =item I<library dirs>
-# 
-# If your package installs perl modules in non-standard
-# directories, you can make dh_perl check those directories by passing their
-# names on the command line. It will only check the vendorlib and vendorarch
-# directories by default.
-# 
-# =back
-# 
-# =head1 CONFORMS TO
-# 
-# Debian policy, version 3.0.1
-# 
-# Perl policy, version 1.18
-# 
-# =cut
-
 my $ocamlc = "/usr/bin/ocamlc";
-my $ocamlobjinfo = "/usr/bin/ocamlobjinfo";
-foreach my $bin ($ocamlc, $ocamlobjinfo) {
+# my $ocaml_md5sums = "/usr/bin/ocaml-md5sums";
+my $ocaml_md5sums = "/home/zack/dati/source/ocaml/dh_ocaml/ocaml-md5sums";
+my @binaries = ($ocamlc, $ocaml_md5sums);
+foreach my $bin (@binaries) {
   error "$bin does not exists or is not executable" unless -x $bin;
 }
+chomp (my $ocaml_lib_dir = `$ocamlc -where`);
 
-my $ocaml_version = `$ocamlc -version`;
-my $ocaml_lib_dir = `$ocamlc -where`;
-chomp ($ocaml_version, $ocaml_lib_dir);
 my $md5sums_dir = "/var/lib/ocaml/md5sums";
 my $md5sums_ext = ".md5sums";
-my $md5sums_registry_path = "$md5sums_dir/MD5SUMS";
-my $dep_substvar = "ocaml:Depends";
+my $ocaml_magic_line = "#!/usr/bin/ocamlrun";
 
-# given as input a directory, returns a list of all ocaml objects installed (at
-# any depth) in that directory
-sub find_objects($) {
+=head1 SYNOPSIS
+
+B<dh_ocaml> [S<I<debhelper options>>]
+
+=head1 DESCRIPTION
+
+dh_ocaml is a debhelper program that is responsible for generating
+the ${ocaml:Depends} substitutions and adding them to substvars files. It will
+also add a postinst and prerm script if required.
+
+The program will look at ocaml objects (files matching *.cm[ao]) shipped by your
+package. From them, dh_ocaml uses ocamlobjinfo for collecting information about
+ocaml modules (or units, in ocamlobjinfo terminology) defined and used by your
+package. Collected information will be used both for extracting dependencies
+information from the local ocaml md5sums registry (stored in
+/var/lib/ocaml/md5sums/MD5SUMS) and for creating libfoo-ocaml-dev.md5sums entry
+for the registry.
+
+Dependencies information will be used for filling the ${ocaml:Depends}
+subtitution while .md5sums entry will be installed in /var/lib/ocaml/md5sums/.
+If such an entry gets installed, postinst and prerm script will also be created
+in order to update the registry at package install/removal time.
+
+=head1 CONFORMS TO
+
+Debian policy, version 3.6.1.1
+
+OCaml packaging policy, version 0.6
+
+=cut
+
+# find ocaml bytecode executables contained in a given directory
+sub find_ocaml_bc_binaries($) {
   my ($dir) = @_;
-  my $cmd = "find $dir$ocaml_lib_dir -type f -name '*.cma'";
-  verbose_print $cmd;
-  my $out = `$cmd` or error "can't execute \"$cmd\" for pipe-reading";
-  my @objects = split /\n/, $out;
-  return @objects;
+  my @binaries = split /\n/, `find $dir -type f -perm -0100`;
+  my @bc_binaries;
+  foreach my $bin (@binaries) {
+    my $line = `/usr/bin/head -1 $bin` or next;
+    chomp $line;
+    push @bc_binaries, $line if $line eq $ocaml_magic_line;
+  }
+  return @bc_binaries;
 }
 
-# globals
-my %defined_md5sums;  # (unit name -> md5sum) mappings for units _defined_ by
-		      # package's objects
-my %imported_md5sums; # same mappings for units _imported_ by package's objects
-my %md5sums_registry; # parsed version of local md5sums registry
-my $registry_parsed = 0;  # flag used for lazy registry parsing
-
-# given as input a list of ocaml object filenames, fills
-# %{defin,import}ed_md5sums. Use ocamlobjinfo to retrieve md5sum information
-sub compute_md5sums(@) {
-  my @objects = @_;
-  my %md5sums;
-  foreach my $object (@objects) {
-    my $cmd = "$ocamlobjinfo $object";
-    verbose_print "\"$cmd\"";
-    open OBJINFO, "$cmd |" or error "can't execute \"$cmd\" for pipe-reading";
-    my $unit_name = "";
-    while (my $line = <OBJINFO>) {
+# read ocaml dependencies information from file and fill ocaml:Depends substvar
+sub fill_ocaml_depends($$) {
+  my ($package, $fname) = @_;
+  delsubstvar($package, "ocaml:Depends");
+  if (-f $fname) {
+    open DEPS, "< $fname" or die "Can't open $fname";
+    while (my $line = <DEPS>) {
       chomp $line;
-      if ($line =~ /^\s*Unit\s+name\s*:\s*(\w+)\s*$/) {
-	$unit_name = $1;
-# 	verbose_print "Unit $unit_name";
-      } elsif ($line =~ /^\s*([0-9A-Fa-f]{32})\s+(\w+)\s*$/) {
-	if ($2 eq $unit_name) {
-	  $defined_md5sums{$2} = $1;
-# 	  verbose_print "Defined $1 $2";
-	} else {
-	  $imported_md5sums{$2} = $1;
-# 	  verbose_print "Imported $1 $2";
-	}
-      }
+      my ($dep_package, $dep_version) = split /\s+/, $line;
+      next unless $dep_package and $dep_version;
+      addsubstvar($package, "ocaml:Depends", $dep_package, ">= $dep_version");
     }
-    close OBJINFO;
+    close DEPS;
   }
 }
 
-# create /var/lib/ocaml/md5sums/ entry and create post{inst,rm} scripts for
-# updating md5sums registry on users' machines
-sub add_md5sums_registry_entry($) {
-  my ($package) = @_;
+# main
+foreach my $package (@{$dh{DOPACKAGES}}) {
   my $tmpdir = tmpdir($package);
-  my $md5sums_fname = "$tmpdir$md5sums_dir/$package$md5sums_ext";
-  doit("mkdir -p " . dirname($md5sums_fname));
-  open MD5SUMS, "> $md5sums_fname";
-  foreach my $unit_name (sort (keys %defined_md5sums)) {
-    print MD5SUMS "$defined_md5sums{$unit_name} $unit_name\n";
-  }
-  close MD5SUMS;
-  if (! $dh{NOSCRIPTS}) {
+  isnative($package);	# sets $dh{VERSION}
+  my $flags = "--package $package --version $dh{VERSION}";
+  my $objinfo   = "debian/$package.ocamlobjinfo~";
+  my $objlist   = "debian/$package.ocamlobjects~";
+  my $ocamldeps = "debian/$package.ocamldeps~";
+  if ($package =~ /^lib.*-ocaml-dev$/) {  # ocaml library package
+      # create md5sum registry entry and post{inst,rm} scripts
+    complex_doit("/usr/bin/find $tmpdir$ocaml_lib_dir -type f -name '*.cm[ao]' "
+      . "> $objlist");
+    complex_doit("mkdir -p $tmpdir$md5sums_dir");
+    complex_doit("$ocaml_md5sums $flags --dump-info $objinfo compute < $objlist"
+      . " | /usr/bin/sort -k 2"  # optional pass, just for "pretty" printing
+      . " > $tmpdir$md5sums_dir/$package$md5sums_ext");
     my $sed = "s/#PACKAGE#/$package/; s/#VERSION#/$dh{VERSION}/";
     autoscript($package, "postinst", "postinst-ocaml", $sed);
     autoscript($package, "postrm", "postrm-ocaml", $sed);
-  }
-}
-
-# lazy parsing of md5sum registry /var/lib/ocaml/md5sums/MD5SUMS
-sub load_md5sum_registry() {
-  if (! $registry_parsed) {
-    open REGISTRY, $md5sums_registry_path;
-    my $lineno = 0;
-    while (my $line = <REGISTRY>) {
-      $lineno++;
-      chomp $line;
-      next if $line =~ /(^#)|(^\s*$)/;	# skip blank lines and comments
-      if ($line =~ /^([0-9A-Fa-f]{32})(\s+\S+){3}$/) {
-	my ($md5sum, $package, $version, $unit_name) = split /\s+/, $line;
-	# mappings like:
-	# "9b93712a344b3b9849a73ce19d8c72ce Foo_bar"->"libfoo-ocaml-dev 0.2.3-5"
-	my $key = "$md5sum $unit_name";
-	if (exists($md5sums_registry{$key})) {
-	  warning("multiple entries for $key in md5sums registry, "
-	    . "ocaml dependencies may be wrong");
-	}
-	$md5sums_registry{$key} = "$package $version";
-      } else {
-	warning
-	  "can't parse md5sums registry line ($md5sums_registry_path:$lineno)";
-	next;
-      }
+      # compute deps for the library
+    complex_doit("$ocaml_md5sums $flags --load-info $objinfo dep < $objlist"
+      . " > $ocamldeps");
+  } else {  # ocaml binary package
+    my @binaries = find_ocaml_bc_binaries($tmpdir);
+    complex_doit "> $ocamldeps";
+    foreach my $bin (@binaries) { # try to find .cmo of bc binaries
+      my $guess = basename($bin) . ".cm[ao]";
+      complex_doit("/usr/bin/find . -type f -name '$guess' >> $ocamldeps");
     }
-    close REGISTRY;
-    $registry_parsed = 1;
+    complex_doit("$ocaml_md5sums $flags dep < $objlist > $ocamldeps");
   }
+  fill_ocaml_depends($package, $ocamldeps);
 }
 
-sub lookup_dep($$) {
-  my ($md5sum, $unit_name) = @_;
-  load_md5sum_registry();
-  my $dep = $md5sums_registry{"$md5sum $unit_name"};
-  if ($dep) {
-    my ($deppackage, $version) = split /\s+/, $dep;
-    return($deppackage, ">= $version");
-  } else {
-    return(0, 0);
-  }
-}
-
-# compute dependencies of package using md5sum registry installed on the machine
-# which is building the package
-sub fill_substvars($) {
-  my ($package) = @_;
-  my $tmpdir = tmpdir($package);
-  delsubstvar($package, $dep_substvar); # idempotency
-  foreach my $unit_name (sort (keys %imported_md5sums)) {
-    next if exists $defined_md5sums{$unit_name};
-    my ($deppackage, $verinfo) =
-      lookup_dep($imported_md5sums{$unit_name}, $unit_name);
-    addsubstvar($package, $dep_substvar, $deppackage, $verinfo) if $deppackage;
-  }
-}
-
-foreach my $package (@{$dh{DOPACKAGES}}) {
-  next unless $package =~ /^lib.*-ocaml-dev$/;
-  isnative($package);	# sets $dh{VERSION}
-  my $tmpdir = tmpdir($package);
-  my @objects = find_objects($tmpdir);
-  compute_md5sums(@objects);  # fills %{defined,imported}_md5sums globals
-  add_md5sums_registry_entry($package);
-  fill_substvars($package);
-}
-
 =head1 SEE ALSO
 
-L<debhelper(7)>
+L<ocamlobjinfo(1)>, L<debhelper(7)>
 
 This program is a part of debhelper.