Hello community,

here is the log from the commit of package virt-bootstrap for openSUSE:Factory 
checked in at 2018-06-02 12:12:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/virt-bootstrap (Old)
 and      /work/SRC/openSUSE:Factory/.virt-bootstrap.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "virt-bootstrap"

Sat Jun  2 12:12:32 2018 rev:4 rq:613269 version:1.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/virt-bootstrap/virt-bootstrap.changes    
2018-02-16 21:45:53.456450650 +0100
+++ /work/SRC/openSUSE:Factory/.virt-bootstrap.new/virt-bootstrap.changes       
2018-06-02 12:13:11.601689959 +0200
@@ -1,0 +2,13 @@
+Thu May 31 11:43:16 UTC 2018 - cbosdon...@suse.com
+
+- Release 1.1.0
+ * safe_untar: check for permissions to set attribs
+ * docker source, support blobs without .tar extension
+ * docker-source, preserve extended file attributes
+ * docker-source, get list of layers without `--raw`
+ * docker-source, void skopeo copy in cache
+ * Show error when guestfs-python or skopeo is not installed
+ * pylint cleanups
+
+
+-------------------------------------------------------------------

Old:
----
  virt-bootstrap-1.0.0.tar.gz

New:
----
  virt-bootstrap-1.1.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ virt-bootstrap.spec ++++++
--- /var/tmp/diff_new_pack.4eTBOQ/_old  2018-06-02 12:13:12.213667512 +0200
+++ /var/tmp/diff_new_pack.4eTBOQ/_new  2018-06-02 12:13:12.217667365 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           virt-bootstrap
-Version:        1.0.0
+Version:        1.1.0
 Release:        0
 Summary:        System container rootfs creation tool
 License:        GPL-3.0+

++++++ virt-bootstrap-1.0.0.tar.gz -> virt-bootstrap-1.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virt-bootstrap-1.0.0/ChangeLog 
new/virt-bootstrap-1.1.0/ChangeLog
--- old/virt-bootstrap-1.0.0/ChangeLog  2017-09-07 16:48:36.000000000 +0200
+++ new/virt-bootstrap-1.1.0/ChangeLog  2018-05-31 13:34:38.000000000 +0200
@@ -1,3 +1,239 @@
+2018-05-31 Cédric Bosdonnat  <cbosdon...@suse.com>
+    
+    Update NEWS file
+    
+    
+2018-05-31 Cédric Bosdonnat  <cbosdon...@suse.com>
+    
+    Bump version to 1.1.0
+    
+    
+2018-04-28 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    safe_untar: Check for permissions to set attribs
+    Make sure we have permissions to restore file extended attributes.
+    
+    [1] ... all processes have read access to extended security attributes,
+    and write access is limited to processes that have the CAP_SYS_ADMIN
+    capability.
+    
+    [2] The file owner and processes capable of CAP_FOWNER are granted the
+    right to modify ACLs of a file. This is analogous to the permissions
+    required for accessing the file mode. (On current Linux systems, root
+    is the only user with the CAP_FOWNER capability.)
+    
+    [1] https://linux.die.net/man/5/attr
+    [2] https://linux.die.net/man/1/setfacl
+    
+    
+    
+2018-04-28 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    docker-source: Support blobs without .tar ext
+    Since skopeo v0.1.29 [1] blobs are saved without the .tar extension.
+    This commit changes the docker-source module to handle both cases (with
+    or without .tar extension)
+    
+    [1] commit: projectatomic/skopeo@43acc74
+    Fix skopeo tests with changes to dir transport
+    
+    The dir transport has been changed to save the blobs without the .tar 
extension
+    Fixes the skopeo tests failing due to this change
+    
+    
+    
+2018-04-24 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    tests: fix typo
+    
+    
+2018-04-24 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    Revert "docker-source: Support blobs without .tar ext"
+    This reverts commit 6146e9ab5e36ff894b8c95d00a45db6181ad8472.
+    
+    
+2018-04-10 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    docker-source: Preserve extended file attributes
+    Preserve extended file attributes of extracted rootfs as described in
+    https://github.com/opencontainers/image-spec/blob/master/layer.md
+    
+    
+    
+2018-04-10 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    tests: docker_source: Update description
+    
+    
+2018-04-10 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    docker-source: Support blobs without .tar ext
+    Since skopeo v0.1.29 blobs are saved without the .tar extension.
+    
+    See commit: projectatomic/skopeo@43acc74
+    Fix skopeo tests with changes to dir transport
+    
+    The dir transport has been changed to save the blobs without the .tar 
extension
+    Fixes the skopeo tests failing due to this change
+    
+    
+    
+2018-04-10 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    tests: docker_source: Remove unused code
+    
+    
+2018-04-10 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    tests: docker_source: Mock out is_installed()
+    Commit b38f588 (source-docker: Show error if skopeo not installed)
+    introduced a check used by Docker-souce to verify that skopeo is
+    installed. However, the unit test cases in TestDockerSource do not
+    aim to ensure that skopeo is installed and therefore this check is
+    redundant.
+    
+    
+    
+2018-03-12 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    setup: Use pylint/pycodestyle modules
+    Use pylint/pycodestyle modules instead of calling the executables
+    to ensure that Python 3 code is checked with Py 3 version of
+    pylint/pycodestyle.
+    
+    
+    
+2018-03-01 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    setup: Use pylint-3 and pycodestyle-3
+    
+    
+2018-03-01 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    pylint: Resolve similar lines
+    This patch resolves the following pylint warning:
+    
+    R:  1, 0: Similar lines in 2 files
+    ==virtBootstrap.sources.docker_source:306
+    ==virtBootstrap.sources.file_source:87
+    dest,
+    self.uid_map,
+    self.gid_map,
+    (self.root_password is None)  # Create new disk?
+    )
+    
+    else:
+    raise Exception("Unknown format:" + self.output_format)
+    (duplicate-code)
+    R:  1, 0: Similar lines in 2 files
+    ==virtBootstrap.sources.file_source:50
+    ==virtBootstrap.sources.virt_builder_source:58
+    self.output_format = kwargs.get('fmt', utils.DEFAULT_OUTPUT_FORMAT)
+    self.uid_map = kwargs.get('uid_map', [])
+    self.gid_map = kwargs.get('gid_map', [])
+    self.root_password = kwargs.get('root_password', None)
+    self.progress = kwargs['progress'].update_progress
+    (duplicate-code)
+    
+    
+    
+2018-03-01 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    pylint: Resolve logging-not-lazy
+    Specify string format arguments as logging function parameters
+    (logging-not-lazy)
+    
+    https://docs.python.org/3/library/logging.html#logging.Logger.debug
+    
+    
+    
+2018-03-01 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    pylint: Resolve - two spaces before comment
+    E261 at least two spaces before inline comment
+    
+    
+    
+2018-03-01 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    pylint: Resolve test for membership
+    E713 test for membership should be 'not in'
+    
+    
+    
+2018-03-01 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    tests: Add empty line at the end of file
+    Resolves pylint: "W292 no newline at end of file"
+    
+    
+2018-03-01 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    pylint: Provide modules instead of files
+    We should give Pylint the name of a python package or module. [1]
+    
+    A python module is a file containing Python definitions and statements
+    or directory containing the input script (__init__.py) [2]
+    
+    1: 
https://pylint.readthedocs.io/en/latest/user_guide/run.html#invoking-pylint
+    2: https://docs.python.org/2/tutorial/modules.html
+    
+    
+    
+2017-12-18 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    docker-source: Get list of layers without `--raw`
+    When `skopeo inspect --raw docker://feodra` is used the returned
+    manifest content contains a list with manifests for specific
+    platforms [1] rather than a list with layers.
+    
+    By using `skopeo inpect docker://fedora` the correct manifest
+    content is retrieved and a list with layers is provided. In addition,
+    skopeo handles the difference between schemaVersion 1 and 2.
+    
+    [1] 
https://docs.docker.com/registry/spec/manifest-v2-2/#manifest-list-field-descriptions
+    
+    
+2017-12-12 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    docker-source: Avoid skopeo copy in cache
+    The `skopeo copy` command has changed it's behaviour to keep only a files 
for
+    single container image per directory. To get around this and keep cache of
+    downloaded images is used temporary destination directory for 'skopeo copy'
+    and image files are then moved in the cache folder.
+    
+    
+2017-11-21 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    source-docker: Show error if skopeo not installed
+    Show appropriate error message when skopeo is not installed.
+    
+    
+2017-11-21 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    Show error when guestfs-python is not installed
+    Show appropriate error message when the python bindings for
+    libguestfs are not installed.
+    
+    
+2017-11-21 Radostin Stoyanov  <rstoyan...@gmail.com>
+    
+    utils: Add is_installed function
+    Add utility function to check whether an executable is available in
+    the PATH env variable.
+    
+    
+2017-09-07 Cédric Bosdonnat  <cbosdon...@suse.com>
+    
+    NEWS: fix formatting
+    
+    
+2017-09-07 Cédric Bosdonnat  <cbosdon...@suse.com>
+    
+    Add NEWS files
+    
+    
 2017-09-07 Cédric Bosdonnat  <cbosdon...@suse.com>
     
     Bump version to 1.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virt-bootstrap-1.0.0/MANIFEST.in 
new/virt-bootstrap-1.1.0/MANIFEST.in
--- old/virt-bootstrap-1.0.0/MANIFEST.in        2017-09-07 11:49:40.000000000 
+0200
+++ new/virt-bootstrap-1.1.0/MANIFEST.in        2017-09-07 17:30:45.000000000 
+0200
@@ -1,4 +1,4 @@
-include README.md LICENSE ChangeLog AUTHORS
+include README.md LICENSE ChangeLog AUTHORS NEWS.md
 recursive-include src *.py
 recursive-include tests *.py
 recursive-include man *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virt-bootstrap-1.0.0/NEWS.md 
new/virt-bootstrap-1.1.0/NEWS.md
--- old/virt-bootstrap-1.0.0/NEWS.md    1970-01-01 01:00:00.000000000 +0100
+++ new/virt-bootstrap-1.1.0/NEWS.md    2018-05-31 13:32:45.000000000 +0200
@@ -0,0 +1,15 @@
+# Virt Bootstrap News
+
+## Release 1.1.0 (May 31, 2018)
+
+ * safe_untar: check for permissions to set attribs
+ * docker source, support blobs without .tar extension
+ * docker-source, preserve extended file attributes
+ * docker-source, get list of layers without `--raw`
+ * docker-source, void skopeo copy in cache
+ * Show error when guestfs-python or skopeo is not installed
+ * pylint cleanups
+
+## Release 1.0.0 (Sep 07, 2017)
+
+ * Initial release
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virt-bootstrap-1.0.0/PKG-INFO 
new/virt-bootstrap-1.1.0/PKG-INFO
--- old/virt-bootstrap-1.0.0/PKG-INFO   2017-09-07 16:48:36.000000000 +0200
+++ new/virt-bootstrap-1.1.0/PKG-INFO   2018-05-31 13:34:38.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
 Name: virt-bootstrap
-Version: 1.0.0
+Version: 1.1.0
 Summary: Container bootstrapping tool
 Home-page: https://github.com/virt-manager/virt-bootstrap
 Author: Cedric Bosdonnat
@@ -52,3 +52,4 @@
 Classifier: License :: OSI Approved :: GNU General Public License v3 or later 
(GPLv3+)
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 3
+Provides-Extra: dev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virt-bootstrap-1.0.0/setup.py 
new/virt-bootstrap-1.1.0/setup.py
--- old/virt-bootstrap-1.0.0/setup.py   2017-09-07 16:23:22.000000000 +0200
+++ new/virt-bootstrap-1.1.0/setup.py   2018-03-12 11:03:10.000000000 +0100
@@ -94,25 +94,30 @@
         """
         Call pycodestyle and pylint here.
         """
+        import pylint.lint
+        import pycodestyle
 
-        res = 0
-        files = ' '.join(["setup.py", "src/virtBootstrap/*.py", "tests/*.py"])
+        files = ["setup.py", "src/virtBootstrap/", "tests/"]
         output_format = "colorized" if sys.stdout.isatty() else "text"
 
         print(">>> Running pycodestyle ...")
-        cmd = "pycodestyle "
-        if (subprocess.call(cmd + files, shell=True) != 0):
-            res = 1
+
+        style_guide = pycodestyle.StyleGuide(paths=files)
+        report = style_guide.check_files()
+        if style_guide.options.count:
+            sys.stderr.write(str(report.total_errors) + '\n')
 
         print(">>> Running pylint ...")
-        args = ""
+
+        pylint_opts = [
+            "--rcfile", "pylintrc",
+            "--output-format=%s" % output_format
+        ]
+
         if self.errors_only:
-            args = "-E"
-        cmd = "pylint %s --output-format=%s " % (args, format(output_format))
-        if (subprocess.call(cmd + files, shell=True) != 0):
-            res = 1
+            pylint_opts.append("-E")
 
-        sys.exit(res)
+        pylint.lint.Run(files + pylint_opts)
 
 
 # SdistCommand is reused from the libvirt python binding (GPLv2+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/virt-bootstrap-1.0.0/src/virtBootstrap/sources/docker_source.py 
new/virt-bootstrap-1.1.0/src/virtBootstrap/sources/docker_source.py
--- old/virt-bootstrap-1.0.0/src/virtBootstrap/sources/docker_source.py 
2017-09-07 11:49:01.000000000 +0200
+++ new/virt-bootstrap-1.1.0/src/virtBootstrap/sources/docker_source.py 
2018-05-31 13:03:07.000000000 +0200
@@ -62,6 +62,10 @@
             [[<start>, <target>, <count>], [<start>, <target>, <count>] ...]
         """
 
+        # Check if skopeo is installed
+        if not utils.is_installed('skopeo'):
+            raise RuntimeError('skopeo is not installed')
+
         self.url = self.gen_valid_uri(kwargs['uri'])
         self.username = kwargs.get('username', None)
         self.password = kwargs.get('password', None)
@@ -73,7 +77,7 @@
         self.no_cache = kwargs.get('no_cache', False)
         self.progress = kwargs['progress'].update_progress
         self.images_dir = utils.get_image_dir(self.no_cache)
-        self.manifest = None
+        self.image_details = None
         self.layers = []
         self.checksums = []
 
@@ -87,30 +91,25 @@
         Retrive manifest from registry and get layers' digest,
         sum_type, size and file_path in a list.
         """
-        self.manifest = utils.get_image_details(self.url, raw=True,
+        image_details = utils.get_image_details(self.url, raw=False,
                                                 insecure=self.insecure,
                                                 username=self.username,
                                                 password=self.password)
 
-        if self.manifest['schemaVersion'] == 1:
-            layers_list = self.manifest['fsLayers'][::-1]
-            digest_field = 'blobSum'
-        elif self.manifest['schemaVersion'] == 2:
-            layers_list = self.manifest['layers']
-            digest_field = 'digest'
-        else:
-            raise ValueError('Unsupported manifest schema.')
+        if 'Layers' not in image_details or not image_details['Layers']:
+            raise ValueError('No image layers.')
 
-        for layer in layers_list:
-            # Store checksums of layers
-            layer_digest = layer[digest_field]
+        # Layers are in order:
+        # - root layer first, and then successive layered layers
+        # Ref: https://github.com/containers/image/blob/master/image/oci.go
+        for layer_digest in image_details['Layers']:
             sum_type, layer_sum = layer_digest.split(':')
-            self.checksums.append([sum_type, layer_sum])
+            self.checksums.append([sum_type, layer_sum])  # Store checksums
 
-            # Store file path and size of each layer
-            file_path = os.path.join(self.images_dir, layer_sum + '.tar')
-            layer_size = layer.get('size', None)
-            self.layers.append([file_path, layer_size])
+            # Layers are tar files with hashsum used as name
+            file_path = os.path.join(self.images_dir, layer_sum)
+            # Store 'file path' and set placeholder for 'size'
+            self.layers.append([file_path, None])
 
     def gen_valid_uri(self, uri):
         """
@@ -133,10 +132,16 @@
         """
         Download image layers using "skopeo copy".
         """
+
+        if self.no_cache:
+            dest_dir = self.images_dir
+        else:
+            dest_dir = utils.get_image_dir(no_cache=True)
+
         # Note: we don't want to expose --src-cert-dir to users as
         #       they should place the certificates in the system
         #       folders for broader enablement
-        skopeo_copy = ["skopeo", "copy", self.url, "dir:" + self.images_dir]
+        skopeo_copy = ["skopeo", "copy", self.url, "dir:" + dest_dir]
 
         if self.insecure:
             skopeo_copy.append('--src-tls-verify=false')
@@ -146,8 +151,23 @@
         self.progress("Downloading container image", value=0, logger=logger)
         # Run "skopeo copy" command
         self.read_skopeo_progress(skopeo_copy)
-        # Remove the manifest file as it is not needed
-        os.remove(os.path.join(self.images_dir, "manifest.json"))
+
+        if not self.no_cache:
+            os.remove(os.path.join(dest_dir, "manifest.json"))
+            os.remove(os.path.join(dest_dir, "version"))
+            utils.copytree(dest_dir, self.images_dir)
+            shutil.rmtree(dest_dir)
+
+        # Old versions of skopeo use '.tar' extension to blobs.
+        # Make sure we use the correct file name.
+        for i in range(len(self.layers)):
+            path = self.layers[i][0]
+            if not os.path.exists(path):
+                if os.path.exists(path + '.tar'):
+                    self.layers[i][0] += '.tar'
+                else:
+                    raise ValueError('Blob %s does not exist.' % path)
+
 
     def parse_output(self, proc):
         """
@@ -249,8 +269,14 @@
             sum_type, sum_expected = checksum
 
             logger.debug("Checking layer: %s", path)
-            if not (os.path.exists(path)
+            if (os.path.exists(path)
                     and utils.checksum(path, sum_type, sum_expected)):
+                continue
+            if (not path.endswith('.tar')
+                    and os.path.exists(path + '.tar')
+                    and utils.checksum(path + '.tar', sum_type, sum_expected)):
+                self.layers[index][0] += '.tar'
+            else:
                 return False
         return True
 
@@ -295,8 +321,7 @@
                     logger.info("Mapping UID/GID")
                     utils.map_id_in_image(
                         len(self.layers),  # Number of layers
-                        dest,
-                        self.uid_map,
+                        dest, self.uid_map,
                         self.gid_map,
                         (self.root_password is None)  # Create new disk?
                     )
@@ -310,7 +335,7 @@
         else:
             self.progress("Download and extract completed!", value=100,
                           logger=logger)
-            logger.info("Files are stored in: " + dest)
+            logger.info("Files are stored in: %s", dest)
 
         finally:
             # Clean up
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/virt-bootstrap-1.0.0/src/virtBootstrap/sources/file_source.py 
new/virt-bootstrap-1.1.0/src/virtBootstrap/sources/file_source.py
--- old/virt-bootstrap-1.0.0/src/virtBootstrap/sources/file_source.py   
2017-09-07 11:49:01.000000000 +0200
+++ new/virt-bootstrap-1.1.0/src/virtBootstrap/sources/file_source.py   
2018-03-12 11:03:01.000000000 +0100
@@ -49,9 +49,9 @@
         """
         self.path = kwargs['uri'].path
         self.output_format = kwargs.get('fmt', utils.DEFAULT_OUTPUT_FORMAT)
+        self.root_password = kwargs.get('root_password', None)
         self.uid_map = kwargs.get('uid_map', [])
         self.gid_map = kwargs.get('gid_map', [])
-        self.root_password = kwargs.get('root_password', None)
         self.progress = kwargs['progress'].update_progress
 
     def unpack(self, dest):
@@ -85,9 +85,7 @@
                 logger.info("Mapping UID/GID")
                 utils.map_id_in_image(
                     1,  # Number of layers
-                    dest,
-                    self.uid_map,
-                    self.gid_map,
+                    dest, self.uid_map, self.gid_map,
                     (self.root_password is None)  # Create new disk?
                 )
 
@@ -96,4 +94,4 @@
 
         self.progress("Extraction completed successfully!", value=100,
                       logger=logger)
-        logger.info("Files are stored in: " + dest)
+        logger.info("Files are stored in: %s", dest)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virt-bootstrap-1.0.0/src/virtBootstrap/utils.py 
new/virt-bootstrap-1.1.0/src/virtBootstrap/utils.py
--- old/virt-bootstrap-1.0.0/src/virtBootstrap/utils.py 2017-09-07 
11:49:01.000000000 +0200
+++ new/virt-bootstrap-1.1.0/src/virtBootstrap/utils.py 2018-05-31 
13:03:07.000000000 +0200
@@ -32,10 +32,16 @@
 import sys
 import tempfile
 import logging
+import shutil
 
-import guestfs
 import passlib.hosts
 
+try:
+    import guestfs
+except ImportError:
+    raise RuntimeError('Python bindings for libguestfs are not installed')
+
+
 # pylint: disable=invalid-name
 # Create logger
 logger = logging.getLogger(__name__)
@@ -274,6 +280,10 @@
     # qemu:/// driver. This flag must not be used outside virt-sandbox.
     params = ['--', '/bin/tar', 'xf', src, '-C', '/mnt', '--exclude', 'dev/*',
               '--overwrite', '--absolute-names']
+    # Preserve file attributes following the specification in
+    # https://github.com/opencontainers/image-spec/blob/master/layer.md
+    if os.geteuid() == 0:
+        params.extend(['--acls', '--xattrs', '--selinux'])
     execute(virt_sandbox + params)
 
 
@@ -350,6 +360,19 @@
         return output.read().decode('utf-8').split()[1]
 
 
+def copytree(src, dst, symlinks=False, ignore=None):
+    """
+    Copy an entire directory of files into an existing directory.
+    """
+    for item in os.listdir(src):
+        src_item = os.path.join(src, item)
+        dst_item = os.path.join(dst, item)
+        if os.path.isdir(src_item):
+            shutil.copytree(src_item, dst_item, symlinks, ignore)
+        else:
+            shutil.copy2(src_item, dst_item)
+
+
 def get_image_dir(no_cache=False):
     """
     Get the directory where image layers are stored.
@@ -646,3 +669,16 @@
     balance_uid_gid_maps(uid_map, gid_map)
     for uid, gid in zip(uid_map, gid_map):
         map_id(dest, uid, gid)
+
+
+def is_installed(program):
+    """
+    Try to find executable listed in the PATH env variable.
+
+    Returns the complete filename or None if not found.
+    """
+    for path in os.environ["PATH"].split(os.pathsep):
+        exec_file = os.path.join(path, program)
+        if os.path.isfile(exec_file) and os.access(exec_file, os.X_OK):
+            return exec_file
+    return None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/virt-bootstrap-1.0.0/src/virtBootstrap/virt_bootstrap.py 
new/virt-bootstrap-1.1.0/src/virtBootstrap/virt_bootstrap.py
--- old/virt-bootstrap-1.0.0/src/virtBootstrap/virt_bootstrap.py        
2017-09-07 16:23:22.000000000 +0200
+++ new/virt-bootstrap-1.1.0/src/virtBootstrap/virt_bootstrap.py        
2018-05-31 13:14:57.000000000 +0200
@@ -38,7 +38,7 @@
 from virtBootstrap import utils
 
 
-__version__ = "1.0.0"
+__version__ = "1.1.0"
 
 
 gettext.bindtextdomain("virt-bootstrap", "/usr/share/locale")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/virt-bootstrap-1.0.0/src/virt_bootstrap.egg-info/PKG-INFO 
new/virt-bootstrap-1.1.0/src/virt_bootstrap.egg-info/PKG-INFO
--- old/virt-bootstrap-1.0.0/src/virt_bootstrap.egg-info/PKG-INFO       
2017-09-07 16:48:36.000000000 +0200
+++ new/virt-bootstrap-1.1.0/src/virt_bootstrap.egg-info/PKG-INFO       
2018-05-31 13:34:38.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
 Name: virt-bootstrap
-Version: 1.0.0
+Version: 1.1.0
 Summary: Container bootstrapping tool
 Home-page: https://github.com/virt-manager/virt-bootstrap
 Author: Cedric Bosdonnat
@@ -52,3 +52,4 @@
 Classifier: License :: OSI Approved :: GNU General Public License v3 or later 
(GPLv3+)
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 3
+Provides-Extra: dev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/virt-bootstrap-1.0.0/src/virt_bootstrap.egg-info/SOURCES.txt 
new/virt-bootstrap-1.1.0/src/virt_bootstrap.egg-info/SOURCES.txt
--- old/virt-bootstrap-1.0.0/src/virt_bootstrap.egg-info/SOURCES.txt    
2017-09-07 16:48:36.000000000 +0200
+++ new/virt-bootstrap-1.1.0/src/virt_bootstrap.egg-info/SOURCES.txt    
2018-05-31 13:34:38.000000000 +0200
@@ -2,6 +2,7 @@
 ChangeLog
 LICENSE
 MANIFEST.in
+NEWS.md
 README.md
 setup.py
 man/virt-bootstrap.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virt-bootstrap-1.0.0/tests/docker_source.py 
new/virt-bootstrap-1.1.0/tests/docker_source.py
--- old/virt-bootstrap-1.0.0/tests/docker_source.py     2017-09-05 
15:23:44.000000000 +0200
+++ new/virt-bootstrap-1.1.0/tests/docker_source.py     2018-05-31 
13:03:07.000000000 +0200
@@ -23,8 +23,8 @@
 - utils.get_image_details(): Returns manifest content
 - utils.get_image_dir(): Returns the directory which contains the tar files
 
-Brief description of this tests:
-1. Create dummy tar files named <checksum>.tar used as image layers.
+Description:
+1. Create dummy image layers (tar files).
 2. Generate manifest content.
 3. Mock out get_image_details() and get_image_dir().
 4. Call bootstrap().
@@ -90,11 +90,8 @@
         """
         return {
             "schemaVersion": 2,
-            "layers": [
-                {
-                    "digest":
-                    "sha256:" + os.path.basename(layer).split('.')[0]
-                }
+            "Layers": [
+                "sha256:" + os.path.basename(layer).split('.')[0]
                 for layer in self.layers
             ]
         }
@@ -104,11 +101,6 @@
     """
     Ensures that all layers extracted correctly in destination folder.
     """
-    def check_result(self, layers_rootfs, dest):
-        """
-        Iterates trough values of layers_rootfs in reverse order (from the last
-        layer to first) and calls check_extracted_files().
-        """
 
     def call_bootstrap(self, manifest):
         """
@@ -141,7 +133,7 @@
         layers_rootfs = layers.get_layers_rootfs()
         for rootfs_tree in layers_rootfs[::-1]:
             self.rootfs_tree = rootfs_tree
-            self.check_rootfs(skip_ownership=(os.geteuid != 0))
+            self.check_rootfs(skip_ownership=(os.geteuid() != 0))
 
     @unittest.skipIf(NOT_ROOT, "Root privileges required")
     def test_dir_ownership_mapping(self):
@@ -320,10 +312,12 @@
         """
         with mock.patch.multiple('virtBootstrap.utils',
                                  get_image_details=mock.DEFAULT,
+                                 is_installed=mock.DEFAULT,
                                  get_image_dir=mock.DEFAULT) as m_utils:
 
             m_utils['get_image_details'].return_value = manifest
             m_utils['get_image_dir'].return_value = '/images_path'
+            m_utils['is_installed'].return_value = True
 
             patch_method = 'virtBootstrap.sources.DockerSource.gen_valid_uri'
             with mock.patch(patch_method) as m_uri:
@@ -340,7 +334,7 @@
             'progress': mock.Mock()
         }
 
-        manifest = {'schemaVersion': 2, 'layers': []}
+        manifest = {'schemaVersion': 2, 'Layers': ['sha256:a7050fc1']}
         (src_instance,
          m_uri, m_utils) = self._mock_retrieve_layers_info(manifest,
                                                            src_kwargs)
@@ -349,7 +343,7 @@
             'insecure': src_instance.insecure,
             'username': src_instance.username,
             'password': src_instance.password,
-            'raw': True
+            'raw': False
         }
         m_utils['get_image_details'].assert_called_once_with(m_uri(), **kwargs)
 
@@ -365,64 +359,21 @@
         }
 
         manifest = {
-            'schemaVersion': 1,
-            'fsLayers': [
-                {'blobSum': 'sha256:75c416ea'},
-                {'blobSum': 'sha256:c6ff40b6'},
-                {'blobSum': 'sha256:a7050fc1'}
+            'schemaVersion': 2,
+            'Layers': [
+                'sha256:a7050fc1',
+                'sha256:c6ff40b6',
+                'sha256:75c416ea'
             ]
         }
 
         expected_result = [
-            ['/images_path/a7050fc1.tar', None],
-            ['/images_path/c6ff40b6.tar', None],
-            ['/images_path/75c416ea.tar', None]
+            ['/images_path/a7050fc1', None],
+            ['/images_path/c6ff40b6', None],
+            ['/images_path/75c416ea', None]
         ]
 
         with mock.patch('os.path.getsize') as m_getsize:
             m_getsize.return_value = None
             src_instance = self._mock_retrieve_layers_info(manifest, kwargs)[0]
         self.assertEqual(src_instance.layers, expected_result)
-
-    def test_retrieve_layers_info_schema_version_2(self):
-        """
-        Ensures that retrieve_layers_info() extracts the layers' information
-        from manifest with schema version 2 a list with format:
-            ["digest", "sum_type", "file_path", "size"].
-        """
-        kwargs = {
-            'uri': '',
-            'progress': mock.Mock()
-        }
-
-        manifest = {
-            'schemaVersion': 2,
-            "layers": [
-                {"size": 47103294, "digest": "sha256:75c416ea"},
-                {"size": 814, "digest": "sha256:c6ff40b6"},
-                {"size": 513, "digest": "sha256:a7050fc1"}
-            ]
-        }
-
-        expected_result = [
-            ['/images_path/75c416ea.tar', 47103294],
-            ['/images_path/c6ff40b6.tar', 814],
-            ['/images_path/a7050fc1.tar', 513]
-        ]
-
-        src_instance = self._mock_retrieve_layers_info(manifest, kwargs)[0]
-        self.assertEqual(src_instance.layers, expected_result)
-
-    def test_retrieve_layers_info_raise_error_on_invalid_schema_version(self):
-        """
-        Ensures that retrieve_layers_info() calls get_image_details()
-        with all passed arguments.
-        """
-        kwargs = {
-            'uri': '',
-            'progress': mock.Mock()
-        }
-
-        manifest = {'schemaVersion': 3}
-        with self.assertRaises(ValueError):
-            self._mock_retrieve_layers_info(manifest, kwargs)


Reply via email to