版本¶
本节解释如何创建给定包的不同版本,首先从手动更改 conanfile.py 配方中的 version 属性开始,然后介绍 set_version() 方法作为自动化定义包版本的机制。
注意
本节使用非常简单、空的配方,不构建任何代码,因此没有 build()、package() 等,以说明使用最简单的配方进行版本控制,并允许示例轻松运行且非常快速和简单。在实际情况下,配方将是完整的配方,如教程前面的章节中所见,构建实际的库和包。
让我们从一个非常简单的配方开始
from conan import ConanFile
class pkgRecipe(ConanFile):
name = "pkg"
version = "1.0"
# The recipe would export files and package them, but not really
# necessary for the purpose of this part of the tutorial
# exports_sources = "include/*"
# def package(self):
# ...
我们可以创建 pkg/1.0 包
$ conan create .
...
pkg/1.0 .
...
$ conan list "pkg/*"
Local Cache
pkg
pkg/1.0
如果现在对该库的源文件进行了一些更改,这将是一个新版本,我们可以将 conanfile.py 版本更改为 version = "1.1" 并创建新的 pkg/1.1 版本
# Make sure you modified conanfile.py to version=1.1
$ conan create .
...
pkg/1.1 .
...
$ conan list "pkg/*"
Local Cache
pkg
pkg/1.0
pkg/1.1
如我们所见,现在我们在缓存中看到 pkg/1.0 和 pkg/1.1。 Conan 缓存可以存储相同 pkg 包的任何数量的不同版本和配置。
自动化版本¶
与其手动更改 conanfile.py 中的版本,不如可以使用 2 种不同的方法来自动化它。
首先,可以直接在命令行中提供 version。 在上面的示例中,我们可以删除配方中的 version 属性并执行
# Make sure you removed the version attribute in conanfile.py
$ conan create . --version=1.2
...
pkg/1.2 .
...
$ conan list "pkg/*"
Local Cache
pkg
pkg/1.0
pkg/1.1
pkg/1.2
另一种可能性是使用 set_version() 方法动态定义版本,例如,如果版本已经存在于源代码或文本文件中,或者应该从 git 版本推断出来。
假设我们在 repo 中有一个 version.txt 文件,其中仅包含版本字符串 1.3。 然后,可以这样操作
from conan import ConanFile
from conan.tools.files import load
class pkgRecipe(ConanFile):
name = "pkg"
def set_version(self):
self.version = load(self, "version.txt")
# No need to specify the version in CLI arg or in recipe attribute
$ conan create .
...
pkg/1.3 .
...
$ conan list "pkg/*"
Local Cache
pkg
pkg/1.0
pkg/1.1
pkg/1.2
pkg/1.3
也可以将命令行版本定义与从文件读取结合起来,如果未提供命令行参数,则采用以下语法
def set_version(self):
# if self.version is already defined from CLI --version arg, it will
# not load version.txt
self.version = self.version or load(self, "version.txt")
# This will create the "1.4" version even if the version.txt file contains "1.3"
$ conan create . --version=1.4
...
pkg/1.4 .
...
$ conan list "pkg/*"
Local Cache
pkg
pkg/1.0
pkg/1.1
pkg/1.2
pkg/1.3
pkg/1.4
同样,也可以从 Git 标签获取版本
from conan import ConanFile
from conan.tools.scm import Git
class pkgRecipe(ConanFile):
name = "pkg"
def set_version(self):
git = Git(self)
tag = git.run("describe --tags")
self.version = tag
# assuming this is a git repo, and it was tagged to 1.5
$ git init .
$ git add .
$ git commit -m "initial commit"
$ git tag 1.5
$ conan create .
...
pkg/1.5 .
...
$ conan list "pkg/*"
Local Cache
pkg
pkg/1.0
pkg/1.1
pkg/1.2
pkg/1.3
pkg/1.4
pkg/1.5
注意
最佳实践
我们可能会尝试使用分支名称或提交作为版本号。 但是,这可能有一些缺点,例如,当此包被需要时,需要在每个需要它的其他包配方中明确指定
requires = "pkg/commit",并且可能难以一致地更新使用者,以及知道是使用较新还是较旧的依赖项。
需要新版本¶
当创建新包版本时,如果需要此包的其他包配方包含明确的 requires,并固定精确的版本,例如
from conan import ConanFile
class AppRecipe(ConanFile):
name = "app"
version = "1.0"
requires = "pkg/1.0"
那么,安装或创建 app 配方将继续需要和使用 pkg/1.0 版本,而不是更新的版本。 要开始使用新的 pkg 版本,必须显式更新 requires,例如
from conan import ConanFile
class AppRecipe(ConanFile):
name = "app"
version = "1.0"
requires = "pkg/1.5"
虽然此过程实现了非常好的可重现性和可追溯性,但如果管理大型依赖关系图并且希望更快地使用最新的依赖项版本,并减少手动干预,则可能会有些繁琐。 为了自动化此过程,可以使用下一节中解释的 *版本范围*。