Resolves: rhbz#982164, rhbz#994488
Sanitizes and post-processes --image arguments. Moves functionality
into a separate method.
Two problems fixed are:
994488 --- convert relative to absolute path
982164 --- check that path actually exists
Other differences from previous semantics are:
* Raises an exception if the name specified by the user contains a "/",
previously it just synthesized a name
* Certainly avoids name conflicts, previously just avoided likely ones
Signed-off-by: mulhern <amulhern(a)redhat.com>
---
anaconda | 27 ++++++++++-----------
pyanaconda/anaconda_optparse.py | 52 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/anaconda b/anaconda
index 8ec0363..677e818 100755
--- a/anaconda
+++ b/anaconda
@@ -1004,22 +1004,19 @@ if __name__ == "__main__":
if anaconda.displayMode == 'c':
flags.ksprompt = False
- image_count = 0
- for image in opts.images:
- image_spec = image.rsplit(":", 1)
- path = image_spec[0]
- if len(image_spec) == 2 and image_spec[1].strip():
- name = image_spec[1].strip()
- else:
- name = os.path.splitext(os.path.basename(path))[0]
+ from pyanaconda.anaconda_optparse import name_path_pairs
- if "/" in name or name in anaconda.storage.config.diskImages.keys():
- name = "diskimg%d" % image_count
-
- log.info("naming disk image '%s' '%s'" % (path, name))
- anaconda.storage.config.diskImages[name] = path
- image_count += 1
- flags.imageInstall = True
+ image_count = 0
+ try:
+ disk_image_counter = 0
+ for (name, path) in name_path_pairs(opts.images):
+ log.info("naming disk image '%s' '%s'" % (path,
name))
+ anaconda.storage.config.diskImages[name] = path
+ image_count += 1
+ flags.imageInstall = True
+ except ValueError as e:
+ stdoutLog.error("error specifying image file: %s" % e)
+ sys.exit(0)
if image_count:
anaconda.storage.setupDiskImages()
diff --git a/pyanaconda/anaconda_optparse.py b/pyanaconda/anaconda_optparse.py
index 37f4b86..bcaab81 100644
--- a/pyanaconda/anaconda_optparse.py
+++ b/pyanaconda/anaconda_optparse.py
@@ -19,6 +19,9 @@
# Authors:
# Will Woods <wwoods(a)redhat.com>
+import itertools
+import os
+
from flags import BootArgs
from optparse import OptionParser, OptionConflictError
@@ -124,3 +127,52 @@ class AnacondaOptionParser(OptionParser):
values = self.get_default_values()
v = self.parse_boot_cmdline(cmdline, values)
return OptionParser.parse_args(self, args, v)
+
+def name_path_pairs(image_specs):
+ """Processes and verifies image file specifications. Generates pairs
+ of names and paths.
+
+ If no name given in specification, synthesizes name from basename
+ of path. Since two distinct paths may have the same basename, handles
+ name collisions by synthesizing a different name for the colliding
+ name.
+
+ :param image_specs: a list of image specifications
+ :type image_specs: list of str
+
+ Raises an exception if:
+ * A path is empty
+ * A path specifies a non-existant file
+ * A path specifies a directory
+ * Duplicate paths are specified
+ * A name contains a "/"
+ """
+ image_specs = (spec.rsplit(":", 1) for spec in image_specs)
+ path_name_pairs = ((image_spec[0], image_spec[1].strip() if len(image_spec) == 2 else
None) for image_spec in image_specs)
+
+ paths_seen = []
+ names_seen = []
+ for (path, name) in path_name_pairs:
+ if path == "":
+ raise ValueError("empty path specified for image file")
+ path = os.path.abspath(path)
+ if not os.path.exists(path):
+ raise ValueError("non-existant path %s specified for image file" %
path)
+ if os.path.isdir(path):
+ raise ValueError("directory path %s specified for image file" %
path)
+ if path in paths_seen:
+ raise ValueError("path %s specified twice for image file" % path)
+ paths_seen.append(path)
+
+ if name and "/" in name:
+ raise ValueError("improperly formatted image file name %s, includes
slashes" % name)
+
+ if not name:
+ name = os.path.splitext(os.path.basename(path))[0]
+
+ if name in names_seen:
+ names = ("%s_%d" % (name, n) for n in itertools.count())
+ name = itertools.dropwhile(lambda n: n in names_seen, names).next()
+ names_seen.append(name)
+
+ yield name, path
--
1.8.3.1