Skip to content

Commit

Permalink
Feature/6207 config single file (#7840)
Browse files Browse the repository at this point in the history
* feat(client): Specify configuration file installation

* In order to specify a file configuration for the command `conan config install`,
we test if the file is a zip file first. If it is not a zip, then we use the same
logic in the function _process_folder, by using the name file.
* For some convinance, we have comment the all other files copy during made
by the command `conan config install`

* fix(pep8): Fixed pep8 intendation

* chore(tools): Implement is_compressed_file

* is_compressed_file permit to test if a file is a zip, or a gzip,
or a targz file
* Remove the check is_zipfile in unzip function, in order to
test if a file is a zip in the ./client/conf/config_installer.py file

* chore(conf): Keep custom files install and specify compressed files

* Keep custom files installation
* Test if the uri is a compressed file and use decompression
  configuration function
* Test if the uri is a regular file and use file configuration function

* fix(tools): Fixed is_compressed_file function

* Add first, if the filename is a file in order to remove
the `compressed` state

* chore(conf): Remove `compressed` state

* Remove the `compressed` state, by checking if a `file` type is a zip or a tar* or a gzip

* refactor(conf): Remove commented code

* chore(tools): Open a file first in is_compressed_file

* In order to raise an exception if a file exist or not, open a file in
  order to check if it is a gzip file first, then check if it is a zip
or a tar* file

* test(functional): Add a test for file installation

* Test the command conan config install with a specific file

* fix(test): Use mkdtemp instead of TemporaryDirectory

Co-authored-by: Marian GAPPA <marian.gappa@zenika.com>
  • Loading branch information
sagarafr and mgappa committed Oct 18, 2020
1 parent 4d43ce8 commit 4f9822d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 38 deletions.
82 changes: 45 additions & 37 deletions conans/client/conf/config_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from conans.client import tools
from conans.client.cache.remote_registry import load_registry_txt, migrate_registry_file
from conans.client.tools import Git
from conans.client.tools.files import unzip
from conans.client.tools.files import unzip, is_compressed_file
from conans.errors import ConanException
from conans.util.files import mkdir, rmdir, walk, save, touch, remove
from conans.client.cache.cache import ClientCache
Expand Down Expand Up @@ -86,6 +86,43 @@ def _filecopy(src, filename, dst):
shutil.copyfile(src, dst)


def _process_file(directory, filename, config, cache, output, folder):
if filename == "settings.yml":
output.info("Installing settings.yml")
_filecopy(directory, filename, cache.cache_folder)
elif filename == "conan.conf":
output.info("Processing conan.conf")
_handle_conan_conf(cache.config, os.path.join(directory, filename))
elif filename == "remotes.txt":
output.info("Defining remotes from remotes.txt")
_handle_remotes(cache, os.path.join(directory, filename))
elif filename in ("registry.txt", "registry.json"):
try:
os.remove(cache.remotes_path)
except OSError:
pass
finally:
_filecopy(directory, filename, cache.cache_folder)
migrate_registry_file(cache, output)
elif filename == "remotes.json":
# Fix for Conan 2.0
raise ConanException("remotes.json install is not supported yet. Use 'remotes.txt'")
else:
# This is ugly, should be removed in Conan 2.0
if filename in ("README.md", "LICENSE.txt"):
output.info("Skip %s" % filename)
else:
relpath = os.path.relpath(directory, folder)
if config.target_folder:
target_folder = os.path.join(cache.cache_folder, config.target_folder,
relpath)
else:
target_folder = os.path.join(cache.cache_folder, relpath)
mkdir(target_folder)
output.info("Copying file %s to %s" % (filename, target_folder))
_filecopy(directory, filename, target_folder)


def _process_folder(config, folder, cache, output):
if not os.path.isdir(folder):
raise ConanException("No such directory: '%s'" % str(folder))
Expand All @@ -96,40 +133,7 @@ def _process_folder(config, folder, cache, output):
if ".git" in root:
continue
for f in files:
if f == "settings.yml":
output.info("Installing settings.yml")
_filecopy(root, f, cache.cache_folder)
elif f == "conan.conf":
output.info("Processing conan.conf")
_handle_conan_conf(cache.config, os.path.join(root, f))
elif f == "remotes.txt":
output.info("Defining remotes from remotes.txt")
_handle_remotes(cache, os.path.join(root, f))
elif f in ("registry.txt", "registry.json"):
try:
os.remove(cache.remotes_path)
except OSError:
pass
finally:
_filecopy(root, f, cache.cache_folder)
migrate_registry_file(cache, output)
elif f == "remotes.json":
# Fix for Conan 2.0
raise ConanException("remotes.json install is not supported yet. Use 'remotes.txt'")
else:
# This is ugly, should be removed in Conan 2.0
if root == folder and f in ("README.md", "LICENSE.txt"):
output.info("Skip %s" % f)
continue
relpath = os.path.relpath(root, folder)
if config.target_folder:
target_folder = os.path.join(cache.cache_folder, config.target_folder,
relpath)
else:
target_folder = os.path.join(cache.cache_folder, relpath)
mkdir(target_folder)
output.info("Copying file %s to %s" % (f, target_folder))
_filecopy(root, f, target_folder)
_process_file(root, f, config, cache, output, folder)


def _process_download(config, cache, output, requester):
Expand Down Expand Up @@ -202,8 +206,12 @@ def _process_config(config, cache, output, requester):
elif config.type == "dir":
_process_folder(config, config.uri, cache, output)
elif config.type == "file":
with tmp_config_install_folder(cache) as tmp_folder:
_process_zip_file(config, config.uri, cache, output, tmp_folder)
if is_compressed_file(config.uri):
with tmp_config_install_folder(cache) as tmp_folder:
_process_zip_file(config, config.uri, cache, output, tmp_folder)
else:
dirname, filename = os.path.dirname(config.uri), os.path.basename(config.uri)
_process_file(dirname, filename, config, cache, output, dirname)
elif config.type == "url":
_process_download(config, cache, output, requester=requester)
else:
Expand Down
13 changes: 13 additions & 0 deletions conans/client/tools/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ def human_size(size_bytes):
return "%s%s" % (formatted_size, suffix)


def is_compressed_file(filename):
import zipfile
import tarfile
import binascii
# test gzip magic number
with open(filename, 'rb') as fd:
if binascii.hexlify(fd.read(2)) == b'1f8b':
return True
if zipfile.is_zipfile(filename) or tarfile.is_tarfile(filename):
return True
return False


def unzip(filename, destination=".", keep_permissions=False, pattern=None, output=None):
"""
Unzip a zipped file
Expand Down
27 changes: 26 additions & 1 deletion conans/test/functional/command/config_install_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def _create_zip(self, zippath=None):
def _check(self, params):
typ, uri, verify, args = [p.strip() for p in params.split(",")]
configs = json.loads(load(self.client.cache.config_install_file))
config = _ConfigOrigin(configs[0])
config = _ConfigOrigin(configs[-1])
self.assertEqual(config.type, typ)
self.assertEqual(config.uri, uri)
self.assertEqual(str(config.verify_ssl), verify)
Expand Down Expand Up @@ -214,6 +214,31 @@ def test_install_file_test(self):
self._check("file, %s, True, None" % zippath)
self.assertTrue(os.path.exists(zippath))

def test_install_config_file_test(self):
""" should install from a settings and remotes file in configuration directory
"""
import tempfile
profile_folder = self._create_profile_folder()
self.assertTrue(os.path.isdir(profile_folder))
src_setting_file = os.path.join(profile_folder, "settings.yml")
src_remote_file = os.path.join(profile_folder, "remotes.txt")

# Install profile_folder without settings.yml + remotes.txt in order to install them manually
tmp_dir = tempfile.mkdtemp()
dest_setting_file = os.path.join(tmp_dir, "settings.yml")
dest_remote_file = os.path.join(tmp_dir, "remotes.txt")
shutil.move(src_setting_file, dest_setting_file)
shutil.move(src_remote_file, dest_remote_file)
self.client.run('config install "%s"' % profile_folder)
shutil.move(dest_setting_file, src_setting_file)
shutil.move(dest_remote_file, src_remote_file)
shutil.rmtree(tmp_dir)

for cmd_option in ["", "--type=file"]:
self.client.run('config install "%s" %s' % (src_setting_file, cmd_option))
self.client.run('config install "%s" %s' % (src_remote_file, cmd_option))
self._check("file, %s, True, None" % src_remote_file)

def test_install_dir_test(self):
""" should install from a dir in current dir
"""
Expand Down

0 comments on commit 4f9822d

Please sign in to comment.