自动获取SVN版本号到程序中

20

我有一个使用SVN管理的Python项目,并且希望在运行时显示版本号。是否有办法实现这一点(例如在提交代码时自动运行一个简短的脚本来更新版本文件,或者在Python中查询SVN存储库)?

11个回答

29

我不确定Python的具体情况,但如果在文件中放置字符串$Revision$,并且在您的SVN配置中启用了enable-auto-props=true,它将被重写为类似$Revision: 144$的内容。然后,您可以在脚本中解析此内容。

许多属性关键字可以以这种方式使用

这不会有任何开销,例如查询SVN repo,因为该字符串在提交或更新时已经硬编码到您的文件中。

我不确定您如何在Python中解析此内容,但在PHP中,我会这样做:

$revString = '$Revision: 144$';
if(preg_match('/: ([0-9]+)\$/', $revString, $matches) {
    echo 'Revision is ' . $matches[1];
}

这是正确的答案!另外,请记住在您想要执行此操作的每个文件上设置属性'keywords=Revision'。 - Drew Hall
Drew - 我认为如果设置了enable-auto-props=true,则默认关键字都已设置? - Ciaran McNulty
3
太棒了!不过,在我的情况下,如果修改的是另一个文件,有没有办法让SVN编辑修订版本号呢?例如,如果我在version.py中使用修订版本号关键字,但我在修订号nnn中没有更改version.py,它不会更新它,对吗?如果不行,有没有办法以这种方式使用这种方法呢? - Smashery
@Smashery 我想你需要自己编写提交钩子来实现这一点 - 你可以使用 svn:keywords 属性,设置自己的关键词,让 SVN 为你进行替换。 - Ciaran McNulty
这只适用于正在提交的文件。我们在构建脚本中处理它,很容易做到。 - orip

15

类似于 PHP 的答案,但更符合 Python 风格;将此放在模块的 __init__.py 中:

__version__ = filter(str.isdigit, "$Revision: 13 $")

并确保您添加了 Revision 属性:

svn propset svn:keywords Revision __init__.py

1
如果您不喜欢过滤器,可以使用以下代码:''.join(c for c in "$LastChangedRevision: 1546 $" if c.isdigit()) - Tal Weiss

12

或者你可以这样做:

import re,subprocess

svn_info = subprocess.check_output("svn info")

print (re.search(ur"Revision:\s\d+", svn_info)).group()

在我的项目中它会打印"Revision: 2874"

或者是这样的:

print (subprocess.check_output("svnversion")).split(":")[0]

在我的项目中它会打印"2874"

编辑

对于新版本的Python(>=3.4)和明确的文件路径:

import re,subprocess

file_path = 'c:/foo'

svn_info = subprocess.check_output('svn info ' + file_path)

revision_string = re.search(r"Revision:\s\d+", str(svn_info)).group()
revision = revision_string.split(': ')[1]
print(revision)

例如打印

'8623'


不仅可以使用工作副本。您可以首先从“svn info”检索svn远程URL,例如执行“svn info”,然后从输出中获取“URL”参数值并执行相同的代码,但使用“svn info value_of_URL_param”因此,更新的代码是:import re,subprocesssvn_info = subprocess.check_output("svn info https://svn.you_remote_repo_url")print (re.search(ur"Revision:\s\d+", svn_info)).group() - German Petrov
1
你的打印语句出现了无效语法错误。print(re.search(ur"Revision:\s\d+", svn_info)).group() - tzg
a) 自Python 3.4起,请使用r而不是ur来表示字符串:https://dev59.com/Y18e5IYBdhLWcg3wHngs b) 将二进制字符串包装在str()中。 - Stefan

4
您的存储库中的hooks/pre-commit文件是一个脚本或程序,将在成功提交之前执行。只需将其设置为一个脚本,当提交时更新您的文件并附带正确的版本号(版本号作为运行脚本时传递)。以下是编写预提交挂钩的示例教程:http://wordaligned.org/articles/a-subversion-pre-commit-hook

2
哎呀。让 pre-commit 钩子修改文件通常是一个坏主意。仓库中的版本将与工作副本中的版本不同,这可能会导致一些混淆。提交者必须恢复到文件的早期版本,然后获取新版本,这可能会导致某种冲突,因为 svn 已经将原始版本存储在工作副本的文本基础中。 - sunny256
我同意这是危险的,通常不是期望的行为,但如果你适当地限制自己,那么我不认为有问题。例如,如果你有一个名为“svn_version.txt”的文件,其中仅包含当前版本号,那么它将是完全安全的;你的本地副本始终具有你检出的版本,而存储库始终具有最新版本(通常与你的工作副本相同)。 - Eli Courtwright

4

这个函数只有在从子版本检出中运行时才有效。如果这是 OP 想要的,那么问题解决了。然而,我怀疑他可能希望脚本包含在自身或配置文件中的子版本修订号,即使脚本不再处于子版本控制下,这种情况下该链接就没有用了。 - Eli Courtwright
是的,这是一个很好的备选方案,但在源代码控制下也有版本号会更好。谢谢!+1 - Smashery

3

请看一下pysvn。它为Subversion运行时功能在Python中提供了扩展。


3
我通过在构建项目时运行一个小脚本来实现这一点。该脚本只是调用svn info与sed相结合,以获取裸版本数据并将该数字注入到revision.txt文件中。
Hudson构建服务器使其更加容易,因为它在调用您的构建脚本之前将SVN修订号设置为环境变量。

1

我觉得“when it is run”这一部分有点含糊不清——从哪里运行?从 SVN checkout 还是从发布的代码?所有的解决方案都在某种程度上将 SVN 版本注入到 Python 源码中或者仓库的某个版本文件中。

版本文件会在新的 checkout 时被更改,因此在分发之前需要进行干净的 checkout。所以我的问题是程序在哪里运行。


1

重新回答,因为我在寻找Python 3的所有信息时遇到了麻烦。 在Python 3中,您可以使用以下内容:

import re

revstring = '$Revision: 123 $'
revnumber = re.sub(r'\D', '', revstring)

要让SVN替换数字,必须设置文件关键字“Revision”。您可以通过在终端中键入以下命令来实现:

svn propset svn:keywords Revision YOURFILE.py

此外,在Subversion配置文件中,属性enable-auto-props必须设置为yes。这应该已经是这种情况了。在Tortoise SVN中,可以通过单击常规设置选项卡中“Subversion配置文件”旁边的“编辑”按钮来访问此配置文件。

0
你可以通过解析“svn info --xml”的输出到一个XML元素来以编程方式实现这一点:
def get_svn_rev(dir: Union[str, Path]) -> str:
    """Get the svn revision of the given directory"""
    dir = str(dir)
    svn_info_cmd = ['svn', 'info', '--xml', dir]
    print(' '.join(svn_info_cmd))
    svn_info_process = subprocess.run(svn_info_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if svn_info_process.returncode:
        eprint(svn_info_process.stderr.decode().strip())
        raise subprocess.CalledProcessError(returncode=svn_info_process.returncode, cmd=svn_info_cmd,
                                            output=svn_info_process.stdout,
                                            stderr=svn_info_process.stderr)
    else:
        info = ElementTree.fromstring(svn_info_process.stdout.decode().strip())
        entry = info.find('entry')
        revision = entry.get('revision')

    return revision

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接