diff --git a/features/lockfiles/ci_build_require/.gitignore b/features/lockfiles/ci_build_require/.gitignore new file mode 100644 index 00000000..02b6e85b --- /dev/null +++ b/features/lockfiles/ci_build_require/.gitignore @@ -0,0 +1,4 @@ +release/ +tmp/ +locks/ +bo*.json \ No newline at end of file diff --git a/features/lockfiles/ci_build_require/app1/conanfile.py b/features/lockfiles/ci_build_require/app1/conanfile.py new file mode 100644 index 00000000..7b434ceb --- /dev/null +++ b/features/lockfiles/ci_build_require/app1/conanfile.py @@ -0,0 +1,8 @@ + +from conans import ConanFile + +required_conan_version = ">=1.28" + +class App1Conan(ConanFile): + settings = "build_type" + requires = "libd/[>0.0 <1.0]@user/testing" diff --git a/features/lockfiles/ci_build_require/app2/conanfile.py b/features/lockfiles/ci_build_require/app2/conanfile.py new file mode 100644 index 00000000..1c905a99 --- /dev/null +++ b/features/lockfiles/ci_build_require/app2/conanfile.py @@ -0,0 +1,8 @@ + +from conans import ConanFile + +required_conan_version = ">=1.28" + +class App2Conan(ConanFile): + settings = "build_type" + requires = "libc/[>0.0 <1.0]@user/testing" diff --git a/features/lockfiles/ci_build_require/build.bat b/features/lockfiles/ci_build_require/build.bat new file mode 100644 index 00000000..f64fcd65 --- /dev/null +++ b/features/lockfiles/ci_build_require/build.bat @@ -0,0 +1 @@ +python build.py \ No newline at end of file diff --git a/features/lockfiles/ci_build_require/build.py b/features/lockfiles/ci_build_require/build.py new file mode 100644 index 00000000..8f93abb0 --- /dev/null +++ b/features/lockfiles/ci_build_require/build.py @@ -0,0 +1,124 @@ +import os, json, shutil +import subprocess +from contextlib import contextmanager + + +def run(cmd, assert_error=False): + print("*********** Running: %s" % cmd) + ret = os.system(cmd) + if ret == 0 and assert_error: + raise Exception("Command unexpectedly succedeed: %s" % cmd) + if ret != 0 and not assert_error: + raise Exception("Failed command: %s" % cmd) + +def load(filename): + with open(filename, "r") as f: + return f.read() + +def save(filename, content): + with open(filename, "w") as f: + return f.write(content) + + +def rm(path): + if os.path.isfile(path): + os.remove(path) + elif os.path.isdir(path): + shutil.rmtree(path) + +@contextmanager +def chdir(path): + current_path = os.getcwd() + try: + os.chdir(path) + yield + finally: + os.chdir(current_path) + +@contextmanager +def setenv(key, value): + old_value = os.environ.get(key) + os.environ[key] = value + try: + yield + finally: + if old_value is not None: + os.environ[key] = old_value + + +def clean(): + rm("tmp") + rm("locks") + rm("bo_release.json") + rm("bo_debug.json") + + +def ci_pipeline(): + clean() + run("conan config set general.default_package_id_mode=full_version_mode") + for config in ("Release", "Debug"): + run("conan create tool tool1/0.1@user/testing -s build_type=%s" % config) + run("conan create tool tool2/0.1@user/testing -s build_type=%s" % config) + run("conan create liba liba/0.1@user/testing -s build_type=%s" % config) + run("conan create libb libb/0.1@user/testing -s build_type=%s" % config) + run("conan create libc libc/0.1@user/testing -s build_type=%s" % config) + run("conan create libd libd/0.1@user/testing -s build_type=%s" % config) + run("conan create app1 app1/0.1@user/testing -s build_type=%s" % config) + run("conan create app2 app2/0.1@user/testing -s build_type=%s" % config) + + # A developer does some change to the libb + with chdir("libb"): + libb = load("conanfile.py") + libb = libb + "# Some changes" + save("conanfile.py", libb) + + run("conan lock create conanfile.py --name=libb --version=0.2 " + "--user=user --channel=testing --lockfile-out=../locks/libb_deps_base.lock --base") + + # Even if liba gets a new 0.2 version, the lockfile will avoid it + run("conan create liba liba/0.2@user/testing") + with chdir("libb"): + # This will be useful to capture the revision + run("conan export . libb/0.2@user/testing --lockfile=../locks/libb_deps_base.lock " + "--lockfile-out=../locks/libb_base.lock") + print(load("../locks/libb_base.lock")) + # Capture the configuration lockfiles, one per configuration + run("conan lock create conanfile.py --name=libb --version=0.2 --profile=../profile -s build_type=Debug " + "--user=user --channel=testing --lockfile=../locks/libb_base.lock --lockfile-out=../locks/libb_deps_debug.lock") + run("conan lock create conanfile.py --name=libb --version=0.2 --profile=../profile -s build_type=Release " + "--user=user --channel=testing --lockfile=../locks/libb_base.lock --lockfile-out=../locks/libb_deps_release.lock") + print(load("../locks/libb_deps_release.lock")) + print(load("../locks/libb_deps_debug.lock")) + # Now build libb + run("conan create . libb/0.2@user/testing --lockfile=../locks/libb_deps_release.lock") + run("conan create . libb/0.2@user/testing --lockfile=../locks/libb_deps_debug.lock") + + # Capture the app1 base lockfile + run("conan lock create --reference=app1/0.1@user/testing --lockfile=locks/libb_base.lock " + "--lockfile-out=locks/app1_base.lock --base") + # And one lockfile per configuration + run("conan lock create --reference=app1/0.1@user/testing --lockfile=locks/app1_base.lock " + "--lockfile-out=locks/app1_release.lock -s build_type=Release --profile=profile") + run("conan lock create --reference=app1/0.1@user/testing --lockfile=locks/app1_base.lock " + "--lockfile-out=locks/app1_debug.lock -s build_type=Debug --profile=profile") + + run("conan lock build-order locks/app1_release.lock --json=bo_release.json") + run("conan lock build-order locks/app1_debug.lock --json=bo_debug.json") + build_order_release = json.loads(load("bo_release.json")) + build_order_debug = json.loads(load("bo_debug.json")) + + for level in build_order_release: + for item in level: + ref, pid, context, id_ = item + print(item) + run("conan install %s --build=%s --lockfile=locks/app1_release.lock " + "--lockfile-out=locks/app1_release_updated.lock" % (ref, ref)) + run("conan lock update locks/app1_release.lock locks/app1_release_updated.lock") + + print(load("locks/app1_release.lock")) + clean() + +if __name__ == '__main__': + home = os.path.abspath(os.path.join(os.path.dirname(__file__), "tmp")) + with setenv("CONAN_USER_HOME", home): + ci_pipeline() diff --git a/features/lockfiles/ci_build_require/build.sh b/features/lockfiles/ci_build_require/build.sh new file mode 100644 index 00000000..421641ed --- /dev/null +++ b/features/lockfiles/ci_build_require/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -ex + +python build.py diff --git a/features/lockfiles/ci_build_require/liba/conanfile.py b/features/lockfiles/ci_build_require/liba/conanfile.py new file mode 100644 index 00000000..040b059a --- /dev/null +++ b/features/lockfiles/ci_build_require/liba/conanfile.py @@ -0,0 +1,6 @@ +from conans import ConanFile, tools + +required_conan_version = ">=1.28.0" + +class PkgaConan(ConanFile): + settings = "build_type" diff --git a/features/lockfiles/ci_build_require/libb/conanfile.py b/features/lockfiles/ci_build_require/libb/conanfile.py new file mode 100644 index 00000000..580d6395 --- /dev/null +++ b/features/lockfiles/ci_build_require/libb/conanfile.py @@ -0,0 +1,7 @@ +from conans import ConanFile + +required_conan_version = ">=1.28" + +class LibBConan(ConanFile): + settings = "build_type" + requires = "liba/[>0.0 <1.0]@user/testing" diff --git a/features/lockfiles/ci_build_require/libc/conanfile.py b/features/lockfiles/ci_build_require/libc/conanfile.py new file mode 100644 index 00000000..19335859 --- /dev/null +++ b/features/lockfiles/ci_build_require/libc/conanfile.py @@ -0,0 +1,7 @@ +from conans import ConanFile + +required_conan_version = ">=1.28" + +class LibCConan(ConanFile): + settings = "build_type" + requires = "liba/[>0.0 <1.0]@user/testing" diff --git a/features/lockfiles/ci_build_require/libd/conanfile.py b/features/lockfiles/ci_build_require/libd/conanfile.py new file mode 100644 index 00000000..bfef28b1 --- /dev/null +++ b/features/lockfiles/ci_build_require/libd/conanfile.py @@ -0,0 +1,8 @@ + +from conans import ConanFile + +required_conan_version = ">=1.28" + +class LibDConan(ConanFile): + settings = "build_type" + requires = "libb/[>0.0 <1.0]@user/testing", "libc/[>0.0 <1.0]@user/testing" diff --git a/features/lockfiles/ci_build_require/profile b/features/lockfiles/ci_build_require/profile new file mode 100644 index 00000000..7bc5aec0 --- /dev/null +++ b/features/lockfiles/ci_build_require/profile @@ -0,0 +1,3 @@ +[build_requires] +tool1/0.1@user/testing +tool2/0.1@user/testing diff --git a/features/lockfiles/ci_build_require/tool/conanfile.py b/features/lockfiles/ci_build_require/tool/conanfile.py new file mode 100644 index 00000000..08311b38 --- /dev/null +++ b/features/lockfiles/ci_build_require/tool/conanfile.py @@ -0,0 +1,6 @@ +from conans import ConanFile + +required_conan_version = ">=1.28.0" + +class PkgaConan(ConanFile): + settings = "build_type"