diff --git a/src/modules/unpackfs/main.py b/src/modules/unpackfs/main.py index 90c258cd7..fd3f97353 100644 --- a/src/modules/unpackfs/main.py +++ b/src/modules/unpackfs/main.py @@ -58,6 +58,9 @@ class UnpackEntry: self.copied = 0 self.total = 0 + def is_file(self): + return self.sourcefs == "file" + ON_POSIX = 'posix' in sys.builtin_module_names @@ -100,7 +103,7 @@ def file_copy(source, dest, progress_cb): # `source` *must* end with '/' otherwise a directory named after the source # will be created in `dest`: ie if `source` is "/foo/bar" and `dest` is # "/dest", then files will be copied in "/dest/bar". - if not source.endswith("/"): + if not source.endswith("/") and not os.path.isfile(source): source += "/" num_files_total_local = 0 @@ -225,11 +228,16 @@ class UnpackOperation: ["unsquashfs", "-l", entry.source] ) - if entry.sourcefs == "ext4": + elif entry.sourcefs == "ext4": fslist = subprocess.check_output( ["find", imgmountdir, "-type", "f"] ) + elif entry.is_file(): + # Hasn't been mounted, copy directly; find handles both + # files and directories. + fslist = subprocess.check_output(["find", entry.source, "-type", "f"]) + entry.total = len(fslist.splitlines()) self.report_progress() @@ -247,9 +255,15 @@ class UnpackOperation: """ Mount given image as loop device. + A *file* entry (e.g. one with *sourcefs* set to *file*) + is not mounted and just ignored. + :param entry: :param imgmountdir: """ + if entry.is_file(): + return + if os.path.isdir(entry.source): subprocess.check_call(["mount", "--bind", entry.source, @@ -287,12 +301,18 @@ class UnpackOperation: self.report_progress() try: - return file_copy(imgmountdir, entry.destination, progress_cb) + if entry.is_file(): + source = entry.source + else: + source = imgmountdir + + return file_copy(source, entry.destination, progress_cb) finally: - subprocess.check_call(["umount", "-l", imgmountdir]) + if not entry.is_file(): + subprocess.check_call(["umount", "-l", imgmountdir]) -def get_supported_filesystems(): +def get_supported_filesystems_kernel(): """ Reads /proc/filesystems (the list of supported filesystems for the current kernel) and returns a list of (names of) @@ -310,6 +330,14 @@ def get_supported_filesystems(): return [] +def get_supported_filesystems(): + """ + Returns a list of all the supported filesystems + (valid values for the *sourcefs* key in an item. + """ + return ["file"] + get_supported_filesystems_kernel() + + def run(): """ Unsquash filesystem. @@ -330,8 +358,7 @@ def run(): supported_filesystems = get_supported_filesystems() - unpack = list() - + # Bail out before we start when there are obvious problems for entry in job.configuration["unpack"]: source = os.path.abspath(entry["source"]) sourcefs = entry["sourcefs"] @@ -340,14 +367,18 @@ def run(): utils.warning("The filesystem for \"{}\" ({}) is not supported".format(source, sourcefs)) return (_("Bad unsquash configuration"), _("The filesystem for \"{}\" ({}) is not supported").format(source, sourcefs)) - - destination = os.path.abspath(root_mount_point + entry["destination"]) - if not os.path.exists(source): utils.warning("The source filesystem \"{}\" does not exist".format(source)) return (_("Bad unsquash configuration"), _("The source filesystem \"{}\" does not exist").format(source)) + unpack = list() + + for entry in job.configuration["unpack"]: + source = os.path.abspath(entry["source"]) + sourcefs = entry["sourcefs"] + destination = os.path.abspath(root_mount_point + entry["destination"]) + if not os.path.isdir(destination): utils.warning(("The destination \"{}\" in the target system is not a directory").format(destination)) return (_("Bad unsquash configuration"), diff --git a/src/modules/unpackfs/unpackfs.conf b/src/modules/unpackfs/unpackfs.conf index 9720f19a1..d994e351a 100644 --- a/src/modules/unpackfs/unpackfs.conf +++ b/src/modules/unpackfs/unpackfs.conf @@ -9,30 +9,59 @@ # target dir relative to rootMountPoint. --- -unpack: # Each list item is unpacked, in order, to the target system. +# # Each list item has the following attributes: # source: path relative to the live / intstalling system to the image -# sourcefs: ext4 or squashfs (may be others if mount supports it) +# sourcefs: the type of the source files; valid entries are +# - *ext4* (copies the filesystem contents) +# - *squashfs* (unsquashes) +# - *file* (copies a file or directory) +# - (may be others if mount supports it) # destination: path relative to rootMountPoint (so in the target -# system) where this filesystem is unpacked. - +# system) where this filesystem is unpacked. It may be an +# empty string, which effectively is / (the root) of the target +# system. +# +# EXAMPLES +# # Usually you list a filesystem image to unpack; you can use # squashfs or an ext4 image. # # - source: "/path/to/filesystem.sqfs" # sourcefs: "squashfs" # destination: "" - -# You can list more than one filesystem. +# +# Multiple entries are unpacked in-order # # - source: "/path/to/another/filesystem.img" # sourcefs: "ext4" # destination: "" +# - source: "/path/to/another/filesystem2.img" +# sourcefs: "ext4" +# destination: "/usr/lib/extra" # - # You can list filesystem source paths relative to the Calamares run # directory, if you use -d (this is only useful for testing, though). - - source: ./example.sqfs - sourcefs: squashfs - destination: "" +# +# - source: ./example.sqfs +# sourcefs: squashfs +# destination: "" +# +# You can list individual files (copied one-by-one), or directories +# (the files inside this directory are copied directly to the destination, +# so no "dummycpp/" subdirectory is created in this example). +# Do note that the target directory must exist already (e.g. from +# extracting some other filesystem). +# +# - source: ../CHANGES +# sourcefs: file +# destination: "/tmp/derp" +# - source: ../src/modules/dummycpp +# sourcefs: file +# destination: "/tmp/derp" + +unpack: + - source: ../CHANGES + sourcefs: file + destination: "/tmp"