febootstrap: Use contents of installed Debian packages instead of downloading and...
authorHilko Bengen <bengen@hilluzination.de>
Mon, 12 Sep 2011 21:58:09 +0000 (23:58 +0200)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 23 Sep 2011 18:28:18 +0000 (19:28 +0100)
This also adds --use-installed switch (which for now only works for
Debian).

src/febootstrap.ml
src/febootstrap.pod
src/febootstrap_cmdline.ml
src/febootstrap_cmdline.mli
src/febootstrap_debian.ml
src/febootstrap_package_handlers.ml
src/febootstrap_package_handlers.mli
src/febootstrap_pacman.ml
src/febootstrap_yum_rpm.ml

index 7e48206..3afb1bb 100644 (file)
@@ -67,7 +67,7 @@ let () =
     List.flatten (
       List.map (
         fun pkg ->
     List.flatten (
       List.map (
         fun pkg ->
-          let files = ph.ph_list_files pkg in
+          let files = ph.ph_list_files ~use_installed pkg in
           List.map (fun (filename, ft) -> filename, ft, pkg) files
       ) packages
     ) in
           List.map (fun (filename, ft) -> filename, ft, pkg) files
       ) packages
     ) in
@@ -320,7 +320,7 @@ let () =
        * original file from the package.
        *)
       else if config then (
        * original file from the package.
        *)
       else if config then (
-        let outfile = ph.ph_get_file_from_package pkg path in
+        let outfile = ph.ph_get_file_from_package ~use_installed pkg path in
 
         (* Note that the output config file might not be a regular file. *)
         let statbuf = lstat outfile in
 
         (* Note that the output config file might not be a regular file. *)
         let statbuf = lstat outfile in
index ac97f48..68ad367 100644 (file)
@@ -96,6 +96,18 @@ output directory then they will be overwritten.
 Don't remove temporary files and directories on exit.  This is useful
 for debugging.
 
 Don't remove temporary files and directories on exit.  This is useful
 for debugging.
 
+=item B<--use-installed>
+
+If packages are already installed, use the contents (from the local
+filesystem) instead of downloading them.
+
+Note that this can cause malformed appliances if local files have been
+changed from what was originally in the package.  This is particularly
+a problem for configuration files.
+
+However this option is useful in some controlled situations: for
+example when using febootstrap inside a freshly installed chroot.
+
 =item B<-v>
 
 =item B<--verbose>
 =item B<-v>
 
 =item B<--verbose>
index 667e297..fc18bbd 100644 (file)
@@ -23,6 +23,7 @@ let names_mode = ref false
 let outputdir = ref "."
 let packages = ref []
 let save_temps = ref false
 let outputdir = ref "."
 let packages = ref []
 let save_temps = ref false
+let use_installed = ref false
 let verbose = ref false
 let warnings = ref true
 let yum_config = ref None
 let verbose = ref false
 let warnings = ref true
 let yum_config = ref None
@@ -50,6 +51,8 @@ let argspec = Arg.align [
     " Don't delete temporary files and directories on exit.";
   "--save-temps", Arg.Set save_temps,
     " Don't delete temporary files and directories on exit.";
     " Don't delete temporary files and directories on exit.";
   "--save-temps", Arg.Set save_temps,
     " Don't delete temporary files and directories on exit.";
+  "--use-installed", Arg.Set use_installed,
+    " Inspect already installed packages for determining contents.";
   "-v", Arg.Set verbose,
     " Enable verbose output";
   "--verbose", Arg.Set verbose,
   "-v", Arg.Set verbose,
     " Enable verbose output";
   "--verbose", Arg.Set verbose,
@@ -89,6 +92,7 @@ let names_mode = !names_mode
 let outputdir = !outputdir
 let packages = List.rev !packages
 let save_temps = !save_temps
 let outputdir = !outputdir
 let packages = List.rev !packages
 let save_temps = !save_temps
+let use_installed = !use_installed
 let verbose = !verbose
 let warnings = !warnings
 let yum_config = !yum_config
 let verbose = !verbose
 let warnings = !warnings
 let yum_config = !yum_config
index d948d80..a545012 100644 (file)
@@ -38,6 +38,9 @@ val packages : string list
 val save_temps : bool
   (** True if [--save-temps] was given on the command line. *)
 
 val save_temps : bool
   (** True if [--save-temps] was given on the command line. *)
 
+val use_installed : bool
+  (** True if [--use-installed] was given on the command line *)
+
 val verbose : bool
   (** True if [--verbose] was given on the command line.
       See also {!debug}. *)
 val verbose : bool
   (** True if [--verbose] was given on the command line.
       See also {!debug}. *)
index 23f3593..7482ed4 100644 (file)
@@ -28,6 +28,9 @@ open Febootstrap_cmdline
 (* Create a temporary directory for use by all the functions in this file. *)
 let tmpdir = tmpdir ()
 
 (* Create a temporary directory for use by all the functions in this file. *)
 let tmpdir = tmpdir ()
 
+let installed_pkgs =
+  run_command_get_lines "dpkg-query --show --showformat='${Package}\\n'"
+
 let debian_detect () =
   file_exists "/etc/debian_version" &&
     Config.aptitude <> "no" && Config.apt_cache <> "no" && Config.dpkg <> "no"
 let debian_detect () =
   file_exists "/etc/debian_version" &&
     Config.aptitude <> "no" && Config.apt_cache <> "no" && Config.dpkg <> "no"
@@ -51,18 +54,29 @@ let rec debian_resolve_dependencies_and_download names =
         not (List.exists (fun re -> Str.string_match re name 0) excludes)
     ) pkgs in
 
         not (List.exists (fun re -> Str.string_match re name 0) excludes)
     ) pkgs in
 
+  let present_pkgs, download_pkgs = List.partition (
+    fun pkg -> List.exists ((=) pkg) installed_pkgs
+  ) pkgs in
+
+  debug "wanted packages (present / download): %s / %s\n"
+    (String.concat " " present_pkgs)
+    (String.concat " " download_pkgs);
+
   (* Download the packages. *)
   (* Download the packages. *)
-  let cmd =
-    sprintf "umask 0000; cd %s && %s download %s"
-      (Filename.quote tmpdir)
-      Config.aptitude
-      (String.concat " " (List.map Filename.quote pkgs)) in
-  run_command cmd;
+  if (List.length download_pkgs > 0)
+  then (
+    let cmd =
+      sprintf "umask 0000; cd %s && %s download %s"
+        (Filename.quote tmpdir)
+        Config.aptitude
+        (String.concat " " (List.map Filename.quote download_pkgs)) in
+    run_command cmd
+  );
 
   (* Find out what aptitude downloaded. *)
   let files = Sys.readdir tmpdir in
 
 
   (* Find out what aptitude downloaded. *)
   let files = Sys.readdir tmpdir in
 
-  let pkgs = List.map (
+  let download_pkgs = List.map (
     fun pkg ->
       (* Look for 'pkg_*.deb' in the list of files. *)
       let pre = pkg ^ "_" in
     fun pkg ->
       (* Look for 'pkg_*.deb' in the list of files. *)
       let pre = pkg ^ "_" in
@@ -79,9 +93,9 @@ let rec debian_resolve_dependencies_and_download names =
        exit 1
       with
          Exit -> !r
        exit 1
       with
          Exit -> !r
-  ) pkgs in
+  ) download_pkgs in
 
 
-  List.sort compare pkgs
+  List.sort compare (List.append present_pkgs download_pkgs)
 
 (* On Ubuntu 10.04 LTS, apt-cache depends --recurse is broken.  It
  * doesn't return the full list of dependencies.  Therefore recurse
 
 (* On Ubuntu 10.04 LTS, apt-cache depends --recurse is broken.  It
  * doesn't return the full list of dependencies.  Therefore recurse
@@ -106,7 +120,7 @@ and workaround_broken_apt_cache_depends_recurse names =
   else
     names
 
   else
     names
 
-let debian_list_files pkg =
+let debian_list_files_downloaded pkg =
   debug "unpacking %s ..." pkg;
 
   (* We actually need to extract the file in order to get the
   debug "unpacking %s ..." pkg;
 
   (* We actually need to extract the file in order to get the
@@ -147,9 +161,38 @@ let debian_list_files pkg =
 
   files
 
 
   files
 
+let debian_list_files_installed pkg =
+  debug "using installed package %s ..." pkg;
+  let cmd = sprintf "dpkg-query --listfiles %s" pkg in
+  let lines = run_command_get_lines cmd in
+  (* filter out lines not directly describing fs objects such as
+     "package diverts others to: /path/to/..." *)
+  let lines = List.filter (
+    fun l -> l.[0] = '/' && l.[1] != '.'
+  ) lines in
+  let files = List.map (
+    fun path ->
+      let statbuf = lstat path in
+      let is_dir = statbuf.st_kind = S_DIR in
+      let config = statbuf.st_kind = S_REG && string_prefix "/etc/" path in
+      let mode = statbuf.st_perm in
+      (path, { ft_dir = is_dir; ft_config = config; ft_mode = mode;
+              ft_ghost = false; ft_size = statbuf.st_size })
+  ) lines in
+  files
+
+let debian_list_files ?(use_installed=false) pkg =
+  if use_installed && List.exists ((=) pkg) installed_pkgs then
+    debian_list_files_installed pkg
+  else
+    debian_list_files_downloaded pkg
+
 (* Easy because we already unpacked the archive above. *)
 (* Easy because we already unpacked the archive above. *)
-let debian_get_file_from_package pkg file =
-  tmpdir // pkg ^ ".d" // file
+let debian_get_file_from_package ?(use_installed=false) pkg file =
+  if use_installed && List.exists (fun p -> p = pkg) installed_pkgs then
+    file
+  else
+    tmpdir // pkg ^ ".d" // file
 
 let () =
   let ph = {
 
 let () =
   let ph = {
index ad3a233..f627d2f 100644 (file)
@@ -25,8 +25,8 @@ open Febootstrap_cmdline
 type package_handler = {
   ph_detect : unit -> bool;
   ph_resolve_dependencies_and_download : string list -> string list;
 type package_handler = {
   ph_detect : unit -> bool;
   ph_resolve_dependencies_and_download : string list -> string list;
-  ph_list_files : string -> (string * file_type) list;
-  ph_get_file_from_package : string -> string -> string
+  ph_list_files : ?use_installed:bool -> string -> (string * file_type) list;
+  ph_get_file_from_package : ?use_installed:bool -> string -> string -> string
 }
 and file_type = {
   ft_dir : bool;
 }
 and file_type = {
   ft_dir : bool;
index c28d81f..ebf0386 100644 (file)
@@ -31,11 +31,11 @@ type package_handler = {
 
       Note this should also process the [excludes] list. *)
 
 
       Note this should also process the [excludes] list. *)
 
-  ph_list_files : string -> (string * file_type) list;
+  ph_list_files : ?use_installed:bool -> string -> (string * file_type) list;
   (** [ph_list_files pkg] lists the files and file metadata in the
       package called [pkg] (a package file). *)
 
   (** [ph_list_files pkg] lists the files and file metadata in the
       package called [pkg] (a package file). *)
 
-  ph_get_file_from_package : string -> string -> string;
+  ph_get_file_from_package : ?use_installed:bool -> string -> string -> string;
   (** [ph_get_file_from_package pkg file] extracts the
       single named file [file] from [pkg].  The path of the
       extracted file is returned. *)
   (** [ph_get_file_from_package pkg file] extracts the
       single named file [file] from [pkg].  The path of the
       extracted file is returned. *)
index 6691ebe..657f4d7 100644 (file)
@@ -71,7 +71,10 @@ let pacman_resolve_dependencies_and_download names =
 
   List.sort compare pkgs
 
 
   List.sort compare pkgs
 
-let pacman_list_files pkg =
+let pacman_list_files ?(use_installed=false) pkg =
+  if use_installed then
+    failwith "pacman driver doesn't support --use-installed";
+
   debug "unpacking %s ..." pkg;
 
   (* We actually need to extract the file in order to get the
   debug "unpacking %s ..." pkg;
 
   (* We actually need to extract the file in order to get the
@@ -117,7 +120,10 @@ let pacman_list_files pkg =
   files
 
 (* Easy because we already unpacked the archive above. *)
   files
 
 (* Easy because we already unpacked the archive above. *)
-let pacman_get_file_from_package pkg file =
+let pacman_get_file_from_package ?(use_installed=false) pkg file =
+  if use_installed then
+    failwith "pacman driver doesn't support --use-installed";
+
   tmpdir // pkg ^ ".d" // file
 
 let () =
   tmpdir // pkg ^ ".d" // file
 
 let () =
index 028492a..815c5ba 100644 (file)
@@ -172,7 +172,10 @@ if verbose:
       sprintf "%s/%s-%s-%s.%s.rpm" tmpdir name version release arch
   ) pkgs
 
       sprintf "%s/%s-%s-%s.%s.rpm" tmpdir name version release arch
   ) pkgs
 
-let rec yum_rpm_list_files pkg =
+let rec yum_rpm_list_files ?(use_installed=false) pkg =
+  if use_installed then
+    failwith "yum_rpm driver doesn't support --use-installed";
+
   (* Run rpm -qlp with some extra magic. *)
   let cmd =
     sprintf "rpm -q --qf '[%%{FILENAMES} %%{FILEFLAGS:fflags} %%{FILEMODES} %%{FILESIZES}\\n]' -p %s"
   (* Run rpm -qlp with some extra magic. *)
   let cmd =
     sprintf "rpm -q --qf '[%%{FILENAMES} %%{FILEFLAGS:fflags} %%{FILEMODES} %%{FILESIZES}\\n]' -p %s"
@@ -228,7 +231,10 @@ let rec yum_rpm_list_files pkg =
 
   files
 
 
   files
 
-let yum_rpm_get_file_from_package pkg file =
+let yum_rpm_get_file_from_package ?(use_installed=false) pkg file =
+  if use_installed then
+    failwith "yum_rpm driver doesn't support --use-installed";
+
   debug "extracting %s from %s ..." file (Filename.basename pkg);
 
   let outfile = tmpdir // file in
   debug "extracting %s from %s ..." file (Filename.basename pkg);
 
   let outfile = tmpdir // file in