From ab4b6730a8894c108d595e09b2a997afb8404841 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Wed, 29 Jul 2020 17:00:10 -0300 Subject: [PATCH 01/26] Bump Conan version to 1.28.0 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/__init__.py | 4 ++-- cpt/requirements.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpt/__init__.py b/cpt/__init__.py index 8ea71dde..89f67b39 100644 --- a/cpt/__init__.py +++ b/cpt/__init__.py @@ -1,6 +1,6 @@ -__version__ = '0.34.0' -NEWEST_CONAN_SUPPORTED = "1.27.000" +__version__ = '0.34.1' +NEWEST_CONAN_SUPPORTED = "1.28.000" def get_client_version(): diff --git a/cpt/requirements.txt b/cpt/requirements.txt index 9838fc43..2620348c 100644 --- a/cpt/requirements.txt +++ b/cpt/requirements.txt @@ -1,3 +1,3 @@ six>=1.10.0, <1.15.0 -conan>=1.7.0, <1.28.0 +conan>=1.7.0, <1.29.0 tabulate>=0.8.0, <0.9.0 From 27614f74e9248095b268b90e6b12db4335b0e3a4 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Thu, 30 Jul 2020 10:39:18 -0300 Subject: [PATCH 02/26] #515 Fix CPT_TEST_FOLDER=False Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/runner.py | 3 +++ cpt/test/integration/basic_test.py | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/cpt/runner.py b/cpt/runner.py index d9315c4f..42769ccd 100644 --- a/cpt/runner.py +++ b/cpt/runner.py @@ -62,6 +62,9 @@ def __init__(self, profile_abs_path, reference, conan_api, uploader, self._profile = load_profile(profile_abs_path, cache) + if isinstance(self._test_folder, str) and self._test_folder.lower() == "false": + self._test_folder = False + @property def settings(self): return self._profile.settings diff --git a/cpt/test/integration/basic_test.py b/cpt/test/integration/basic_test.py index 6dc3378a..7c4c02b9 100644 --- a/cpt/test/integration/basic_test.py +++ b/cpt/test/integration/basic_test.py @@ -310,6 +310,26 @@ def configure(self): json_data = json.load(json_content) self.assertFalse(json_data[0]["package"]["error"]) + def test_disable_test_folder(self): + conanfile = """from conans import ConanFile + +class Pkg(ConanFile): + name = "lib" + version = "1.0" +""" + self.save_conanfile(conanfile) + conanfile = """from conans import ConanFile + +class Pkg(ConanFile): + def test(self): + raise Exception("Should not run") +""" + tools.save(os.path.join(self.tmp_folder, "test_package", "conanfile.py"), conanfile) + with tools.environment_append({"CPT_TEST_FOLDER": "False"}): + self.packager = ConanMultiPackager(out=self.output.write) + self.packager.add_common_builds() + self.packager.run() + def test_custom_name_version(self): conanfile = """from conans import ConanFile from datetime import date From 2d629177abb1dc1813d02ac4bd74295ef7507c81 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Thu, 30 Jul 2020 12:07:42 -0300 Subject: [PATCH 03/26] #515 Add invalid test_folder test Signed-off-by: Uilian Ries <uilianries@gmail.com> --- .travis.yml | 4 ++-- cpt/test/integration/basic_test.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e33b092a..03d6aa6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,11 +16,11 @@ jobs: - stage: Conan Latest - Macos language: generic os: osx - osx_image: xcode8.3 + osx_image: xcode12 env: PYVER=py27 TOXENV=py27-conan-latest - language: generic os: osx - osx_image: xcode8.3 + osx_image: xcode12 env: PYVER=py37 TOXENV=py37-conan-latest - stage: Conan Development - Linux diff --git a/cpt/test/integration/basic_test.py b/cpt/test/integration/basic_test.py index 7c4c02b9..390757b6 100644 --- a/cpt/test/integration/basic_test.py +++ b/cpt/test/integration/basic_test.py @@ -5,6 +5,7 @@ from conans import tools from conans.model.ref import ConanFileReference +from conans.errors import ConanException from cpt.test.integration.base import BaseTest from cpt.packager import ConanMultiPackager @@ -330,6 +331,24 @@ def test(self): self.packager.add_common_builds() self.packager.run() + def test_invalid_test_folder(self): + conanfile = """from conans import ConanFile + +class Pkg(ConanFile): + name = "lib" + version = "1.0" +""" + self.save_conanfile(conanfile) + for test_folder in ["True", "foobar"]: + with tools.environment_append({"CPT_TEST_FOLDER": test_folder}): + self.packager = ConanMultiPackager(out=self.output.write) + self.packager.add_common_builds() + with self.assertRaises(ConanException) as raised: + self.packager.run() + self.assertIn("test folder '{}' not available, or it doesn't have a conanfile.py" + .format(test_folder), + str(raised.exception)) + def test_custom_name_version(self): conanfile = """from conans import ConanFile from datetime import date From 584b56f9eb4c4e1ccc8307f874649a0cd7d9d7bb Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Thu, 30 Jul 2020 12:47:14 -0300 Subject: [PATCH 04/26] #515 Update OSX version to 10.3 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 03d6aa6e..55a7c3c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,11 +16,11 @@ jobs: - stage: Conan Latest - Macos language: generic os: osx - osx_image: xcode12 + osx_image: xcode10.3 env: PYVER=py27 TOXENV=py27-conan-latest - language: generic os: osx - osx_image: xcode12 + osx_image: xcode10.3 env: PYVER=py37 TOXENV=py37-conan-latest - stage: Conan Development - Linux From 8dc8d198ba52b19e3c759e92e7c552bd7b08c50a Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Tue, 1 Sep 2020 14:49:50 -0300 Subject: [PATCH 05/26] Support Conan 1.29 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/__init__.py | 4 ++-- cpt/requirements.txt | 2 +- setup.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpt/__init__.py b/cpt/__init__.py index 89f67b39..c8a4b0c5 100644 --- a/cpt/__init__.py +++ b/cpt/__init__.py @@ -1,6 +1,6 @@ -__version__ = '0.34.1' -NEWEST_CONAN_SUPPORTED = "1.28.000" +__version__ = '0.34.2' +NEWEST_CONAN_SUPPORTED = "1.29.000" def get_client_version(): diff --git a/cpt/requirements.txt b/cpt/requirements.txt index 2620348c..9594dac6 100644 --- a/cpt/requirements.txt +++ b/cpt/requirements.txt @@ -1,3 +1,3 @@ six>=1.10.0, <1.15.0 -conan>=1.7.0, <1.29.0 +conan>=1.7.0, <1.30.0 tabulate>=0.8.0, <0.9.0 diff --git a/setup.py b/setup.py index 74ce48c9..44226547 100644 --- a/setup.py +++ b/setup.py @@ -47,8 +47,8 @@ def load_version(): url='https://github.com/conan-io/conan-package-tools', # Author details - author='JFrog LTD. Luis Martinez de Bartolome', - author_email='luism@jfrog.com', + author='JFrog LTD', + author_email='info@conan.io', # Choose your license license='MIT', From 6b06ed36a94a77999f63361e7db3d2ffeaaa41c3 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Thu, 1 Oct 2020 11:59:28 -0300 Subject: [PATCH 06/26] Accept Conan 1.30 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/__init__.py | 4 ++-- cpt/requirements.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpt/__init__.py b/cpt/__init__.py index c8a4b0c5..edceec8b 100644 --- a/cpt/__init__.py +++ b/cpt/__init__.py @@ -1,6 +1,6 @@ -__version__ = '0.34.2' -NEWEST_CONAN_SUPPORTED = "1.29.000" +__version__ = '0.34.3' +NEWEST_CONAN_SUPPORTED = "1.30.000" def get_client_version(): diff --git a/cpt/requirements.txt b/cpt/requirements.txt index 9594dac6..75f313ff 100644 --- a/cpt/requirements.txt +++ b/cpt/requirements.txt @@ -1,3 +1,3 @@ six>=1.10.0, <1.15.0 -conan>=1.7.0, <1.30.0 +conan>=1.7.0, <1.31.0 tabulate>=0.8.0, <0.9.0 From 4fc377e55ba871005f7ded9439fca33830af3345 Mon Sep 17 00:00:00 2001 From: ericLemanissier <ericLemanissier@users.noreply.github.com> Date: Tue, 25 Feb 2020 12:24:43 +0100 Subject: [PATCH 07/26] build static before shared usually, the static build is the default one --- cpt/builds_generator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpt/builds_generator.py b/cpt/builds_generator.py index 4eba274c..6781a471 100644 --- a/cpt/builds_generator.py +++ b/cpt/builds_generator.py @@ -221,7 +221,7 @@ def get_mingw_builds(mingw_configurations, mingw_installer_reference, build_requires = {"*": [mingw_installer_reference]} if shared_option_name and not build_all_options_values: - for shared in [True, False]: + for shared in [False, True]: opt = copy.copy(options) opt[shared_option_name] = shared builds += _make_mingw_builds(settings, opt, build_requires, build_types, cppstds, reference) @@ -367,7 +367,7 @@ def get_osx_apple_clang_builds(apple_clang_versions, archs, shared_option_name, for arch in archs: for cppstd in cppstds: if shared_option_name and not build_all_options_values: - for shared in [True, False]: + for shared in [False, True]: opt = copy.copy(options) opt[shared_option_name] = shared for build_type_it in build_types: @@ -414,7 +414,7 @@ def get_linux_gcc_builds(gcc_versions, archs, shared_option_name, pure_c, build_ for arch in archs: for cppstd in cppstds: if shared_option_name and not build_all_options_values: - for shared in [True, False]: + for shared in [False, True]: opt = copy.copy(options) opt[shared_option_name] = shared for build_type_it in build_types: @@ -464,7 +464,7 @@ def get_linux_clang_builds(clang_versions, archs, shared_option_name, pure_c, bu for arch in archs: for cppstd in cppstds: if shared_option_name and not build_all_options_values: - for shared in [True, False]: + for shared in [False, True]: opt = copy.copy(options) opt[shared_option_name] = shared for build_type_it in build_types: From ed5b0218dec6f9ea8b844ae6931bec5fd8f5d1db Mon Sep 17 00:00:00 2001 From: Eric Lemanissier <eric.lemanissier@gmail.com> Date: Tue, 27 Oct 2020 22:28:31 +0100 Subject: [PATCH 08/26] fix unit tests --- cpt/test/unit/generators_test.py | 178 +++++++++++++++---------------- cpt/test/unit/packager_test.py | 8 +- 2 files changed, 93 insertions(+), 93 deletions(-) diff --git a/cpt/test/unit/generators_test.py b/cpt/test/unit/generators_test.py index eeb3403f..7510cd64 100644 --- a/cpt/test/unit/generators_test.py +++ b/cpt/test/unit/generators_test.py @@ -20,25 +20,25 @@ def test_mingw_generator(self): ({'build_type': 'Release', 'compiler.version': '4.9', 'compiler.libcxx': "libstdc++", 'compiler': 'gcc', 'arch': 'x86', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix'}, - {'pack:shared': True}, + {'pack:shared': False}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref), ({'compiler.version': '4.9', 'compiler': 'gcc', 'compiler.libcxx': "libstdc++", 'build_type': 'Debug', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', - 'arch': 'x86'}, {'pack:shared': True}, + 'arch': 'x86'}, {'pack:shared': False}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref), ({'build_type': 'Release', 'compiler.version': '4.9', 'compiler.libcxx': "libstdc++", 'compiler': 'gcc', 'arch': 'x86', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix'}, - {'pack:shared': False}, + {'pack:shared': True}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref), ({'compiler.version': '4.9', 'compiler': 'gcc', 'compiler.libcxx': "libstdc++", 'build_type': 'Debug', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', 'arch': 'x86'}, - {'pack:shared': False}, + {'pack:shared': True}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref)] @@ -50,13 +50,13 @@ def test_mingw_generator(self): ({'build_type': 'Release', 'compiler.version': '4.9', 'compiler.libcxx': "libstdc++", 'compiler': 'gcc', 'arch': 'x86', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', 'compiler.cppstd': '20'}, - {'pack:shared': True}, + {'pack:shared': False}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, None), ({'build_type': 'Release', 'compiler.version': '4.9', 'compiler.libcxx': "libstdc++", 'compiler': 'gcc', 'arch': 'x86', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', 'compiler.cppstd': '20'}, - {'pack:shared': False}, + {'pack:shared': True}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, None)] @@ -68,13 +68,13 @@ def test_mingw_generator(self): ({'compiler.version': '4.9', 'compiler': 'gcc', 'compiler.libcxx': "libstdc++", 'build_type': 'Debug', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', 'arch': 'x86', 'compiler.cppstd': '14'}, - {'pack:shared': True}, + {'pack:shared': False}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, None), ({'compiler.version': '4.9', 'compiler': 'gcc', 'compiler.libcxx': "libstdc++", 'build_type': 'Debug', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', 'arch': 'x86', 'compiler.cppstd': '14'}, - {'pack:shared': False}, + {'pack:shared': True}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, None)] @@ -89,26 +89,26 @@ def test_mingw_generator(self): ({'build_type': 'Release', 'compiler.version': '4.9', 'compiler.libcxx': "libstdc++", 'compiler': 'gcc', 'arch': 'x86', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix'}, - {'pack:shared': True, "pack:foobar": True, "foobar:qux": "data"}, + {'pack:shared': False, "pack:foobar": True, "foobar:qux": "data"}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref), ({'compiler.version': '4.9', 'compiler': 'gcc', 'compiler.libcxx': "libstdc++", 'build_type': 'Debug', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', 'arch': 'x86'}, - {'pack:shared': True, "pack:foobar": True, "foobar:qux": "data"}, + {'pack:shared': False, "pack:foobar": True, "foobar:qux": "data"}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref), ({'build_type': 'Release', 'compiler.version': '4.9', 'compiler.libcxx': "libstdc++", 'compiler': 'gcc', 'arch': 'x86', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix'}, - {'pack:shared': False, "pack:foobar": True, "foobar:qux": "data"}, + {'pack:shared': True, "pack:foobar": True, "foobar:qux": "data"}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref), ({'compiler.version': '4.9', 'compiler': 'gcc', 'compiler.libcxx': "libstdc++", 'build_type': 'Debug', 'compiler.exception': 'dwarf2', 'compiler.threads': 'posix', 'arch': 'x86'}, - {'pack:shared': False, "pack:foobar": True, "foobar:qux": "data"}, + {'pack:shared': True, "pack:foobar": True, "foobar:qux": "data"}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}, ref)] @@ -255,13 +255,13 @@ def test_get_osx_apple_clang_builds(self): options={}, reference=ref) expected = [({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': True}, {}, {}, ref), - ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug'}, {'pack:shared': False}, {}, {}, ref), + ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug'}, + {'pack:shared': True}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': False}, {}, {}, ref)] + {'pack:shared': True}, {}, {}, ref)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_osx_apple_clang_builds(["8.0"], ["x86_64"], "pack:shared", pure_c=True, @@ -270,50 +270,50 @@ def test_get_osx_apple_clang_builds(self): options={}) expected = [({'arch': 'x86_64', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug'}, - {'pack:shared': False}, {}, {}, None), + {'pack:shared': True}, {}, {}, None), ({'arch': 'x86_64', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_osx_apple_clang_builds(["8.0"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Debug"], cppstds=["14"], options={}) expected = [({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug', 'compiler.cppstd': '14'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug', 'compiler.cppstd': '14'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_osx_apple_clang_builds(["8.0"], ["x86_64"], "pack:shared", pure_c=True, build_types=["Release"], cppstds=["17"], options={}) expected = [({'arch': 'x86_64', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_osx_apple_clang_builds(["8.0"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Debug", "Release"], cppstds=[None], options={"qux:foobar": False, "foo:pkg": "bar"}, reference=ref) expected = [({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug'}, - {'pack:shared': True, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref), + {'pack:shared': False, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': True, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref), + {'pack:shared': False, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Debug'}, - {'pack:shared': False, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref), + {'pack:shared': True, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.libcxx': 'libc++', 'compiler': 'apple-clang', 'compiler.version': '8.0', 'build_type': 'Release'}, - {'pack:shared': False, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref)] + {'pack:shared': True, "qux:foobar": False, "foo:pkg": "bar"}, {}, {}, ref)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_osx_apple_clang_builds(["8.0"], ["x86_64"], None, pure_c=False, @@ -397,104 +397,104 @@ def test_get_osx_apple_clang_builds(self): def test_get_linux_gcc_builds(self): builds = get_linux_gcc_builds(["6"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Debug", "Release"], cppstds=[None], options={}) expected = [({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, None), - ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, {'pack:shared': False}, {}, {}, None), + ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, + {'pack:shared': True}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, None), + {'pack:shared': True}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, None), + {'pack:shared': True}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_gcc_builds(["6"], ["x86_64"], "pack:shared", pure_c=True, build_types=["Debug", "Release"], cppstds=[None], options={}) expected = [({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Debug', 'compiler': 'gcc'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Release', 'compiler': 'gcc'}, - {'pack:shared': True}, {}, {}, None), - ({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Debug', 'compiler': 'gcc'}, {'pack:shared': False}, {}, {}, None), + ({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Debug', 'compiler': 'gcc'}, + {'pack:shared': True}, {}, {}, None), ({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Release', 'compiler': 'gcc'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_gcc_builds(["6"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Debug"], cppstds=["14"], options={}) expected = [({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '14'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '14'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '14'}, - {'pack:shared': False}, {}, {}, None), + {'pack:shared': True}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '14'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_gcc_builds(["6"], ["x86_64"], "pack:shared", pure_c=True, build_types=["Debug"], cppstds=["14"], options={}) expected = [({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Debug', 'compiler': 'gcc'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Debug', 'compiler': 'gcc'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_gcc_builds(["6"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Release"], cppstds=["17"], options={}) expected = [({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '17'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '17'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '17'}, - {'pack:shared': False}, {}, {}, None), + {'pack:shared': True}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64', 'compiler.cppstd': '17'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_gcc_builds(["6"], ["x86_64"], "pack:shared", pure_c=True, build_types=["Release"], cppstds=["17"], options={}) expected = [({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Release', 'compiler': 'gcc'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler.version': '6', 'build_type': 'Release', 'compiler': 'gcc'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_gcc_builds(["6"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Debug", "Release"], cppstds=[None], options={"foo:bar": "qux", "pkg:qux": False}) expected = [({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), + {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), + {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), + {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), + {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), + {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), + {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), + {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None), ({'compiler': 'gcc', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++11', 'compiler.version': '6', 'arch': 'x86_64'}, - {'pack:shared': False, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None)] + {'pack:shared': True, "foo:bar": "qux", "pkg:qux": False}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_gcc_builds(["6"], ["x86_64"], None, pure_c=True, build_types=["Debug", "Release"], @@ -627,84 +627,84 @@ def test_get_linux_clang_builds(self): build_types=["Debug", "Release"], cppstds=[None], options={}, reference=ref) expected = [({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), - ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, {'pack:shared': False}, {}, {}, ref), + ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, + {'pack:shared': True}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, ref), + {'pack:shared': True}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, ref), + {'pack:shared': True}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, ref)] + {'pack:shared': True}, {}, {}, ref)] b = [tuple(a) for a in builds] self.assertEquals(b, expected) builds = get_linux_clang_builds(["4.0"], ["x86_64"], "pack:shared", pure_c=True, build_types=["Debug", "Release"], cppstds=[None], options={}, reference=ref) expected = [({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Debug', 'compiler': 'clang'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Release', 'compiler': 'clang'}, - {'pack:shared': True}, {}, {}, ref), - ({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Debug', 'compiler': 'clang'}, {'pack:shared': False}, {}, {}, ref), + ({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Debug', 'compiler': 'clang'}, + {'pack:shared': True}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Release', 'compiler': 'clang'}, - {'pack:shared': False}, {}, {}, ref)] + {'pack:shared': True}, {}, {}, ref)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_clang_builds(["4.0"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Debug"], cppstds=[None], options={}, reference=ref) expected = [({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, ref), + {'pack:shared': True}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, ref)] + {'pack:shared': True}, {}, {}, ref)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_clang_builds(["4.0"], ["x86_64"], "pack:shared", pure_c=True, build_types=["Debug"], cppstds=[None], options={}, reference=ref) expected = [({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Debug', 'compiler': 'clang'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Debug', 'compiler': 'clang'}, - {'pack:shared': False}, {}, {}, ref)] + {'pack:shared': True}, {}, {}, ref)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_clang_builds(["4.0"], ["x86_64"], "pack:shared", pure_c=False, build_types=["Release"], cppstds=[None], options={}, reference=ref) expected = [({'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ( {'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True}, {}, {}, ref), + {'pack:shared': False}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, ref), + {'pack:shared': True}, {}, {}, ref), ( {'compiler': 'clang', 'build_type': 'Release', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False}, {}, {}, ref)] + {'pack:shared': True}, {}, {}, ref)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_clang_builds(["4.0"], ["x86_64"], "pack:shared", pure_c=True, build_types=["Release"], cppstds=[None], options={}, reference=None) expected = [({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Release', 'compiler': 'clang'}, - {'pack:shared': True}, {}, {}, None), + {'pack:shared': False}, {}, {}, None), ({'arch': 'x86_64', 'compiler.version': '4.0', 'build_type': 'Release', 'compiler': 'clang'}, - {'pack:shared': False}, {}, {}, None)] + {'pack:shared': True}, {}, {}, None)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_clang_builds(["4.0"], ["x86_64"], "pack:shared", pure_c=False, @@ -712,18 +712,18 @@ def test_get_linux_clang_builds(self): options={"foo:bar": "qux", "pkg:shared": True}, reference=ref) expected = [({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref), + {'pack:shared': False, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref), ( {'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': True, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref), + {'pack:shared': False, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref), ({'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libstdc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref), + {'pack:shared': True, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref), ( {'compiler': 'clang', 'build_type': 'Debug', 'compiler.libcxx': 'libc++', 'compiler.version': '4.0', 'arch': 'x86_64'}, - {'pack:shared': False, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref)] + {'pack:shared': True, "foo:bar": "qux", "pkg:shared": True}, {}, {}, ref)] self.assertEquals([tuple(a) for a in builds], expected) builds = get_linux_clang_builds(["4.0"], ["x86_64"], None, pure_c=False, @@ -1448,7 +1448,7 @@ def test_visual_toolsets(self): {'pack:shared': True, 'pack:foo': False, 'pack:bar': False}, {}, {}, ref), ( {'compiler': 'Visual Studio', 'compiler.version': '10', 'arch': 'x86', 'build_type': 'Debug', 'compiler.runtime': 'MDd'}, - {'pack:shared': False, 'pack:foo': True, 'pack:bar': True}, {}, {}, ref), ( + {'pack:shared': False, 'pack:foo': True, 'pack:bar': True}, {}, {}, ref), ( {'compiler': 'Visual Studio', 'compiler.version': '10', 'arch': 'x86', 'build_type': 'Debug', 'compiler.runtime': 'MDd'}, {'pack:shared': False, 'pack:foo': False, 'pack:bar': True}, {}, {}, ref), ( diff --git a/cpt/test/unit/packager_test.py b/cpt/test/unit/packager_test.py index 9816b351..eceb64fa 100644 --- a/cpt/test/unit/packager_test.py +++ b/cpt/test/unit/packager_test.py @@ -430,26 +430,26 @@ def test_only_mingw(self): expected = [({'compiler.exception': 'seh', 'compiler.libcxx': "libstdc++", 'compiler.threads': 'posix', 'compiler.version': '4.9', 'arch': 'x86_64', 'build_type': 'Release', 'compiler': 'gcc'}, - {'zlib:shared': True}, + {'zlib:shared': False}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}), ({'compiler.exception': 'seh', 'compiler.libcxx': "libstdc++", 'arch': 'x86_64', 'compiler.threads': 'posix', 'compiler.version': '4.9', 'build_type': 'Debug', 'compiler': 'gcc'}, - {'zlib:shared': True}, + {'zlib:shared': False}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}), ({'compiler.exception': 'seh', 'compiler.libcxx': "libstdc++", 'compiler.threads': 'posix', 'compiler.version': '4.9', 'arch': 'x86_64', 'build_type': 'Release', 'compiler': 'gcc'}, - {'zlib:shared': False}, + {'zlib:shared': True}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]}), ({'compiler.exception': 'seh', 'compiler.libcxx': "libstdc++", 'arch': 'x86_64', 'compiler.threads': 'posix', 'compiler.version': '4.9', 'build_type': 'Debug', 'compiler': 'gcc'}, - {'zlib:shared': False}, + {'zlib:shared': True}, {}, {'*': [ConanFileReference.loads("mingw_installer/1.0@conan/stable")]})] From 245b72193b95a8d3d2fb8e70b53fbb37d11cd2aa Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Fri, 30 Oct 2020 09:23:23 -0300 Subject: [PATCH 09/26] Update max Conan version to 1.31.0 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/__init__.py | 4 ++-- cpt/requirements.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpt/__init__.py b/cpt/__init__.py index edceec8b..89d9d5aa 100644 --- a/cpt/__init__.py +++ b/cpt/__init__.py @@ -1,6 +1,6 @@ -__version__ = '0.34.3' -NEWEST_CONAN_SUPPORTED = "1.30.000" +__version__ = '0.34.4' +NEWEST_CONAN_SUPPORTED = "1.31.000" def get_client_version(): diff --git a/cpt/requirements.txt b/cpt/requirements.txt index 75f313ff..80f2dbf4 100644 --- a/cpt/requirements.txt +++ b/cpt/requirements.txt @@ -1,3 +1,3 @@ -six>=1.10.0, <1.15.0 -conan>=1.7.0, <1.31.0 +six>=1.10.0,<=1.15.0 +conan>=1.7.0, <1.32.0 tabulate>=0.8.0, <0.9.0 From c0a316530f21b5d7137a31a79c784e48625dafe5 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Tue, 17 Nov 2020 12:59:59 -0300 Subject: [PATCH 10/26] Bump dev version (#531) * Bump dev version Signed-off-by: Uilian Ries <uilianries@gmail.com> * Allow dev branch Signed-off-by: Uilian Ries <uilianries@gmail.com> * Remove maximum Conan version Signed-off-by: Uilian Ries <uilianries@gmail.com> * Remove conan version Signed-off-by: Uilian Ries <uilianries@gmail.com> * Copy Conan Tests to CPT Signed-off-by: Uilian Ries <uilianries@gmail.com> * Remove unused files Signed-off-by: Uilian Ries <uilianries@gmail.com> * Export source for fPIC template Signed-off-by: Uilian Ries <uilianries@gmail.com> * Fix integration test according Conan version Signed-off-by: Uilian Ries <uilianries@gmail.com> --- .gitignore | 8 + cpt/__init__.py | 4 +- cpt/packager.py | 16 +- cpt/requirements.txt | 2 +- cpt/test/assets/__init__.py | 16 + cpt/test/assets/genconanfile.py | 390 ++++++++ cpt/test/integration/base.py | 10 +- cpt/test/integration/conan_version_test.py | 18 - cpt/test/integration/update_deps_test.py | 2 +- .../integration/update_python_reqs_test.py | 2 +- cpt/test/integration/update_some_deps_test.py | 2 +- cpt/test/integration/upload_test.py | 2 +- cpt/test/test_client/config_install_test.py | 2 +- .../test_client/invalid_config_checks_test.py | 2 +- cpt/test/test_client/upload_checks_test.py | 2 +- cpt/test/test_client/visual_toolsets_test.py | 2 +- cpt/test/unit/auth_test.py | 2 +- cpt/test/unit/ci_manager_test.py | 2 +- cpt/test/unit/packager_test.py | 2 +- cpt/test/unit/utils.py | 2 +- cpt/test/utils/__init__.py | 0 cpt/test/utils/mocks.py | 231 +++++ cpt/test/utils/scm.py | 126 +++ cpt/test/utils/server_launcher.py | 113 +++ cpt/test/utils/test_files.py | 91 ++ cpt/test/utils/tools.py | 898 ++++++++++++++++++ 26 files changed, 1895 insertions(+), 52 deletions(-) create mode 100644 cpt/test/assets/__init__.py create mode 100644 cpt/test/assets/genconanfile.py delete mode 100644 cpt/test/integration/conan_version_test.py create mode 100644 cpt/test/utils/__init__.py create mode 100644 cpt/test/utils/mocks.py create mode 100644 cpt/test/utils/scm.py create mode 100644 cpt/test/utils/server_launcher.py create mode 100644 cpt/test/utils/test_files.py create mode 100644 cpt/test/utils/tools.py diff --git a/.gitignore b/.gitignore index d5ed69ad..aa2f6a10 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,11 @@ cacert.pem # tmp eclipse markdown viewer /.README* + + +# Virtualenv +env/ +venv/ + +# Coverage +.coveragerc diff --git a/cpt/__init__.py b/cpt/__init__.py index 89d9d5aa..eccc02cf 100644 --- a/cpt/__init__.py +++ b/cpt/__init__.py @@ -1,10 +1,10 @@ -__version__ = '0.34.4' -NEWEST_CONAN_SUPPORTED = "1.31.000" +__version__ = '0.34.5-dev' def get_client_version(): from conans.model.version import Version from conans import __version__ as client_version + from os import getenv # It is a mess comparing dev versions, lets assume that the -dev is the further release return Version(client_version.replace("-dev", "")) diff --git a/cpt/packager.py b/cpt/packager.py index bd0166f7..7f310715 100644 --- a/cpt/packager.py +++ b/cpt/packager.py @@ -13,7 +13,7 @@ from conans.model.ref import ConanFileReference from conans.model.version import Version -from cpt import NEWEST_CONAN_SUPPORTED, get_client_version +from cpt import get_client_version from cpt.auth import AuthManager from cpt.builds_generator import BuildConf, BuildGenerator from cpt.ci_manager import CIManager @@ -346,18 +346,6 @@ def valid_pair(var, value): for var, value in self.__dict__.items() if valid_pair(var, value)}) - self._newest_supported_conan_version = Version(NEWEST_CONAN_SUPPORTED).minor(fill=False) - self._client_conan_version = conan_version - - def _check_conan_version(self): - tmp = self._newest_supported_conan_version - if Version(self._client_conan_version).minor(fill=False) > tmp: - msg = "Conan/CPT version mismatch. Conan version installed: " \ - "%s . This version of CPT supports only Conan < %s" \ - "" % (self._client_conan_version, str(tmp)) - self.printer.print_message(msg) - raise Exception(msg) - # For Docker on Windows, including Linux containers on Windows @property def is_lcow(self): @@ -569,8 +557,6 @@ def update_build_if(self, predicate, new_settings=None, new_options=None, new_en self._builds = updated_builds def run(self, base_profile_name=None, summary_file=None): - self._check_conan_version() - env_vars = self.auth_manager.env_vars() env_vars.update(self.remotes_manager.env_vars()) with tools.environment_append(env_vars): diff --git a/cpt/requirements.txt b/cpt/requirements.txt index 80f2dbf4..981153dc 100644 --- a/cpt/requirements.txt +++ b/cpt/requirements.txt @@ -1,3 +1,3 @@ six>=1.10.0,<=1.15.0 -conan>=1.7.0, <1.32.0 +conan>=1.7.0 tabulate>=0.8.0, <0.9.0 diff --git a/cpt/test/assets/__init__.py b/cpt/test/assets/__init__.py new file mode 100644 index 00000000..c7f40f86 --- /dev/null +++ b/cpt/test/assets/__init__.py @@ -0,0 +1,16 @@ +import os +import shutil + + +def copy_assets(src_folder, dst_folder, assets=None): + assets_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "files") + if src_folder: + src_folder = os.path.join(assets_path, src_folder) + assets = assets or os.listdir(src_folder) + for asset in assets: + s = os.path.join(src_folder, asset) + d = os.path.join(dst_folder, asset) + if os.path.isdir(s): + shutil.copytree(s, d) + else: + shutil.copy2(s, d) diff --git a/cpt/test/assets/genconanfile.py b/cpt/test/assets/genconanfile.py new file mode 100644 index 00000000..f253d584 --- /dev/null +++ b/cpt/test/assets/genconanfile.py @@ -0,0 +1,390 @@ +from conans.model.ref import ConanFileReference + + +class GenConanfile(object): + """ + USAGE: + + x = GenConanfile().with_import("import os").\ + with_setting("os").\ + with_option("shared", [True, False]).\ + with_default_option("shared", True).\ + with_build_msg("holaaa").\ + with_build_msg("adiooos").\ + with_package_file("file.txt", "hola").\ + with_package_file("file2.txt", "hola") + """ + + def __init__(self, name=None, version=None): + self._imports = ["from conans import ConanFile"] + self._name = name + self._version = version + self._settings = [] + self._options = {} + self._generators = [] + self._default_options = {} + self._provides = [] + self._deprecated = None + self._package_files = {} + self._package_files_env = {} + self._package_files_link = {} + self._build_messages = [] + self._scm = {} + self._requires = [] + self._requirements = [] + self._build_requires = [] + self._build_requirements = [] + self._revision_mode = None + self._package_info = {} + self._package_id_lines = [] + self._test_lines = [] + + def with_name(self, name): + self._name = name + return self + + def with_version(self, version): + self._version = version + return self + + def with_provides(self, provides): + self._provides.append(provides) + return self + + def with_deprecated(self, deprecated): + self._deprecated = deprecated + return self + + def with_revision_mode(self, revision_mode): + self._revision_mode = revision_mode + return self + + def with_scm(self, scm): + self._scm = scm + return self + + def with_generator(self, generator): + self._generators.append(generator) + return self + + def with_require(self, ref, private=False, override=False): + ref_str = ref.full_str() if isinstance(ref, ConanFileReference) else ref + self._requires.append((ref_str, private, override)) + return self + + def with_requires(self, *refs): + for ref in refs: + self.with_require(ref) + return self + + def with_requirement(self, ref, private=False, override=False): + ref_str = ref.full_str() if isinstance(ref, ConanFileReference) else ref + self._requirements.append((ref_str, private, override)) + return self + + def with_build_requires(self, *refs): + for ref in refs: + ref_str = ref.full_str() if isinstance(ref, ConanFileReference) else ref + self._build_requires.append(ref_str) + return self + + def with_build_requirement(self, ref, force_host_context=False): + ref_str = ref.full_str() if isinstance(ref, ConanFileReference) else ref + self._build_requirements.append((ref_str, force_host_context)) + return self + + def with_import(self, i): + if i not in self._imports: + self._imports.append(i) + return self + + def with_setting(self, setting): + self._settings.append(setting) + return self + + def with_settings(self, *settings): + self._settings.extend(settings) + return self + + def with_option(self, option_name, values): + self._options[option_name] = values + return self + + def with_default_option(self, option_name, value): + self._default_options[option_name] = value + return self + + def with_package_file(self, file_name, contents=None, env_var=None, link=None): + if not contents and not env_var: + raise Exception("Specify contents or env_var") + self.with_import("import os") + self.with_import("from conans import tools") + if contents: + self._package_files[file_name] = contents + if link: + self._package_files_link[file_name] = link + if env_var: + self._package_files_env[file_name] = env_var + return self + + def with_build_msg(self, msg): + self._build_messages.append(msg) + return self + + def with_package_info(self, cpp_info=None, env_info=None): + assert isinstance(cpp_info, dict), "cpp_info ({}) expects dict".format(type(cpp_info)) + assert isinstance(env_info, dict), "env_info ({}) expects dict".format(type(env_info)) + if cpp_info: + self._package_info["cpp_info"] = cpp_info + if env_info: + self._package_info["env_info"] = env_info + return self + + def with_package_id(self, line): + self._package_id_lines.append(line) + return self + + def with_test(self, line): + self._test_lines.append(line) + return self + + @property + def _name_line(self): + if not self._name: + return "" + return "name = '{}'".format(self._name) + + @property + def _version_line(self): + if not self._version: + return "" + return "version = '{}'".format(self._version) + + @property + def _provides_line(self): + if not self._provides: + return "" + line = ", ".join('"{}"'.format(provide) for provide in self._provides) + return "provides = {}".format(line) + + @property + def _deprecated_line(self): + if not self._deprecated: + return "" + return "deprecated = {}".format(self._deprecated) + + @property + def _scm_line(self): + if not self._scm: + return "" + line = ", ".join('"%s": "%s"' % (k, v) for k, v in self._scm.items()) + return "scm = {%s}" % line + + @property + def _generators_line(self): + if not self._generators: + return "" + line = ", ".join('"{}"'.format(generator) for generator in self._generators) + return "generators = {}".format(line) + + @property + def _revision_mode_line(self): + if not self._revision_mode: + return "" + line = "revision_mode=\"{}\"".format(self._revision_mode) + return line + + @property + def _settings_line(self): + if not self._settings: + return "" + line = ", ".join('"%s"' % s for s in self._settings) + return "settings = {}".format(line) + + @property + def _options_line(self): + if not self._options: + return "" + line = ", ".join('"%s": %s' % (k, v) for k, v in self._options.items()) + tmp = "options = {%s}" % line + return tmp + + @property + def _default_options_line(self): + if not self._default_options: + return "" + line = ", ".join('"%s": %s' % (k, v) for k, v in self._default_options.items()) + tmp = "default_options = {%s}" % line + return tmp + + @property + def _build_requirements_method(self): + if not self._build_requirements: + return "" + + lines = [] + for ref, force_host_context in self._build_requirements: + force_host = ", force_host_context=True" if force_host_context else "" + lines.append(' self.build_requires("{}"{})'.format(ref, force_host)) + return "def build_requirements(self):\n{}\n".format("\n".join(lines)) + + @property + def _build_requires_line(self): + if not self._build_requires: + return "" + line = ", ".join(['"{}"'.format(r) for r in self._build_requires]) + tmp = "build_requires = %s" % line + return tmp + + @property + def _requires_line(self): + if not self._requires: + return "" + items = [] + for ref, private, override in self._requires: + if private or override: + private_str = ", 'private'" if private else "" + override_str = ", 'override'" if override else "" + items.append('("{}"{}{})'.format(ref, private_str, override_str)) + else: + items.append('"{}"'.format(ref)) + tmp = "requires = ({}, )".format(", ".join(items)) + return tmp + + @property + def _requirements_method(self): + if not self._requirements: + return "" + + lines = [] + for ref, private, override in self._requirements: + private_str = ", private=True" if private else "" + override_str = ", override=True" if override else "" + lines.append(' self.requires("{}"{}{})'.format(ref, private_str, override_str)) + + return """ + def requirements(self): +{} + """.format("\n".join(lines)) + + @property + def _package_method(self): + lines = [] + if self._package_files: + lines = [' tools.save(os.path.join(self.package_folder, "{}"), "{}")' + ''.format(key, value) + for key, value in self._package_files.items()] + + if self._package_files_env: + lines.extend([' tools.save(os.path.join(self.package_folder, "{}"), ' + 'os.getenv("{}"))'.format(key, value) + for key, value in self._package_files_env.items()]) + if self._package_files_link: + lines.extend([' with tools.chdir(os.path.dirname(' + 'os.path.join(self.package_folder, "{}"))):\n' + ' os.symlink(os.path.basename("{}"), ' + 'os.path.join(self.package_folder, "{}"))'.format(key, key, value) + for key, value in self._package_files_link.items()]) + + if not lines: + return "" + return """ + def package(self): +{} + """.format("\n".join(lines)) + + @property + def _build_method(self): + if not self._build_messages: + return "" + lines = [' self.output.warn("{}")'.format(m) for m in self._build_messages] + return """ + def build(self): +{} + """.format("\n".join(lines)) + + @property + def _package_info_method(self): + if not self._package_info: + return "" + lines = [] + if "cpp_info" in self._package_info: + for k, v in self._package_info["cpp_info"].items(): + if k == "components": + for comp_name, comp in v.items(): + for comp_attr_name, comp_attr_value in comp.items(): + lines.append(' self.cpp_info.components["{}"].{} = {}'.format( + comp_name, comp_attr_name, str(comp_attr_value))) + else: + lines.append(' self.cpp_info.{} = {}'.format(k, str(v))) + if "env_info" in self._package_info: + for k, v in self._package_info["env_info"].items(): + lines.append(' self.env_info.{} = {}'.format(k, str(v))) + + return """ + def package_info(self): +{} + """.format("\n".join(lines)) + + @property + def _package_id_method(self): + if not self._package_id_lines: + return "" + lines = [' {}'.format(line) for line in self._package_id_lines] + return """ + def package_id(self): +{} + """.format("\n".join(lines)) + + @property + def _test_method(self): + if not self._test_lines: + return "" + lines = ['', ' def test(self):'] + [' %s' % m for m in self._test_lines] + return "\n".join(lines) + + def __repr__(self): + ret = [] + ret.extend(self._imports) + ret.append("class HelloConan(ConanFile):") + if self._name_line: + ret.append(" {}".format(self._name_line)) + if self._version_line: + ret.append(" {}".format(self._version_line)) + if self._provides_line: + ret.append(" {}".format(self._provides_line)) + if self._deprecated_line: + ret.append(" {}".format(self._deprecated_line)) + if self._generators_line: + ret.append(" {}".format(self._generators_line)) + if self._requires_line: + ret.append(" {}".format(self._requires_line)) + if self._build_requires_line: + ret.append(" {}".format(self._build_requires_line)) + if self._requirements_method: + ret.append(" {}".format(self._requirements_method)) + if self._build_requirements_method: + ret.append(" {}".format(self._build_requirements_method)) + if self._scm: + ret.append(" {}".format(self._scm_line)) + if self._revision_mode_line: + ret.append(" {}".format(self._revision_mode_line)) + if self._settings_line: + ret.append(" {}".format(self._settings_line)) + if self._options_line: + ret.append(" {}".format(self._options_line)) + if self._default_options_line: + ret.append(" {}".format(self._default_options_line)) + if self._build_method: + ret.append(" {}".format(self._build_method)) + if self._package_method: + ret.append(" {}".format(self._package_method)) + if self._package_info_method: + ret.append(" {}".format(self._package_info_method)) + if self._package_id_lines: + ret.append(" {}".format(self._package_id_method)) + if self._test_method: + ret.append(" {}".format(self._test_method)) + if len(ret) == 2: + ret.append(" pass") + return "\n".join(ret) diff --git a/cpt/test/integration/base.py b/cpt/test/integration/base.py index f087a942..19829c69 100644 --- a/cpt/test/integration/base.py +++ b/cpt/test/integration/base.py @@ -2,10 +2,11 @@ import unittest from conans.util.files import mkdir_tmp +from conans import __version__ as client_version from conans import tools from conans.client.conan_api import ConanAPIV1 -from conans.test.utils.tools import TestBufferConanOutput +from cpt.test.utils.tools import TestBufferConanOutput CONAN_UPLOAD_URL = os.getenv("CONAN_UPLOAD_URL", "https://conan.jfrog.io/conan/api/conan/conan-testsuite") @@ -39,7 +40,10 @@ def save_conanfile(self, conanfile): def create_project(self): with tools.chdir(self.tmp_folder): - self.api.new("hello/0.1.0", pure_c=True) + if tools.Version(client_version) >= "1.32.0": + self.api.new("hello/0.1.0", pure_c=True, exports_sources=True) + else: + self.api.new("hello/0.1.0") @property def root_project_folder(self): @@ -50,5 +54,3 @@ def root_project_folder(self): else: dir_path = os.path.abspath(os.path.join(dir_path, os.pardir)) raise Exception("Cannot find root project folder") - - diff --git a/cpt/test/integration/conan_version_test.py b/cpt/test/integration/conan_version_test.py deleted file mode 100644 index 904438e9..00000000 --- a/cpt/test/integration/conan_version_test.py +++ /dev/null @@ -1,18 +0,0 @@ -import unittest -from cpt.packager import ConanMultiPackager - - -class ConanVersionTest(unittest.TestCase): - - def test_conan_incompatible_version(self): - cpt = ConanMultiPackager(username="user", reference="lib/1.0@conan/stable") - cpt._newest_supported_conan_version = "2.0" - cpt._client_conan_version = "2.1" - with self.assertRaisesRegexp(Exception, "Conan/CPT version mismatch. " - "Conan version installed: 2.1 . " - "This version of CPT supports only Conan < 2.0"): - cpt.run() - - cpt._newest_supported_conan_version = "2.1" - cpt._client_conan_version = "2.1" - cpt.run() diff --git a/cpt/test/integration/update_deps_test.py b/cpt/test/integration/update_deps_test.py index 28d6a869..8b3974b1 100644 --- a/cpt/test/integration/update_deps_test.py +++ b/cpt/test/integration/update_deps_test.py @@ -1,7 +1,7 @@ import unittest from conans.client.tools import environment_append -from conans.test.utils.tools import TestClient, TestServer +from cpt.test.utils.tools import TestClient, TestServer from cpt.test.unit.utils import MockCIManager from cpt.test.test_client.tools import get_patched_multipackager diff --git a/cpt/test/integration/update_python_reqs_test.py b/cpt/test/integration/update_python_reqs_test.py index 5f0a177d..90bc7ba2 100644 --- a/cpt/test/integration/update_python_reqs_test.py +++ b/cpt/test/integration/update_python_reqs_test.py @@ -1,6 +1,6 @@ import unittest -from conans.test.utils.tools import TestClient +from cpt.test.utils.tools import TestClient from cpt.test.test_client.tools import get_patched_multipackager diff --git a/cpt/test/integration/update_some_deps_test.py b/cpt/test/integration/update_some_deps_test.py index 803a3ebe..38d48835 100644 --- a/cpt/test/integration/update_some_deps_test.py +++ b/cpt/test/integration/update_some_deps_test.py @@ -1,7 +1,7 @@ import unittest from conans.client.tools import environment_append -from conans.test.utils.tools import TestClient, TestServer +from cpt.test.utils.tools import TestClient, TestServer from cpt.test.unit.utils import MockCIManager from cpt.test.test_client.tools import get_patched_multipackager diff --git a/cpt/test/integration/upload_test.py b/cpt/test/integration/upload_test.py index 8ada72e5..98b9f688 100644 --- a/cpt/test/integration/upload_test.py +++ b/cpt/test/integration/upload_test.py @@ -1,6 +1,6 @@ from conans.client import tools from conans.errors import ConanException -from conans.test.utils.test_files import temp_folder +from cpt.test.utils.test_files import temp_folder from cpt.test.integration.base import BaseTest from cpt.packager import ConanMultiPackager diff --git a/cpt/test/test_client/config_install_test.py b/cpt/test/test_client/config_install_test.py index bad3af12..57435873 100644 --- a/cpt/test/test_client/config_install_test.py +++ b/cpt/test/test_client/config_install_test.py @@ -3,7 +3,7 @@ import zipfile from conans.client.tools import environment_append -from conans.test.utils.tools import TestClient, TestServer +from cpt.test.utils.tools import TestClient, TestServer from cpt.test.test_client.tools import get_patched_multipackager diff --git a/cpt/test/test_client/invalid_config_checks_test.py b/cpt/test/test_client/invalid_config_checks_test.py index 41aca6b5..3bd6c174 100644 --- a/cpt/test/test_client/invalid_config_checks_test.py +++ b/cpt/test/test_client/invalid_config_checks_test.py @@ -1,7 +1,7 @@ import unittest from conans.client.tools import environment_append -from conans.test.utils.tools import TestClient, TestServer +from cpt.test.utils.tools import TestClient, TestServer from cpt.test.test_client.tools import get_patched_multipackager diff --git a/cpt/test/test_client/upload_checks_test.py b/cpt/test/test_client/upload_checks_test.py index a1fe4c52..496f5bf9 100644 --- a/cpt/test/test_client/upload_checks_test.py +++ b/cpt/test/test_client/upload_checks_test.py @@ -3,7 +3,7 @@ import zipfile from conans.client.tools import environment_append -from conans.test.utils.tools import TestClient, TestServer +from cpt.test.utils.tools import TestClient, TestServer from cpt.test.unit.utils import MockCIManager from cpt.test.test_client.tools import get_patched_multipackager diff --git a/cpt/test/test_client/visual_toolsets_test.py b/cpt/test/test_client/visual_toolsets_test.py index 4cd3c3bd..66a292de 100644 --- a/cpt/test/test_client/visual_toolsets_test.py +++ b/cpt/test/test_client/visual_toolsets_test.py @@ -2,7 +2,7 @@ import unittest from conans.client.tools import environment_append -from conans.test.utils.tools import TestClient, TestServer +from cpt.test.utils.tools import TestClient, TestServer from cpt.test.test_client.tools import get_patched_multipackager diff --git a/cpt/test/unit/auth_test.py b/cpt/test/unit/auth_test.py index 6060bcbb..de7dbdde 100644 --- a/cpt/test/unit/auth_test.py +++ b/cpt/test/unit/auth_test.py @@ -1,7 +1,7 @@ import unittest from conans import tools -from conans.test.utils.tools import TestBufferConanOutput +from cpt.test.utils.tools import TestBufferConanOutput from cpt.auth import AuthManager from cpt.printer import Printer from cpt.test.unit.packager_test import MockConanAPI diff --git a/cpt/test/unit/ci_manager_test.py b/cpt/test/unit/ci_manager_test.py index b15b9605..be0c3e6a 100644 --- a/cpt/test/unit/ci_manager_test.py +++ b/cpt/test/unit/ci_manager_test.py @@ -1,7 +1,7 @@ import unittest import os -from conans.test.utils.tools import TestBufferConanOutput +from cpt.test.utils.tools import TestBufferConanOutput from cpt.packager import ConanMultiPackager from cpt.ci_manager import CIManager from conans import tools diff --git a/cpt/test/unit/packager_test.py b/cpt/test/unit/packager_test.py index eceb64fa..d4aa97d6 100644 --- a/cpt/test/unit/packager_test.py +++ b/cpt/test/unit/packager_test.py @@ -8,7 +8,7 @@ from cpt.builds_generator import BuildConf from cpt.packager import ConanMultiPackager from conans import tools -from conans.test.utils.tools import TestBufferConanOutput +from cpt.test.utils.tools import TestBufferConanOutput from conans.model.ref import ConanFileReference from cpt.test.unit.utils import MockConanAPI, MockRunner, MockCIManager diff --git a/cpt/test/unit/utils.py b/cpt/test/unit/utils.py index 78b83bb2..2de41313 100644 --- a/cpt/test/unit/utils.py +++ b/cpt/test/unit/utils.py @@ -5,7 +5,7 @@ from conans import tools from conans.model.ref import ConanFileReference -from conans.test.utils.test_files import temp_folder +from cpt.test.utils.test_files import temp_folder from conans.util.files import save from conans.model.version import Version from cpt import get_client_version diff --git a/cpt/test/utils/__init__.py b/cpt/test/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cpt/test/utils/mocks.py b/cpt/test/utils/mocks.py new file mode 100644 index 00000000..f4baf7c4 --- /dev/null +++ b/cpt/test/utils/mocks.py @@ -0,0 +1,231 @@ +import os +import sys +from collections import Counter, defaultdict, namedtuple + + +import six +from six import StringIO + +from conans import ConanFile, Options +from conans.client.output import ConanOutput +from conans.client.userio import UserIO +from conans.model.env_info import DepsEnvInfo, EnvInfo, EnvValues +from conans.model.options import PackageOptions +from conans.model.user_info import DepsUserInfo + + +class LocalDBMock(object): + + def __init__(self, user=None, access_token=None, refresh_token=None): + self.user = user + self.access_token = access_token + self.refresh_token = refresh_token + + def get_login(self, _): + return self.user, self.access_token, self.refresh_token + + def get_username(self, _): + return self.user + + def store(self, user, access_token, refresh_token, _): + self.user = user + self.access_token = access_token + self.refresh_token = refresh_token + + +class MockedUserIO(UserIO): + """ + Mock for testing. If get_username or get_password is requested will raise + an exception except we have a value to return. + """ + + def __init__(self, logins, ins=sys.stdin, out=None): + """ + logins is a dict of {remote: list(user, password)} + will return sequentially + """ + assert isinstance(logins, dict) + self.logins = logins + self.login_index = Counter() + UserIO.__init__(self, ins, out) + + def get_username(self, remote_name): + username_env = self._get_env_username(remote_name) + if username_env: + return username_env + + self._raise_if_non_interactive() + sub_dict = self.logins[remote_name] + index = self.login_index[remote_name] + if len(sub_dict) - 1 < index: + raise Exception("Bad user/password in testing framework, " + "provide more tuples or input the right ones") + return sub_dict[index][0] + + def get_password(self, remote_name): + """Overridable for testing purpose""" + password_env = self._get_env_password(remote_name) + if password_env: + return password_env + + self._raise_if_non_interactive() + sub_dict = self.logins[remote_name] + index = self.login_index[remote_name] + tmp = sub_dict[index][1] + self.login_index.update([remote_name]) + return tmp + + +class MockSettings(object): + + def __init__(self, values): + self.values = values + + def get_safe(self, value): + return self.values.get(value, None) + + +class MockCppInfo(object): + def __init__(self): + self.bin_paths = [] + self.lib_paths = [] + self.include_paths = [] + self.libs = [] + self.cflags = [] + self.cppflags = [] + self.defines = [] + self.frameworks = [] + self.framework_paths = [] + + +class MockDepsCppInfo(defaultdict): + + def __init__(self): + super(MockDepsCppInfo, self).__init__(MockCppInfo) + self.include_paths = [] + self.lib_paths = [] + self.libs = [] + self.defines = [] + self.cflags = [] + self.cxxflags = [] + self.sharedlinkflags = [] + self.exelinkflags = [] + self.sysroot = "" + self.frameworks = [] + self.framework_paths = [] + self.system_libs = [] + + @property + def deps(self): + return self.keys() + + +class MockConanfile(ConanFile): + + def __init__(self, settings, options=None, runner=None): + self.deps_cpp_info = MockDepsCppInfo() + self.settings = settings + self.runner = runner + self.options = options or MockOptions({}) + self.generators = [] + self.output = TestBufferConanOutput() + + self.should_configure = True + self.should_build = True + self.should_install = True + self.should_test = True + + self.package_folder = None + + def run(self, *args, **kwargs): + if self.runner: + kwargs["output"] = None + self.runner(*args, **kwargs) + + +class ConanFileMock(ConanFile): + + def __init__(self, shared=None, options=None, options_values=None): + options = options or "" + self.command = None + self.path = None + self.source_folder = self.build_folder = "." + self.settings = None + self.options = Options(PackageOptions.loads(options)) + if options_values: + for var, value in options_values.items(): + self.options._data[var] = value + self.deps_cpp_info = MockDepsCppInfo() # ("deps_cpp_info", "sysroot")("/path/to/sysroot") + self.deps_cpp_info.sysroot = "/path/to/sysroot" + self.output = TestBufferConanOutput() + self.in_local_cache = False + self.install_folder = "myinstallfolder" + if shared is not None: + self.options = namedtuple("options", "shared")(shared) + self.should_configure = True + self.should_build = True + self.should_install = True + self.should_test = True + self.generators = [] + self.captured_env = {} + self.deps_env_info = DepsEnvInfo() + self.env_info = EnvInfo() + self.deps_user_info = DepsUserInfo() + self._conan_env_values = EnvValues() + + def run(self, command): + self.command = command + self.path = os.environ["PATH"] + self.captured_env = {key: value for key, value in os.environ.items()} + + +MockOptions = MockSettings + + +class TestBufferConanOutput(ConanOutput): + """ wraps the normal output of the application, captures it into an stream + and gives it operators similar to string, so it can be compared in tests + """ + + def __init__(self): + ConanOutput.__init__(self, StringIO(), color=False) + + def __repr__(self): + # FIXME: I'm sure there is a better approach. Look at six docs. + if six.PY2: + return str(self._stream.getvalue().encode("ascii", "ignore")) + else: + return self._stream.getvalue() + + def __str__(self, *args, **kwargs): + return self.__repr__() + + def __eq__(self, value): + return self.__repr__() == value + + def __ne__(self, value): + return not self.__eq__(value) + + def __contains__(self, value): + return value in self.__repr__() + + +# cli2.0 +class RedirectedTestOutput(StringIO): + def __init__(self): + super(RedirectedTestOutput, self).__init__() + + def __repr__(self): + return self.getvalue() + + def __str__(self, *args, **kwargs): + return self.__repr__() + + def __eq__(self, value): + return self.__repr__() == value + + def __ne__(self, value): + return not self.__eq__(value) + + def __contains__(self, value): + return value in self.__repr__() diff --git a/cpt/test/utils/scm.py b/cpt/test/utils/scm.py new file mode 100644 index 00000000..4dc8f574 --- /dev/null +++ b/cpt/test/utils/scm.py @@ -0,0 +1,126 @@ +import errno +import os +import shutil +import stat +import subprocess +import tempfile +import unittest +import uuid + +from six.moves.urllib.parse import quote + +from conans.client.tools import get_cased_path, Git, chdir, SVN +from cpt.test.utils.test_files import temp_folder +from conans.util.files import save_files, mkdir +from conans.util.runners import check_output_runner + + +def create_local_git_repo(files=None, branch=None, submodules=None, folder=None, commits=1, + tags=None, origin_url=None): + tmp = folder or temp_folder() + tmp = get_cased_path(tmp) + if files: + save_files(tmp, files) + git = Git(tmp) + git.run("init .") + git.run('config user.email "you@example.com"') + git.run('config user.name "Your Name"') + + if branch: + git.run("checkout -b %s" % branch) + + git.run("add .") + for i in range(0, commits): + git.run('commit --allow-empty -m "commiting"') + + tags = tags or [] + for tag in tags: + git.run("tag %s" % tag) + + if submodules: + for submodule in submodules: + git.run('submodule add "%s"' % submodule) + git.run('commit -m "add submodules"') + + if origin_url: + git.run('remote add origin {}'.format(origin_url)) + + return tmp.replace("\\", "/"), git.get_revision() + + +def create_local_svn_checkout(files, repo_url, rel_project_path=None, + commit_msg='default commit message', delete_checkout=True, + folder=None): + tmp_dir = folder or temp_folder() + try: + rel_project_path = rel_project_path or str(uuid.uuid4()) + # Do not use SVN class as it is what we will be testing + subprocess.check_output('svn co "{url}" "{path}"'.format(url=repo_url, + path=tmp_dir), + shell=True) + tmp_project_dir = os.path.join(tmp_dir, rel_project_path) + mkdir(tmp_project_dir) + save_files(tmp_project_dir, files) + with chdir(tmp_project_dir): + subprocess.check_output("svn add .", shell=True) + subprocess.check_output('svn commit -m "{}"'.format(commit_msg), shell=True) + if SVN.get_version() >= SVN.API_CHANGE_VERSION: + rev = check_output_runner("svn info --show-item revision").strip() + else: + import xml.etree.ElementTree as ET + output = check_output_runner("svn info --xml").strip() + root = ET.fromstring(output) + rev = root.findall("./entry")[0].get("revision") + project_url = repo_url + "/" + quote(rel_project_path.replace("\\", "/")) + return project_url, rev + finally: + if delete_checkout: + shutil.rmtree(tmp_dir, ignore_errors=False, onerror=try_remove_readonly) + + +def create_remote_svn_repo(folder=None): + tmp_dir = folder or temp_folder() + subprocess.check_output('svnadmin create "{}"'.format(tmp_dir), shell=True) + return SVN.file_protocol + quote(tmp_dir.replace("\\", "/"), safe='/:') + + +class SVNLocalRepoTestCase(unittest.TestCase): + path_with_spaces = True + + def _create_local_svn_repo(self): + folder = os.path.join(self._tmp_folder, 'repo_server') + return create_remote_svn_repo(folder) + + def gimme_tmp(self, create=True): + tmp = os.path.join(self._tmp_folder, str(uuid.uuid4())) + if create: + os.makedirs(tmp) + return tmp + + def create_project(self, files, rel_project_path=None, commit_msg='default commit message', + delete_checkout=True): + tmp_dir = self.gimme_tmp() + return create_local_svn_checkout(files, self.repo_url, rel_project_path=rel_project_path, + commit_msg=commit_msg, delete_checkout=delete_checkout, + folder=tmp_dir) + + def run(self, *args, **kwargs): + tmp_folder = tempfile.mkdtemp(suffix='_conans') + try: + self._tmp_folder = os.path.join(tmp_folder, 'path with spaces' + if self.path_with_spaces else 'pathwithoutspaces') + os.makedirs(self._tmp_folder) + self.repo_url = self._create_local_svn_repo() + super(SVNLocalRepoTestCase, self).run(*args, **kwargs) + finally: + shutil.rmtree(tmp_folder, ignore_errors=False, onerror=try_remove_readonly) + + +def try_remove_readonly(func, path, exc): # TODO: May promote to conan tools? + # src: https://stackoverflow.com/questions/1213706/what-user-do-python-scripts-run-as-in-windows + excvalue = exc[1] + if func in (os.rmdir, os.remove, os.unlink) and excvalue.errno == errno.EACCES: + os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777 + func(path) + else: + raise OSError("Cannot make read-only %s" % path) diff --git a/cpt/test/utils/server_launcher.py b/cpt/test/utils/server_launcher.py new file mode 100644 index 00000000..b273613e --- /dev/null +++ b/cpt/test/utils/server_launcher.py @@ -0,0 +1,113 @@ +#!/usr/bin/python +import os +import shutil +import time + +from conans import SERVER_CAPABILITIES +from conans.server.conf import get_server_store +from conans.server.crypto.jwt.jwt_credentials_manager import JWTCredentialsManager +from conans.server.crypto.jwt.jwt_updown_manager import JWTUpDownAuthManager +from conans.server.migrate import migrate_and_get_server_config +from conans.server.rest.server import ConanServer +from conans.server.service.authorize import BasicAuthenticator, BasicAuthorizer +from cpt.test.utils.test_files import temp_folder + + +TESTING_REMOTE_PRIVATE_USER = "private_user" +TESTING_REMOTE_PRIVATE_PASS = "private_pass" + + +class TestServerLauncher(object): + + def __init__(self, base_path=None, read_permissions=None, + write_permissions=None, users=None, base_url=None, plugins=None, + server_capabilities=None): + + plugins = plugins or [] + if not base_path: + base_path = temp_folder() + + if not os.path.exists(base_path): + raise Exception("Base path not exist! %s") + + self._base_path = base_path + + server_config = migrate_and_get_server_config(base_path) + if server_capabilities is None: + server_capabilities = set(SERVER_CAPABILITIES) + + # Encode and Decode signature for Upload and Download service + updown_auth_manager = JWTUpDownAuthManager(server_config.updown_secret, + server_config.authorize_timeout) + base_url = base_url or server_config.public_url + self.server_store = get_server_store(server_config.disk_storage_path, + base_url, updown_auth_manager) + + # Prepare some test users + if not read_permissions: + read_permissions = server_config.read_permissions + read_permissions.append(("private_library/1.0.0@private_user/testing", "*")) + read_permissions.append(("*/*@*/*", "*")) + + if not write_permissions: + write_permissions = server_config.write_permissions + + if not users: + users = dict(server_config.users) + + users[TESTING_REMOTE_PRIVATE_USER] = TESTING_REMOTE_PRIVATE_PASS + + authorizer = BasicAuthorizer(read_permissions, write_permissions) + authenticator = BasicAuthenticator(users) + credentials_manager = JWTCredentialsManager(server_config.jwt_secret, + server_config.jwt_expire_time) + + self.port = server_config.port + self.ra = ConanServer(self.port, credentials_manager, updown_auth_manager, + authorizer, authenticator, self.server_store, + server_capabilities) + for plugin in plugins: + self.ra.api_v1.install(plugin) + self.ra.api_v2.install(plugin) + + def start(self, daemon=True): + """from multiprocessing import Process + self.p1 = Process(target=ra.run, kwargs={"host": "0.0.0.0"}) + self.p1.start() + self.p1""" + import threading + + class StoppableThread(threading.Thread): + """Thread class with a stop() method. The thread itself has to check + regularly for the stopped() condition.""" + + def __init__(self, *args, **kwargs): + super(StoppableThread, self).__init__(*args, **kwargs) + self._stop = threading.Event() + + def stop(self): + self._stop.set() + + def stopped(self): + return self._stop.isSet() + + self.t1 = StoppableThread(target=self.ra.run, kwargs={"host": "0.0.0.0", "quiet": True}) + self.t1.daemon = daemon + self.t1.start() + time.sleep(1) + + def stop(self): + self.ra.root_app.close() + self.t1.stop() + + def clean(self): + if os.path.exists(self._base_path): + try: + shutil.rmtree(self._base_path) + except Exception: + print("Can't clean the test server data, probably a server process is still opened") + + +if __name__ == "__main__": + server = TestServerLauncher() + server.start(daemon=False) diff --git a/cpt/test/utils/test_files.py b/cpt/test/utils/test_files.py new file mode 100644 index 00000000..cbba03f9 --- /dev/null +++ b/cpt/test/utils/test_files.py @@ -0,0 +1,91 @@ +import os +import platform +import shutil +import tarfile +import tempfile + +import time +from six import BytesIO + +from conans.client.tools.files import untargz +from conans.client.tools.win import get_cased_path +from conans.errors import ConanException +from conans.paths import PACKAGE_TGZ_NAME +from conans.test import CONAN_TEST_FOLDER +from conans.util.files import gzopen_without_timestamps + + +def wait_until_removed(folder): + latest_exception = None + for _ in range(50): # Max 5 seconds + time.sleep(0.1) + try: + shutil.rmtree(folder) + break + except Exception as e: + latest_exception = e + else: + raise Exception("Could remove folder %s: %s" % (folder, latest_exception)) + + +def temp_folder(path_with_spaces=True, create_dir=True): + t = tempfile.mkdtemp(suffix='conans', dir=CONAN_TEST_FOLDER) + # Make sure that the temp folder is correctly cased, as tempfile return lowercase for Win + t = get_cased_path(t) + # necessary for Mac OSX, where the temp folders in /var/ are symlinks to /private/var/ + t = os.path.realpath(t) + # FreeBSD and Solaris do not use GNU Make as a the default 'make' program which has trouble + # with spaces in paths generated by CMake + if not path_with_spaces or platform.system() == "FreeBSD" or platform.system() == "SunOS": + path = "pathwithoutspaces" + else: + path = "path with spaces" + nt = os.path.join(t, path) + if create_dir: + os.makedirs(nt) + return nt + + +def uncompress_packaged_files(paths, pref): + rev = paths.get_last_revision(pref.ref).revision + prev = paths.get_last_package_revision(pref.copy_with_revs(rev, None)).revision + pref = pref.copy_with_revs(rev, prev) + + package_path = paths.package(pref) + if not(os.path.exists(os.path.join(package_path, PACKAGE_TGZ_NAME))): + raise ConanException("%s not found in %s" % (PACKAGE_TGZ_NAME, package_path)) + tmp = temp_folder() + untargz(os.path.join(package_path, PACKAGE_TGZ_NAME), tmp) + return tmp + + +def scan_folder(folder): + scanned_files = [] + for root, dirs, files in os.walk(folder): + dirs[:] = [d for d in dirs if d != "__pycache__"] + relative_path = os.path.relpath(root, folder) + for f in files: + if f.endswith(".pyc"): + continue + relative_name = os.path.normpath(os.path.join(relative_path, f)).replace("\\", "/") + scanned_files.append(relative_name) + + return sorted(scanned_files) + + +def tgz_with_contents(files): + folder = temp_folder() + file_path = os.path.join(folder, "myfile.tar.gz") + + with open(file_path, "wb") as tgz_handle: + tgz = gzopen_without_timestamps("myfile.tar.gz", mode="w", fileobj=tgz_handle) + + for name, content in files.items(): + info = tarfile.TarInfo(name=name) + data = content.encode('utf-8') + info.size = len(data) + tgz.addfile(tarinfo=info, fileobj=BytesIO(data)) + + tgz.close() + + return file_path diff --git a/cpt/test/utils/tools.py b/cpt/test/utils/tools.py new file mode 100644 index 00000000..b406411a --- /dev/null +++ b/cpt/test/utils/tools.py @@ -0,0 +1,898 @@ +import json +import os +import random +import shlex +import shutil +import sys +import textwrap +import threading +import time +import uuid +from collections import OrderedDict +from contextlib import contextmanager + +import bottle +import requests +from mock import Mock +from requests.exceptions import HTTPError +from six.moves.urllib.parse import urlsplit, urlunsplit +from webtest.app import TestApp + +from conans import load +from conans.cli.cli import Cli +from conans.client.api.conan_api import ConanAPIV2 +from conans.client.cache.cache import ClientCache +from conans.client.cache.remote_registry import Remotes +from conans.client.command import Command +from conans.client.conan_api import Conan +from conans.client.rest.file_uploader import IterableToFileAdapter +from conans.client.runner import ConanRunner +from conans.client.tools import environment_append +from conans.client.tools.files import replace_in_file +from conans.errors import NotFoundException, RecipeNotFoundException, PackageNotFoundException +from conans.model.manifest import FileTreeManifest +from conans.model.profile import Profile +from conans.model.ref import ConanFileReference, PackageReference +from conans.model.settings import Settings +from conans.server.revision_list import _RevisionEntry +from cpt.test.assets import copy_assets +from cpt.test.assets.genconanfile import GenConanfile +from cpt.test.utils.mocks import MockedUserIO, TestBufferConanOutput +from cpt.test.utils.scm import create_local_git_repo, create_local_svn_checkout, \ + create_remote_svn_repo +from cpt.test.utils.server_launcher import (TESTING_REMOTE_PRIVATE_PASS, + TESTING_REMOTE_PRIVATE_USER, + TestServerLauncher) +from cpt.test.utils.test_files import temp_folder +from conans.util.conan_v2_mode import CONAN_V2_MODE_ENVVAR +from conans.util.env_reader import get_env +from conans.util.files import mkdir, save_files + +NO_SETTINGS_PACKAGE_ID = "5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9" + +ARTIFACTORY_DEFAULT_USER = os.getenv("ARTIFACTORY_DEFAULT_USER", "admin") +ARTIFACTORY_DEFAULT_PASSWORD = os.getenv("ARTIFACTORY_DEFAULT_PASSWORD", "password") +ARTIFACTORY_DEFAULT_URL = os.getenv("ARTIFACTORY_DEFAULT_URL", "http://localhost:8090/artifactory") + + +def inc_recipe_manifest_timestamp(cache, reference, inc_time): + ref = ConanFileReference.loads(reference) + path = cache.package_layout(ref).export() + manifest = FileTreeManifest.load(path) + manifest.time += inc_time + manifest.save(path) + + +def inc_package_manifest_timestamp(cache, package_reference, inc_time): + pref = PackageReference.loads(package_reference) + path = cache.package_layout(pref.ref).package(pref) + manifest = FileTreeManifest.load(path) + manifest.time += inc_time + manifest.save(path) + + +def test_profile(profile=None, settings=None): + if profile is None: + profile = Profile() + if profile.processed_settings is None: + profile.processed_settings = settings or Settings() + return profile + + +class TestingResponse(object): + """Wraps a response from TestApp external tool + to guarantee the presence of response.ok, response.content + and response.status_code, as it was a requests library object. + + Is instanced by TestRequester on each request""" + + def __init__(self, test_response): + self.test_response = test_response + + def close(self): + pass # Compatibility with close() method of a requests when stream=True + + @property + def headers(self): + return self.test_response.headers + + @property + def ok(self): + return self.test_response.status_code == 200 + + def raise_for_status(self): + """Raises stored :class:`HTTPError`, if one occurred.""" + http_error_msg = '' + if 400 <= self.status_code < 500: + http_error_msg = u'%s Client Error: %s' % (self.status_code, self.content) + + elif 500 <= self.status_code < 600: + http_error_msg = u'%s Server Error: %s' % (self.status_code, self.content) + + if http_error_msg: + raise HTTPError(http_error_msg, response=self) + + @property + def content(self): + return self.test_response.body + + @property + def charset(self): + return self.test_response.charset + + @charset.setter + def charset(self, newcharset): + self.test_response.charset = newcharset + + @property + def text(self): + return self.test_response.text + + def iter_content(self, chunk_size=1): # @UnusedVariable + return [self.content] + + @property + def status_code(self): + return self.test_response.status_code + + def json(self): + try: + return json.loads(self.test_response.content) + except: + raise ValueError("The response is not a JSON") + + +class TestRequester(object): + """Fake requests module calling server applications + with TestApp""" + + def __init__(self, test_servers): + self.test_servers = test_servers + + @staticmethod + def _get_url_path(url): + # Remove schema from url + _, _, path, query, _ = urlsplit(url) + url = urlunsplit(("", "", path, query, "")) + return url + + def _get_wsgi_app(self, url): + for test_server in self.test_servers.values(): + if url.startswith(test_server.fake_url): + return test_server.app + + raise Exception("Testing error: Not remote found") + + def get(self, url, **kwargs): + app, url = self._prepare_call(url, kwargs) + if app: + response = app.get(url, **kwargs) + return TestingResponse(response) + else: + return requests.get(url, **kwargs) + + def put(self, url, **kwargs): + app, url = self._prepare_call(url, kwargs) + if app: + response = app.put(url, **kwargs) + return TestingResponse(response) + else: + return requests.put(url, **kwargs) + + def delete(self, url, **kwargs): + app, url = self._prepare_call(url, kwargs) + if app: + response = app.delete(url, **kwargs) + return TestingResponse(response) + else: + return requests.delete(url, **kwargs) + + def post(self, url, **kwargs): + app, url = self._prepare_call(url, kwargs) + if app: + response = app.post(url, **kwargs) + return TestingResponse(response) + else: + requests.post(url, **kwargs) + + def _prepare_call(self, url, kwargs): + if not url.startswith("http://fake"): # Call to S3 (or external), perform a real request + return None, url + app = self._get_wsgi_app(url) + url = self._get_url_path(url) # Remove http://server.com + + self._set_auth_headers(kwargs) + + if app: + kwargs["expect_errors"] = True + kwargs.pop("stream", None) + kwargs.pop("verify", None) + kwargs.pop("auth", None) + kwargs.pop("cert", None) + kwargs.pop("timeout", None) + if "data" in kwargs: + if isinstance(kwargs["data"], IterableToFileAdapter): + data_accum = b"" + for tmp in kwargs["data"]: + data_accum += tmp + kwargs["data"] = data_accum + kwargs["params"] = kwargs["data"] + del kwargs["data"] # Parameter in test app is called "params" + if kwargs.get("json"): + # json is a high level parameter of requests, not a generic one + # translate it to data and content_type + kwargs["params"] = json.dumps(kwargs["json"]) + kwargs["content_type"] = "application/json" + kwargs.pop("json", None) + + return app, url + + @staticmethod + def _set_auth_headers(kwargs): + if kwargs.get("auth"): + mock_request = Mock() + mock_request.headers = {} + kwargs["auth"](mock_request) + if "headers" not in kwargs: + kwargs["headers"] = {} + kwargs["headers"].update(mock_request.headers) + + +class ArtifactoryServerStore(object): + + def __init__(self, repo_url, user, password): + self._user = user or ARTIFACTORY_DEFAULT_USER + self._password = password or ARTIFACTORY_DEFAULT_PASSWORD + self._repo_url = repo_url + + @property + def _auth(self): + return self._user, self._password + + @staticmethod + def _root_recipe(ref): + return "{}/{}/{}/{}".format(ref.user, ref.name, ref.version, ref.channel) + + @staticmethod + def _ref_index(ref): + return "{}/index.json".format(ArtifactoryServerStore._root_recipe(ref)) + + @staticmethod + def _pref_index(pref): + tmp = ArtifactoryServerStore._root_recipe(pref.ref) + return "{}/{}/package/{}/index.json".format(tmp, pref.ref.revision, pref.id) + + def get_recipe_revisions(self, ref): + time.sleep(0.1) # Index appears to not being updated immediately after a remove + url = "{}/{}".format(self._repo_url, self._ref_index(ref)) + response = requests.get(url, auth=self._auth) + response.raise_for_status() + the_json = response.json() + if not the_json["revisions"]: + raise RecipeNotFoundException(ref) + tmp = [_RevisionEntry(i["revision"], i["time"]) for i in the_json["revisions"]] + return tmp + + def get_package_revisions(self, pref): + time.sleep(0.1) # Index appears to not being updated immediately + url = "{}/{}".format(self._repo_url, self._pref_index(pref)) + response = requests.get(url, auth=self._auth) + response.raise_for_status() + the_json = response.json() + if not the_json["revisions"]: + raise PackageNotFoundException(pref) + tmp = [_RevisionEntry(i["revision"], i["time"]) for i in the_json["revisions"]] + return tmp + + def get_last_revision(self, ref): + revisions = self.get_recipe_revisions(ref) + return revisions[0] + + def get_last_package_revision(self, ref): + revisions = self.get_package_revisions(ref) + return revisions[0] + + def package_exists(self, pref): + try: + if pref.revision: + path = self.server_store.package(pref) + else: + path = self.test_server.server_store.package_revisions_root(pref) + return self.test_server.server_store.path_exists(path) + except NotFoundException: # When resolves the latest and there is no package + return False + + +class ArtifactoryServer(object): + + def __init__(self, *args, **kwargs): + self._user = ARTIFACTORY_DEFAULT_USER + self._password = ARTIFACTORY_DEFAULT_PASSWORD + self._url = ARTIFACTORY_DEFAULT_URL + self._repo_name = "conan_{}".format(str(uuid.uuid4()).replace("-", "")) + self.create_repository() + self.server_store = ArtifactoryServerStore(self.repo_url, self._user, self._password) + + @property + def _auth(self): + return self._user, self._password + + @property + def repo_url(self): + return "{}/{}".format(self._url, self._repo_name) + + @property + def repo_api_url(self): + return "{}/api/conan/{}".format(self._url, self._repo_name) + + def recipe_revision_time(self, ref): + revs = self.server_store.get_recipe_revisions(ref) + for r in revs: + if r.revision == ref.revision: + return r.time + return None + + def package_revision_time(self, pref): + revs = self.server_store.get_package_revisions(pref) + for r in revs: + if r.revision == pref.revision: + return r.time + return None + + def create_repository(self): + url = "{}/api/repositories/{}".format(self._url, self._repo_name) + config = {"key": self._repo_name, "rclass": "local", "packageType": "conan"} + ret = requests.put(url, auth=self._auth, json=config) + ret.raise_for_status() + + def package_exists(self, pref): + try: + revisions = self.server_store.get_package_revisions(pref) + if pref.revision: + for r in revisions: + if pref.revision == r.revision: + return True + return False + return True + except Exception: # When resolves the latest and there is no package + return False + + def recipe_exists(self, ref): + try: + revisions = self.server_store.get_recipe_revisions(ref) + if ref.revision: + for r in revisions: + if ref.revision == r.revision: + return True + return False + return True + except Exception: # When resolves the latest and there is no package + return False + + +class TestServer(object): + def __init__(self, read_permissions=None, + write_permissions=None, users=None, plugins=None, base_path=None, + server_capabilities=None, complete_urls=False): + """ + 'read_permissions' and 'write_permissions' is a list of: + [("opencv/2.3.4@lasote/testing", "user1, user2")] + + 'users': {username: plain-text-passwd} + """ + # Unique identifier for this server, will be used by TestRequester + # to determine where to call. Why? remote_manager just assing an url + # to the rest_client, so rest_client doesn't know about object instances, + # just urls, so testing framework performs a map between fake urls and instances + if read_permissions is None: + read_permissions = [("*/*@*/*", "*")] + if write_permissions is None: + write_permissions = [] + if users is None: + users = {"lasote": "mypass", "conan": "password"} + + self.fake_url = "http://fake%s.com" % str(uuid.uuid4()).replace("-", "") + base_url = "%s/v1" % self.fake_url if complete_urls else "v1" + self.test_server = TestServerLauncher(base_path, read_permissions, + write_permissions, users, + base_url=base_url, + plugins=plugins, + server_capabilities=server_capabilities) + self.app = TestApp(self.test_server.ra.root_app) + + @property + def server_store(self): + return self.test_server.server_store + + def __repr__(self): + return "TestServer @ " + self.fake_url + + def __str__(self): + return self.fake_url + + def recipe_exists(self, ref): + try: + if not ref.revision: + path = self.test_server.server_store.conan_revisions_root(ref) + else: + path = self.test_server.server_store.base_folder(ref) + return self.test_server.server_store.path_exists(path) + except NotFoundException: # When resolves the latest and there is no package + return False + + def package_exists(self, pref): + try: + if pref.revision: + path = self.test_server.server_store.package(pref) + else: + path = self.test_server.server_store.package_revisions_root(pref) + return self.test_server.server_store.path_exists(path) + except NotFoundException: # When resolves the latest and there is no package + return False + + def latest_recipe(self, ref): + rev, _ = self.test_server.server_store.get_last_revision(ref) + return ref.copy_with_rev(rev) + + def recipe_revision_time(self, ref): + if not ref.revision: + raise Exception("Pass a ref with revision (Testing framework)") + return self.test_server.server_store.get_revision_time(ref) + + def latest_package(self, pref): + if not pref.ref.revision: + raise Exception("Pass a pref with .rev.revision (Testing framework)") + prev = self.test_server.server_store.get_last_package_revision(pref) + return pref.copy_with_revs(pref.ref.revision, prev) + + def package_revision_time(self, pref): + if not pref: + raise Exception("Pass a pref with revision (Testing framework)") + tmp = self.test_server.server_store.get_package_revision_time(pref) + return tmp + + +if get_env("CONAN_TEST_WITH_ARTIFACTORY", False): + TestServer = ArtifactoryServer + + +def _copy_cache_folder(target_folder): + # Some variables affect to cache population (take a different default folder) + vars = [CONAN_V2_MODE_ENVVAR, 'CC', 'CXX', 'PATH'] + cache_key = hash('|'.join(map(str, [os.environ.get(it, None) for it in vars]))) + master_folder = _copy_cache_folder.master.setdefault(cache_key, temp_folder(create_dir=False)) + if not os.path.exists(master_folder): + # Create and populate the cache folder with the defaults + cache = ClientCache(master_folder, TestBufferConanOutput()) + cache.initialize_config() + cache.registry.initialize_remotes() + cache.initialize_default_profile() + cache.initialize_settings() + shutil.copytree(master_folder, target_folder) + + +_copy_cache_folder.master = dict() # temp_folder(create_dir=False) + + +@contextmanager +def redirect_output(target): + original_stdout = sys.stdout + original_stderr = sys.stderr + #TODO: change in 2.0 + # redirecting both of them to the same target for the moment + # to assign to Testclient out + sys.stdout = target + sys.stderr = target + try: + yield + finally: + sys.stdout = original_stdout + sys.stderr = original_stderr + + +class TestClient(object): + """ Test wrap of the conans application to launch tests in the same way as + in command line + """ + + def __init__(self, cache_folder=None, current_folder=None, servers=None, users=None, + requester_class=None, runner=None, path_with_spaces=True, + revisions_enabled=None, cpu_count=1, default_server_user=None, + cache_autopopulate=True): + """ + current_folder: Current execution folder + servers: dict of {remote_name: TestServer} + logins is a list of (user, password) for auto input in order + if required==> [("lasote", "mypass"), ("other", "otherpass")] + """ + if default_server_user is not None: + if servers is not None: + raise Exception("Cannot define both 'servers' and 'default_server_user'") + if users is not None: + raise Exception("Cannot define both 'users' and 'default_server_user'") + if default_server_user is True: + server_users = {"user": "password"} + users = {"default": [("user", "password")]} + else: + server_users = default_server_user + users = {"default": list(default_server_user.items())} + # Allow write permissions to users + server = TestServer(users=server_users, write_permissions=[("*/*@*/*", "*")]) + servers = {"default": server} + + self.users = users + if self.users is None: + self.users = {"default": [(TESTING_REMOTE_PRIVATE_USER, TESTING_REMOTE_PRIVATE_PASS)]} + + if cache_autopopulate and (not cache_folder or not os.path.exists(cache_folder)): + # Copy a cache folder already populated + self.cache_folder = cache_folder or temp_folder(path_with_spaces, create_dir=False) + _copy_cache_folder(self.cache_folder) + else: + self.cache_folder = cache_folder or temp_folder(path_with_spaces) + + self.requester_class = requester_class + self.runner = runner + + if servers and len(servers) > 1 and not isinstance(servers, OrderedDict): + raise Exception(textwrap.dedent(""" + Testing framework error: Servers should be an OrderedDict. e.g: + servers = OrderedDict() + servers["r1"] = server + servers["r2"] = TestServer() + """)) + + self.servers = servers or {} + if servers is not False: # Do not mess with registry remotes + self.update_servers() + self.current_folder = current_folder or temp_folder(path_with_spaces) + + # Once the client is ready, modify the configuration + mkdir(self.current_folder) + self.tune_conan_conf(cache_folder, cpu_count, revisions_enabled) + + def load(self, filename): + return load(os.path.join(self.current_folder, filename)) + + @property + def cache(self): + # Returns a temporary cache object intended for inspecting it + return ClientCache(self.cache_folder, TestBufferConanOutput()) + + @property + def base_folder(self): + # Temporary hack to refactor ConanApp with less changes + return self.cache_folder + + @property + def storage_folder(self): + return self.cache.store + + @property + def requester(self): + api = self.get_conan_api() + api.create_app() + return api.app.requester + + @property + def proxy(self): + api = self.get_conan_api() + api.create_app() + return api.app.proxy + + @property + def _http_requester(self): + # Check if servers are real + real_servers = any(isinstance(s, (str, ArtifactoryServer)) + for s in self.servers.values()) + if not real_servers: + if self.requester_class: + return self.requester_class(self.servers) + else: + return TestRequester(self.servers) + + def _set_revisions(self, value): + value = "1" if value else "0" + self.run("config set general.revisions_enabled={}".format(value)) + + def enable_revisions(self): + self._set_revisions(True) + assert self.cache.config.revisions_enabled + + def disable_revisions(self): + self._set_revisions(False) + assert not self.cache.config.revisions_enabled + + def tune_conan_conf(self, cache_folder, cpu_count, revisions_enabled): + # Create the default + cache = self.cache + _ = cache.config + + if cpu_count: + replace_in_file(cache.conan_conf_path, + "# cpu_count = 1", "cpu_count = %s" % cpu_count, + output=TestBufferConanOutput(), strict=not bool(cache_folder)) + + if revisions_enabled is not None: + self._set_revisions(revisions_enabled) + elif "TESTING_REVISIONS_ENABLED" in os.environ: + value = get_env("TESTING_REVISIONS_ENABLED", True) + self._set_revisions(value) + + def update_servers(self): + cache = self.cache + Remotes().save(cache.remotes_path) + registry = cache.registry + + for name, server in self.servers.items(): + if isinstance(server, ArtifactoryServer): + registry.add(name, server.repo_api_url) + self.users.update({name: [(ARTIFACTORY_DEFAULT_USER, + ARTIFACTORY_DEFAULT_PASSWORD)]}) + elif isinstance(server, TestServer): + registry.add(name, server.fake_url) + else: + registry.add(name, server) + + @contextmanager + def chdir(self, newdir): + old_dir = self.current_folder + if not os.path.isabs(newdir): + newdir = os.path.join(old_dir, newdir) + mkdir(newdir) + self.current_folder = newdir + try: + yield + finally: + self.current_folder = old_dir + + def get_conan_api_v2(self): + user_io = MockedUserIO(self.users, out=sys.stderr) + conan = ConanAPIV2(cache_folder=self.cache_folder, quiet=False, user_io=user_io, + http_requester=self._http_requester, runner=self.runner) + return conan + + def get_conan_api_v1(self, user_io=None): + if user_io: + self.out = user_io.out + else: + self.out = TestBufferConanOutput() + user_io = user_io or MockedUserIO(self.users, out=self.out) + conan = Conan(cache_folder=self.cache_folder, output=self.out, user_io=user_io, + http_requester=self._http_requester, runner=self.runner) + return conan + + def get_conan_api(self, user_io=None): + if os.getenv("CONAN_V2_CLI"): + return self.get_conan_api_v2() + else: + return self.get_conan_api_v1(user_io) + + def run_cli(self, command_line, user_io=None, assert_error=False): + conan = self.get_conan_api(user_io) + self.api = conan + if os.getenv("CONAN_V2_CLI"): + command = Cli(conan) + else: + command = Command(conan) + args = shlex.split(command_line) + current_dir = os.getcwd() + os.chdir(self.current_folder) + old_path = sys.path[:] + old_modules = list(sys.modules.keys()) + + try: + error = command.run(args) + finally: + sys.path = old_path + os.chdir(current_dir) + # Reset sys.modules to its prev state. A .copy() DOES NOT WORK + added_modules = set(sys.modules).difference(old_modules) + for added in added_modules: + sys.modules.pop(added, None) + self._handle_cli_result(command_line, assert_error=assert_error, error=error) + return error + + def run(self, command_line, user_io=None, assert_error=False): + """ run a single command as in the command line. + If user or password is filled, user_io will be mocked to return this + tuple if required + """ + # TODO: remove in 2.0 + if os.getenv("CONAN_V2_CLI"): + from cpt.test.utils.mocks import RedirectedTestOutput + self.out = RedirectedTestOutput() + with redirect_output(self.out): + error = self.run_cli(command_line, user_io=user_io, assert_error=assert_error) + else: + error = self.run_cli(command_line, user_io=user_io, assert_error=assert_error) + + return error + + def run_command(self, command, cwd=None, assert_error=False): + output = TestBufferConanOutput() + self.out = output + runner = ConanRunner(output=output) + ret = runner(command, cwd=cwd or self.current_folder) + self._handle_cli_result(command, assert_error=assert_error, error=ret) + return ret + + def _handle_cli_result(self, command, assert_error, error): + if (assert_error and not error) or (not assert_error and error): + if assert_error: + msg = " Command succeeded (failure expected): " + else: + msg = " Command failed (unexpectedly): " + exc_message = "\n{header}\n{cmd}\n{output_header}\n{output}\n{output_footer}\n".format( + header='{:-^80}'.format(msg), + output_header='{:-^80}'.format(" Output: "), + output_footer='-' * 80, + cmd=command, + output=self.out + ) + raise Exception(exc_message) + + def save(self, files, path=None, clean_first=False): + """ helper metod, will store files in the current folder + param files: dict{filename: filecontents} + """ + path = path or self.current_folder + if clean_first: + shutil.rmtree(self.current_folder, ignore_errors=True) + files = {f: str(content) for f, content in files.items()} + save_files(path, files) + if not files: + mkdir(self.current_folder) + + def copy_assets(self, origin_folder, assets=None): + copy_assets(origin_folder, self.current_folder, assets) + + # Higher level operations + def remove_all(self): + self.run("remove '*' -f") + + def export(self, ref, conanfile=GenConanfile(), args=None): + """ export a ConanFile with as "ref" and return the reference with recipe revision + """ + if conanfile: + self.save({"conanfile.py": conanfile}) + self.run("export . {} {}".format(ref.full_str(), args or "")) + rrev = self.cache.package_layout(ref).recipe_revision() + return ref.copy_with_rev(rrev) + + def init_git_repo(self, files=None, branch=None, submodules=None, folder=None, origin_url=None): + if folder is not None: + folder = os.path.join(self.current_folder, folder) + else: + folder = self.current_folder + _, commit = create_local_git_repo(files, branch, submodules, folder=folder, + origin_url=origin_url) + return commit + + +class TurboTestClient(TestClient): + tmp_json_name = ".tmp_json" + + def __init__(self, *args, **kwargs): + if "users" not in kwargs and "default_server_user" not in kwargs: + from collections import defaultdict + kwargs["users"] = defaultdict(lambda: [("conan", "password")]) + + super(TurboTestClient, self).__init__(*args, **kwargs) + + def create(self, ref, conanfile=GenConanfile(), args=None, assert_error=False): + if conanfile: + self.save({"conanfile.py": conanfile}) + full_str = "{}@".format(ref.full_str()) if not ref.user else ref.full_str() + self.run("create . {} {} --json {}".format(full_str, + args or "", self.tmp_json_name), + assert_error=assert_error) + rrev = self.cache.package_layout(ref).recipe_revision() + data = json.loads(self.load(self.tmp_json_name)) + if assert_error: + return None + package_id = data["installed"][0]["packages"][0]["id"] + package_ref = PackageReference(ref, package_id) + prev = self.cache.package_layout(ref.copy_clear_rev()).package_revision(package_ref) + return package_ref.copy_with_revs(rrev, prev) + + def upload_all(self, ref, remote=None, args=None, assert_error=False): + remote = remote or list(self.servers.keys())[0] + self.run("upload {} -c --all -r {} {}".format(ref.full_str(), remote, args or ""), + assert_error=assert_error) + if not assert_error: + remote_rrev, _ = self.servers[remote].server_store.get_last_revision(ref) + return ref.copy_with_rev(remote_rrev) + return + + def export_pkg(self, ref, conanfile=GenConanfile(), args=None, assert_error=False): + if conanfile: + self.save({"conanfile.py": conanfile}) + self.run("export-pkg . {} {} --json {}".format(ref.full_str(), + args or "", self.tmp_json_name), + assert_error=assert_error) + rrev = self.cache.package_layout(ref).recipe_revision() + data = json.loads(self.load(self.tmp_json_name)) + if assert_error: + return None + package_id = data["installed"][0]["packages"][0]["id"] + package_ref = PackageReference(ref, package_id) + prev = self.cache.package_layout(ref.copy_clear_rev()).package_revision(package_ref) + return package_ref.copy_with_revs(rrev, prev) + + def recipe_exists(self, ref): + return self.cache.package_layout(ref).recipe_exists() + + def package_exists(self, pref): + return self.cache.package_layout(pref.ref).package_exists(pref) + + def recipe_revision(self, ref): + return self.cache.package_layout(ref).recipe_revision() + + def package_revision(self, pref): + return self.cache.package_layout(pref.ref).package_revision(pref) + + def search(self, pattern, remote=None, assert_error=False, args=None): + remote = " -r={}".format(remote) if remote else "" + self.run("search {} --json {} {} {}".format(pattern, self.tmp_json_name, remote, + args or ""), + assert_error=assert_error) + data = json.loads(self.load(self.tmp_json_name)) + return data + + def massive_uploader(self, ref, revisions, num_prev, remote=None): + """Uploads N revisions with M package revisions. The revisions can be specified like: + revisions = [{"os": "Windows"}, {"os": "Linux"}], \ + [{"os": "Macos"}], \ + [{"os": "Solaris"}, {"os": "FreeBSD"}] + + IMPORTANT: Different settings keys will cause different recipe revisions + """ + remote = remote or "default" + ret = [] + for i, settings_groups in enumerate(revisions): + tmp = [] + for settings in settings_groups: + conanfile_gen = GenConanfile(). \ + with_build_msg("REV{}".format(i)). \ + with_package_file("file", env_var="MY_VAR") + for s in settings.keys(): + conanfile_gen = conanfile_gen.with_setting(s) + for k in range(num_prev): + args = " ".join(["-s {}={}".format(key, value) + for key, value in settings.items()]) + with environment_append({"MY_VAR": str(k)}): + pref = self.create(ref, conanfile=conanfile_gen, args=args) + self.upload_all(ref, remote=remote) + tmp.append(pref) + ret.append(tmp) + return ret + + def init_svn_repo(self, subpath, files=None, repo_url=None): + if not repo_url: + repo_url = create_remote_svn_repo(temp_folder()) + _, rev = create_local_svn_checkout(files, repo_url, folder=self.current_folder, + rel_project_path=subpath, delete_checkout=False) + return rev + + +class StoppableThreadBottle(threading.Thread): + """ + Real server to test download endpoints + """ + + def __init__(self, host=None, port=None): + self.host = host or "127.0.0.1" + self.port = port or random.randrange(48000, 49151) + self.server = bottle.Bottle() + super(StoppableThreadBottle, self).__init__(target=self.server.run, + kwargs={"host": self.host, "port": self.port}) + self.daemon = True + self._stop = threading.Event() + + def stop(self): + self._stop.set() + + def run_server(self): + self.start() + time.sleep(1) From 96303deac5e5ac8a41c57a4e33e9f9f4c4d5906a Mon Sep 17 00:00:00 2001 From: theirix <theirix@gmail.com> Date: Wed, 21 Oct 2020 13:01:33 +0300 Subject: [PATCH 11/26] Pass cwd to DockerCreateRunner, #447 The patch allows building packages using Docker in non-flat repositories with specifying cwd. Example: builder = ConanMultiPackager(cwd=os.path.join(os.getcwd(), 'recipes', 'foobar')) --- cpt/packager.py | 3 ++- cpt/runner.py | 6 ++++-- cpt/test/unit/packager_test.py | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cpt/packager.py b/cpt/packager.py index 7f310715..e65460d8 100644 --- a/cpt/packager.py +++ b/cpt/packager.py @@ -704,7 +704,8 @@ def run_builds(self, curpage=None, total_pages=None, base_profile_name=None): lockfile=self.lockfile, force_selinux=self.force_selinux, skip_recipe_export=skip_recipe_export, - update_dependencies=self.update_dependencies) + update_dependencies=self.update_dependencies, + cwd=self.cwd) r.run(pull_image=not pulled_docker_images[docker_image], docker_entry_script=self.docker_entry_script) diff --git a/cpt/runner.py b/cpt/runner.py index 42769ccd..6d72f15e 100644 --- a/cpt/runner.py +++ b/cpt/runner.py @@ -184,7 +184,8 @@ def __init__(self, profile_text, base_profile_text, base_profile_name, reference force_selinux=None, skip_recipe_export=False, update_dependencies=False, - lockfile=None): + lockfile=None, + cwd=None): self.printer = printer or Printer() self._upload = upload @@ -219,6 +220,7 @@ def __init__(self, profile_text, base_profile_text, base_profile_name, reference self._force_selinux = force_selinux self._skip_recipe_export = skip_recipe_export self._update_dependencies = update_dependencies + self._cwd = cwd or os.getcwd() def _pip_update_conan_command(self): commands = [] @@ -298,7 +300,7 @@ def run(self, pull_image=True, docker_entry_script=None): command = ('%s docker run --rm -v "%s:%s/project%s" %s %s %s %s %s ' '"%s cd project && ' '%s run_create_in_docker "' % (self._sudo_docker_command, - os.getcwd(), + self._cwd, self._docker_conan_home, volume_options, env_vars_text, diff --git a/cpt/test/unit/packager_test.py b/cpt/test/unit/packager_test.py index d4aa97d6..548e9d9e 100644 --- a/cpt/test/unit/packager_test.py +++ b/cpt/test/unit/packager_test.py @@ -1078,3 +1078,19 @@ def test_lockfile(self): builder.add_common_builds() builder.run() self.assertEquals("couse.lock", self.conan_api.calls[-1].kwargs["lockfile"]) + + def test_docker_cwd(self): + cwd = os.path.join(os.getcwd(), 'subdir') + self.packager = ConanMultiPackager(username="lasote", + channel="mychannel", + runner=self.runner, + conan_api=self.conan_api, + gcc_versions=["9"], + use_docker=True, + reference="zlib/1.2.11", + ci_manager=self.ci_manager, + cwd=cwd) + + self._add_build(1, "gcc", "9") + self.packager.run_builds(1, 1) + self.assertIn('docker run --rm -v "%s:/home/conan/project"' % cwd, self.runner.calls[4]) \ No newline at end of file From 06696a34dab372825655ca6f6bd7980113ecc249 Mon Sep 17 00:00:00 2001 From: theirix <theirix@gmail.com> Date: Fri, 30 Oct 2020 21:28:39 +0300 Subject: [PATCH 12/26] Fix test_docker_cwd on Windows, #447 --- cpt/test/unit/packager_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpt/test/unit/packager_test.py b/cpt/test/unit/packager_test.py index 548e9d9e..cd5afab3 100644 --- a/cpt/test/unit/packager_test.py +++ b/cpt/test/unit/packager_test.py @@ -1093,4 +1093,4 @@ def test_docker_cwd(self): self._add_build(1, "gcc", "9") self.packager.run_builds(1, 1) - self.assertIn('docker run --rm -v "%s:/home/conan/project"' % cwd, self.runner.calls[4]) \ No newline at end of file + self.assertIn('docker run --rm -v "%s:%s/project"' % (cwd, self.packager.docker_conan_home), self.runner.calls[4]) From 6e32035927278275dd23e3ebbc97a2500caa85b1 Mon Sep 17 00:00:00 2001 From: Kasun Hewage <kasun.ch@gmail.com> Date: Thu, 19 Nov 2020 15:40:05 +0100 Subject: [PATCH 13/26] Hide sensitive information from getting displayed/logged. --- cpt/runner.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpt/runner.py b/cpt/runner.py index 6d72f15e..431617ce 100644 --- a/cpt/runner.py +++ b/cpt/runner.py @@ -1,6 +1,7 @@ import os import sys import subprocess +import re from collections import namedtuple from conans import tools @@ -376,7 +377,11 @@ def __init__(self, runner, printer): self.printer = printer def __call__(self, command): - self.printer.print_command(command) + cmd_str = command + if hide_sensitive: + cmd_str = re.sub(r'(CONAN_LOGIN_USERNAME[_\w+]*)=\"(\w+)\"', r'\1="xxxxxxxx"', cmd_str) + cmd_str = re.sub(r'(CONAN_PASSWORD[_\w+]*)=\"(\w+)\"', r'\1="xxxxxxxx"', cmd_str) + self.printer.print_command(cmd_str) sys.stderr.flush() sys.stdout.flush() return self.runner(command) From a6459bd636363fa22572e067f75c04d7f4a5c79e Mon Sep 17 00:00:00 2001 From: Kasun Hewage <kasun.ch@gmail.com> Date: Thu, 19 Nov 2020 17:32:56 +0100 Subject: [PATCH 14/26] Added the missing function argument. --- cpt/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpt/runner.py b/cpt/runner.py index 431617ce..65c10997 100644 --- a/cpt/runner.py +++ b/cpt/runner.py @@ -376,7 +376,7 @@ def __init__(self, runner, printer): self.runner = runner self.printer = printer - def __call__(self, command): + def __call__(self, command, hide_sensitive=True): cmd_str = command if hide_sensitive: cmd_str = re.sub(r'(CONAN_LOGIN_USERNAME[_\w+]*)=\"(\w+)\"', r'\1="xxxxxxxx"', cmd_str) From 31109723fd0253846d3bad2ffa5959667336ad36 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Mon, 30 Nov 2020 12:49:28 -0300 Subject: [PATCH 15/26] Validate hide sensitive data Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/test/integration/docker_test.py | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/cpt/test/integration/docker_test.py b/cpt/test/integration/docker_test.py index b587088a..683bee20 100644 --- a/cpt/test/integration/docker_test.py +++ b/cpt/test/integration/docker_test.py @@ -1,6 +1,7 @@ import subprocess import unittest import time +import textwrap from conans import tools from conans.model.ref import ConanFileReference @@ -234,3 +235,35 @@ def build(self): self.packager.run() self.assertIn("Error updating the image", str(raised.exception)) self.assertIn("foobar install conan_package_tools", str(raised.exception)) + + @unittest.skipUnless(is_linux_and_have_docker(), "Requires Linux and Docker") + def test_docker_hidden_password(self): + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class Pkg(ConanFile): + settings = "os", "compiler", "build_type", "arch" + + def build(self): + pass + """) + + self.save_conanfile(conanfile) + with tools.environment_append({"CONAN_USERNAME": "bar", + "CONAN_LOGIN_USERNAME": "foobar", + "CONAN_PASSWORD": "foobazcouse", + "CONAN_DOCKER_IMAGE": "conanio/gcc8", + "CONAN_REFERENCE": "foo/0.0.1@bar/testing", + "CONAN_DOCKER_IMAGE_SKIP_UPDATE": "TRUE", + "CONAN_FORCE_SELINUX": "TRUE", + "CONAN_DOCKER_USE_SUDO": "FALSE", + "CONAN_DOCKER_SHELL": "/bin/bash -c", + }): + self.packager = ConanMultiPackager(gcc_versions=["8"], + archs=["x86_64"], + build_types=["Release"], + out=self.output.write) + self.packager.add({}) + self.packager.run() + self.assertIn('-e CONAN_LOGIN_USERNAME="xxxxxxxx"', self.output) + self.assertIn('-e CONAN_PASSWORD="xxxxxxxx"', self.output) From d156da13f4dcdc24791d528465fb03717b35c873 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Wed, 2 Dec 2020 10:02:58 -0300 Subject: [PATCH 16/26] Avoid import error on Conan 1.32 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- {conan => conanio}/__init__.py | 0 {conan => conanio}/packager.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {conan => conanio}/__init__.py (100%) rename {conan => conanio}/packager.py (100%) diff --git a/conan/__init__.py b/conanio/__init__.py similarity index 100% rename from conan/__init__.py rename to conanio/__init__.py diff --git a/conan/packager.py b/conanio/packager.py similarity index 100% rename from conan/packager.py rename to conanio/packager.py From 60e495b34427e9cbfaa241f9f3fe39f204b017c5 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Wed, 2 Dec 2020 10:19:27 -0300 Subject: [PATCH 17/26] Test devel first Signed-off-by: Uilian Ries <uilianries@gmail.com> --- .travis.yml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 55a7c3c5..5b0501b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,15 @@ jobs: fast_finish: true include: + - stage: Conan Development - Linux + if: branch != master AND branch !~ /release*/ + python: 2.7 + env: TOXENV=py27-conan-dev + - python: 3.7 + if: branch != master AND branch !~ /release*/ + env: TOXENV=py37-conan-dev + dist: xenial + - stage: Conan Latest - Linux python: 2.7 env: TOXENV=py27-conan-latest @@ -23,16 +32,6 @@ jobs: osx_image: xcode10.3 env: PYVER=py37 TOXENV=py37-conan-latest - - stage: Conan Development - Linux - if: branch != master AND branch !~ /release*/ - python: 2.7 - env: TOXENV=py27-conan-dev - - python: 3.7 - if: branch != master AND branch !~ /release*/ - env: TOXENV=py37-conan-dev - dist: xenial - - install: - .ci/travis/install.sh @@ -41,4 +40,4 @@ script: - .ci/travis/run.sh after_success: - - bash <(curl -s https://codecov.io/bash) \ No newline at end of file + - bash <(curl -s https://codecov.io/bash) From 4f2e55450446b9ed758f3be5d70f799dacfd097d Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Wed, 2 Dec 2020 10:20:39 -0300 Subject: [PATCH 18/26] Add developmen test on Windows Signed-off-by: Uilian Ries <uilianries@gmail.com> --- appveyor.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 3f7abf42..a6f4ab2c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,15 @@ environment: matrix: + - PYTHON: "C:\\Python27" + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + USE_UNSUPPORTED_CONAN_WITH_PYTHON_2: "1" + TOXENV: "py27-conan-dev" + + - PYTHON: "C:\\Python37" + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + USE_UNSUPPORTED_CONAN_WITH_PYTHON_2: "1" + TOXENV: "py37-conan-dev" + - PYTHON: "C:\\Python27" APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 USE_UNSUPPORTED_CONAN_WITH_PYTHON_2: "1" From 776861eeed4244185592f8bda6dea4cb5540423d Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Thu, 3 Dec 2020 08:40:50 -0300 Subject: [PATCH 19/26] Update development verstion to 0.35.0 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpt/__init__.py b/cpt/__init__.py index eccc02cf..7c59b0d3 100644 --- a/cpt/__init__.py +++ b/cpt/__init__.py @@ -1,5 +1,5 @@ -__version__ = '0.34.5-dev' +__version__ = '0.35.0-dev' def get_client_version(): From 6f4758b39c257dcabcabc6405cf400e8f6a358ea Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Thu, 3 Dec 2020 08:50:25 -0300 Subject: [PATCH 20/26] Update develop version to 0.36.0 Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpt/__init__.py b/cpt/__init__.py index 7c59b0d3..a047d1c6 100644 --- a/cpt/__init__.py +++ b/cpt/__init__.py @@ -1,5 +1,5 @@ -__version__ = '0.35.0-dev' +__version__ = '0.36.0-dev' def get_client_version(): From 485e4f920daad93a736244e00fa65d5f630cc8d5 Mon Sep 17 00:00:00 2001 From: Artalus <artalus-mail@yandex.ru> Date: Tue, 10 Mar 2020 12:21:24 +0300 Subject: [PATCH 21/26] pass CONAN_USERNAME envvar to docker (#479) --- cpt/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpt/runner.py b/cpt/runner.py index 65c10997..8467050b 100644 --- a/cpt/runner.py +++ b/cpt/runner.py @@ -338,7 +338,7 @@ def get_env_vars(self): ret["CPT_BASE_PROFILE"] = escape_env(self._base_profile_text) ret["CPT_BASE_PROFILE_NAME"] = escape_env(self._base_profile_name) - ret["CONAN_USERNAME"] = escape_env(self._reference.user) + ret["CONAN_USERNAME"] = escape_env(self._reference.user or ret.get("CONAN_USERNAME")) ret["CONAN_TEMP_TEST_FOLDER"] = "1" # test package folder to a temp one ret["CPT_UPLOAD_ENABLED"] = self._upload ret["CPT_UPLOAD_RETRY"] = self._upload_retry From 08768f2b8a034af316a0cf0a2bf4e07789fcc0d0 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Mon, 15 Mar 2021 12:04:13 -0300 Subject: [PATCH 22/26] #479 Validate hotfix for _ username Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/test/integration/docker_test.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/cpt/test/integration/docker_test.py b/cpt/test/integration/docker_test.py index 683bee20..b22840b7 100644 --- a/cpt/test/integration/docker_test.py +++ b/cpt/test/integration/docker_test.py @@ -267,3 +267,32 @@ def build(self): self.packager.run() self.assertIn('-e CONAN_LOGIN_USERNAME="xxxxxxxx"', self.output) self.assertIn('-e CONAN_PASSWORD="xxxxxxxx"', self.output) + + @unittest.skipUnless(is_linux_and_have_docker(), "Requires Linux and Docker") + def test_docker_underscore_user_channel(self): + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class Pkg(ConanFile): + def build(self): + pass + """) + + self.save_conanfile(conanfile) + with tools.environment_append({"CONAN_USERNAME": "_", + "CONAN_CHANNEL": "_", + "CONAN_DOCKER_IMAGE": "conanio/gcc8", + "CONAN_REFERENCE": "foo/0.0.1", + "CONAN_DOCKER_IMAGE_SKIP_UPDATE": "TRUE", + "CONAN_FORCE_SELINUX": "TRUE", + "CONAN_DOCKER_USE_SUDO": "FALSE", + "CONAN_DOCKER_SHELL": "/bin/bash -c", + }): + self.packager = ConanMultiPackager(gcc_versions=["8"], + archs=["x86_64"], + build_types=["Release"], + out=self.output.write) + self.packager.add({}) + self.packager.run() + self.assertIn('e CONAN_USERNAME="_"', self.output) + self.assertIn('-e CONAN_CHANNEL="_"', self.output) From 8630068a175b502469c0c29b3a6375314bef5f64 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Mon, 15 Mar 2021 16:35:31 -0300 Subject: [PATCH 23/26] #479 Improve env var for test_docker_underscore_user_channel Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/test/integration/docker_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpt/test/integration/docker_test.py b/cpt/test/integration/docker_test.py index b22840b7..c30e8e50 100644 --- a/cpt/test/integration/docker_test.py +++ b/cpt/test/integration/docker_test.py @@ -294,5 +294,5 @@ def build(self): out=self.output.write) self.packager.add({}) self.packager.run() - self.assertIn('e CONAN_USERNAME="_"', self.output) + self.assertIn('-e CONAN_USERNAME="_"', self.output) self.assertIn('-e CONAN_CHANNEL="_"', self.output) From c533ea8cbec2e500b7d87404f649025ef6a989ee Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Mon, 15 Mar 2021 17:32:02 -0300 Subject: [PATCH 24/26] #479 Add Docker pull retry Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/runner.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cpt/runner.py b/cpt/runner.py index 8467050b..fc663da1 100644 --- a/cpt/runner.py +++ b/cpt/runner.py @@ -325,9 +325,14 @@ def run(self, pull_image=True, docker_entry_script=None): def pull_image(self): with self.printer.foldable_output("docker pull"): - ret = self._runner("%s docker pull %s" % (self._sudo_docker_command, self._docker_image)) - if ret != 0: - raise Exception("Error pulling the image: %s" % self._docker_image) + for retry in range(1, 4): + ret = self._runner("%s docker pull %s" % (self._sudo_docker_command, self._docker_image)) + if ret == 0: + break + elif retry == 3: + raise Exception("Error pulling the image: %s" % self._docker_image) + self.printer.print_message("Could not pull docker image '{}'. Retry ({})" + .format(self._docker_image, retry)) def get_env_vars(self): ret = {key: value for key, value in os.environ.items() if key.startswith("CONAN_") and From 67cfe3a38d3ebfbf9889452494f20c5130af2871 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Mon, 15 Mar 2021 17:33:23 -0300 Subject: [PATCH 25/26] #479 Add small interval for docker pull retry Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/runner.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpt/runner.py b/cpt/runner.py index fc663da1..ab08fa60 100644 --- a/cpt/runner.py +++ b/cpt/runner.py @@ -2,6 +2,7 @@ import sys import subprocess import re +import time from collections import namedtuple from conans import tools @@ -333,6 +334,7 @@ def pull_image(self): raise Exception("Error pulling the image: %s" % self._docker_image) self.printer.print_message("Could not pull docker image '{}'. Retry ({})" .format(self._docker_image, retry)) + time.sleep(3) def get_env_vars(self): ret = {key: value for key, value in os.environ.items() if key.startswith("CONAN_") and From 16f0a3dc0ebce775769320f318a4c181b4fef127 Mon Sep 17 00:00:00 2001 From: Uilian Ries <uilianries@gmail.com> Date: Mon, 15 Mar 2021 17:41:51 -0300 Subject: [PATCH 26/26] #479 Fix unexpected indent for docker tests Signed-off-by: Uilian Ries <uilianries@gmail.com> --- cpt/test/integration/docker_test.py | 46 +++++++++++++++-------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/cpt/test/integration/docker_test.py b/cpt/test/integration/docker_test.py index c30e8e50..2708b349 100644 --- a/cpt/test/integration/docker_test.py +++ b/cpt/test/integration/docker_test.py @@ -34,13 +34,13 @@ def test_docker(self): client_version = get_client_version() ci_manager = MockCIManager() unique_ref = "zlib/%s" % str(time.time()) - conanfile = """from conans import ConanFile -import os - -class Pkg(ConanFile): - settings = "os", "compiler", "build_type", "arch" + conanfile = textwrap.dedent(""" + from conans import ConanFile + import os -""" + class Pkg(ConanFile): + settings = "os", "compiler", "build_type", "arch" + """) self.save_conanfile(conanfile) with tools.environment_append({"CONAN_DOCKER_RUN_OPTIONS": "--network=host -v{}:/tmp/cpt".format(self.root_project_folder), @@ -116,16 +116,17 @@ class Pkg(ConanFile): @unittest.skipUnless(is_linux_and_have_docker(), "Requires Linux and Docker") def test_docker_run_options(self): - conanfile = """from conans import ConanFile -import os + conanfile = textwrap.dedent(""" + from conans import ConanFile + import os -class Pkg(ConanFile): - settings = "os", "compiler", "build_type", "arch" - requires = "zlib/1.2.11@conan/stable" + class Pkg(ConanFile): + settings = "os", "compiler", "build_type", "arch" + requires = "zlib/1.2.11@conan/stable" - def build(self): - pass -""" + def build(self): + pass + """) self.save_conanfile(conanfile) # Validate by Environemnt Variable with tools.environment_append({"CONAN_DOCKER_ENTRY_SCRIPT": "pip install -U /tmp/cpt", @@ -204,16 +205,17 @@ def test_docker_run_android(self): @unittest.skipUnless(is_linux_and_have_docker(), "Requires Linux and Docker") def test_docker_custom_pip_command(self): - conanfile = """from conans import ConanFile - import os + conanfile = textwrap.dedent(""" + from conans import ConanFile + import os - class Pkg(ConanFile): - settings = "os", "compiler", "build_type", "arch" - requires = "zlib/1.2.11@conan/stable" + class Pkg(ConanFile): + settings = "os", "compiler", "build_type", "arch" + requires = "zlib/1.2.11@conan/stable" - def build(self): - pass - """ + def build(self): + pass + """) self.save_conanfile(conanfile) with tools.environment_append({"CONAN_DOCKER_ENTRY_SCRIPT": "pip install -U /tmp/cpt", "CONAN_USERNAME": "bar",