[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH] handle --use-installed in zypp driver



An attempt to use installed files in zypp driver.
Add also a comment about the theory of operation.
Enable set -x in shell only in verbose mode.
This adds a dependency to xmlstarlet, which is required to parse zypper output.

Signed-off-by: Olaf Hering <olaf aepfle de>
---
 src/supermin_zypp_rpm.ml | 93 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 80 insertions(+), 13 deletions(-)

diff --git a/src/supermin_zypp_rpm.ml b/src/supermin_zypp_rpm.ml
index 2089837..720f50a 100644
--- a/src/supermin_zypp_rpm.ml
+++ b/src/supermin_zypp_rpm.ml
@@ -18,6 +18,31 @@
 
 (* Zypper and RPM support. *)
 
+(*
+ * Theory of operation:
+ * called as root:
+ *  - without --use-installed:
+ *    ->ph_resolve_dependencies_and_download() returns a list of filenames
+ *    Need to download all packages into an empty --root directory so that
+ *    zypper places all dependencies into --pkg-cache-dir
+ *  - with --use-installed:
+ *    ->ph_resolve_dependencies_and_download() returns a list of package names
+ *    Need to work with an empty --root directory so that zypper can list
+ *    all dependencies of "names". This mode assumes that all required packages
+ *    are installed and the system is consistent. Downloading just the missing 
+ *    packages is not implemented.
+ * called as non-root:
+ *    (Due to the usage of --root zypper does not require root permissions.)
+ *  - without --use-installed:
+ *    Same as above.
+ *  - with --use-installed:
+ *    Same as above.
+ *
+ * The usage of --packager-config is tricky: If --root is used zypper assumes
+ * that every config file is below <rootdir>. So the config has to be parsed
+ * and relevant files/dirs should be copied into <rootdir> so that zypper can
+ * use the specified config.
+ *)
 open Unix
 open Printf
 
@@ -34,15 +59,15 @@ let zypp_rpm_detect () =
     Config.zypper <> "no" && Config.rpm <> "no"
 
 let zypp_rpm_init () =
-  if use_installed && Unix.getuid() > 0 then
-    failwith "zypp_rpm driver doesn't support --use-installed when called as non-root user"
+  if use_installed then
+    eprintf "supermin: zypp_rpm driver assumes all packages are already installed when called with option --use-installed.\n%!"
 
-let zypp_rpm_resolve_dependencies_and_download names =
+let zypp_rpm_resolve_dependencies_and_download_no_installed names =
   (* Liberate this data from shell. *)
   let tmp_pkg_cache_dir = tmpdir // "pkg_cache_dir" in
   let tmp_root = tmpdir // "root" in
   let sh = sprintf "
-set -ex
+%s
 unset LANG ${!LC_*}
 tmpdir=%S
 cache_dir=\"${tmpdir}/cache-dir\"
@@ -60,6 +85,7 @@ time zypper \
 	--download-only \
 	$@
 "
+    (if verbose then "set -x" else "")
     tmpdir
     tmp_pkg_cache_dir
     (if verbose then "--verbose --verbose" else "--quiet")
@@ -96,10 +122,47 @@ time zypper \
   (* Return list of package filenames. *)
   pkgs
 
+let zypp_rpm_resolve_dependencies_and_download_use_installed names =
+  let cmd = sprintf "
+%s
+unset LANG ${!LC_*}
+zypper \
+	%s \
+	%s \
+	--root %S --reposd-dir /dev/shm/supermin/zypp/repos.d \
+	--cache-dir %S \
+	--gpg-auto-import-keys \
+	--non-interactive \
+	--xml \
+	install \
+	--auto-agree-with-licenses \
+	--dry-run \
+	%s | \
+	xml sel -t \
+	-m \"stream/install-summary/to-install/solvable[% type='package']\" \
+	-c \"string(% name)\" -n
+"
+    (if verbose then "set -x" else "")
+    (if verbose then "--verbose --verbose" else "--quiet")
+    (match packager_config with None -> ""
+     | Some filename -> sprintf "--config %s" filename)
+    tmpdir tmpdir (String.concat " " (List.map Filename.quote names)) in
+  let pkg_names = run_command_get_lines cmd in
+
+  (* Return list of package names, remove empty lines. *)
+  List.filter (fun s -> s <> "") pkg_names
+
+let zypp_rpm_resolve_dependencies_and_download names =
+  if use_installed then
+    zypp_rpm_resolve_dependencies_and_download_use_installed names
+  else
+    zypp_rpm_resolve_dependencies_and_download_no_installed names
+
 let rec zypp_rpm_list_files pkg =
   (* Run rpm -qlp with some extra magic. *)
   let cmd =
-    sprintf "rpm -q --qf '[%%{FILENAMES} %%{FILEFLAGS:fflags} %%{FILEMODES} %%{FILESIZES}\\n]' -p %S"
+    sprintf "rpm -q --qf '[%%{FILENAMES} %%{FILEFLAGS:fflags} %%{FILEMODES} %%{FILESIZES}\\n]' %s %S"
+      (if use_installed then "" else "-p")
       pkg in
   let lines = run_command_get_lines cmd in
 
@@ -153,14 +216,18 @@ let rec zypp_rpm_list_files pkg =
   files
 
 let zypp_rpm_get_file_from_package pkg file =
-  debug "extracting %s from %s ..." file (Filename.basename pkg);
-
-  let outfile = tmpdir // file in
-  let cmd =
-    sprintf "umask 0000; rpm2cpio %s | (cd %s && cpio --quiet -id .%s)"
-      (Filename.quote pkg) (Filename.quote tmpdir) (Filename.quote file) in
-  run_command cmd;
-  outfile
+  if use_installed then
+    file
+  else (
+    debug "extracting %s from %s ..." file (Filename.basename pkg);
+
+    let outfile = tmpdir // file in
+    let cmd =
+      sprintf "umask 0000; rpm2cpio %s | (cd %s && cpio --quiet -id .%s)"
+        (Filename.quote pkg) (Filename.quote tmpdir) (Filename.quote file) in
+    run_command cmd;
+    outfile
+    )
 
 let () =
   let ph = {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]