使用 Python 编写 Mercurial 脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1153469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 21:35:46  来源:igfitidea点击:

Mercurial scripting with python

pythonmercurialrevision

提问by Jiaaro

I am trying to get the mercurial revision number/id (it's a hash not a number) programmatically in python.

我试图在 python 中以编程方式获取 mercurial 修订号/id(它是一个散列而不是数字)。

The reason is that I want to add it to the css/js files on our website like so:

原因是我想将它添加到我们网站上的 css/js 文件中,如下所示:

<link rel="stylesheet" href="example.css?{% mercurial_revision "example.css" %}" />

So that whenever a change is made to the stylesheet, it will get a new url and no longer use the old cached version.

这样无论何时对样式表进行更改,它都会获得一个新的 url 并且不再使用旧的缓存版本。

ORif you know where to find good documentation for the mercurial python module, that would also be helpful. I can't seem to find it anywhere.

或者,如果您知道在哪里可以找到有关 mercurialpython 模块的良好文档,那也会有所帮助。我似乎无法在任何地方找到它。

My Solution

我的解决方案

I ended up using subprocess to just run a command that gets the hg node. I chose this solution because the api is not guaranteed to stay the same, but the bash interface probably will:

我最终使用子进程来运行一个获取 hg 节点的命令。我选择这个解决方案是因为不能保证 api 保持不变,但 bash 界面可能会:

import subprocess

def get_hg_rev(file_path):
    pipe = subprocess.Popen(
        ["hg", "log", "-l", "1", "--template", "{node}", file_path],
        stdout=subprocess.PIPE
        )
    return pipe.stdout.read()

example use:

示例使用:

> path_to_file = "/home/jim/workspace/lgr/pinax/projects/lgr/site_media/base.css"
> get_hg_rev(path_to_file)
'0ed525cf38a7b7f4f1321763d964a39327db97c4'

采纳答案by brendan

It's true there's no official API, but you can get an idea about best practices by reading other extensions, particularly those bundled with hg. For this particular problem, I would do something like this:

确实没有官方 API,但是您可以通过阅读其他扩展(尤其是与 hg 捆绑在一起的扩展)来了解最佳实践。对于这个特定的问题,我会做这样的事情:

from mercurial import ui, hg
from mercurial.node import hex

repo = hg.repository('/path/to/repo/root', ui.ui())
fctx = repo.filectx('/path/to/file', 'tip')
hexnode = hex(fctx.node())

UpdateAt some point the parameter order changed, now it's like this:

更新在某些时候参数顺序发生了变化,现在是这样的:

   repo = hg.repository(ui.ui(), '/path/to/repo/root' )

回答by rob

Do you mean this documentation?
Note that, as stated in that page, there is no officialAPI, because they still reserve the right to change it at any time. But you can see the list of changes in the last few versions, it is not very extensive.

你的意思是这个文件
请注意,如该页面所述,没有官方API,因为他们仍然保留随时更改它的权利。但是你可以看到最近几个版本的变化列表,不是很广泛。

回答by Nick T

An updated, cleaner subprocess version (uses .check_output(), added in Python 2.7/3.1) that I use in my Django settings file for a crude end-to-end deployment check (I dump it into an HTML comment):

.check_output()我在我的 Django 设置文件中使用了一个更新的、更清晰的子进程版本(使用,在 Python 2.7/3.1 中添加),用于粗略的端到端部署检查(我将其转储到 HTML 注释中):

import subprocess

HG_REV = subprocess.check_output(['hg', 'id', '--id']).strip()

You could wrap it in a tryif you don't want some strange hiccup to prevent startup:

try如果您不希望出现一些奇怪的问题来阻止启动,您可以将它包装在 a 中:

try:
    HG_REV = subprocess.check_output(['hg', 'id', '--id']).strip()
except OSError:
    HG_REV = "? (Couldn't find hg)"
except subprocess.CalledProcessError as e:
    HG_REV = "? (Error {})".format(e.returncode)
except Exception:  # don't use bare 'except', mis-catches Ctrl-C and more
    # should never have to deal with a hangup 
    HG_REV = "???"

回答by Esteis

If you are using Python 2, you want to use hglib.

如果您使用的是 Python 2,您想使用hglib.

I don't know what to use if you're using Python 3, sorry. Probably hgapi.

如果您使用的是 Python 3,我不知道该使用什么,抱歉。大概hgapi

Contents of this answer

本回答内容

  • Mercurial's APIs
  • How to use hglib
  • Why hglib is the best choice for Python 2 users
  • If you're writing a hook, that discouraged internal interface is awfully convenient
  • Mercurial 的 API
  • 如何使用 hglib
  • 为什么 hglib 是 Python 2 用户的最佳选择
  • 如果你正在写一个钩子,那个不鼓励的内部接口非常方便

Mercurial's APIs

Mercurial 的 API

Mercurial has two official APIs.

Mercurial 有两个官方 API。

  1. The Mercurial command server. You can talk to it from Python 2 using the hglib(wiki, PyPI) package, which is maintained by the Mercurial team.
  2. Mercurial's command-line interface. You can talk to it via subprocess, or hgapi, or somesuch.
  1. Mercurial 命令服务器。您可以使用由 Mercurial 团队维护的hglib( wiki, PyPI) 包从 Python 2 与它对话。
  2. Mercurial 的命令行界面。您可以通过subprocess、 或hgapi、 或其他方式与它交谈。

How to use hglib

如何使用 hglib

Installation:

安装:

pip install python-hglib

Usage:

用法:

import hglib
client = hglib.open("/path/to/repo")

commit = client.log("tip")
print commit.author

More usage information on the hglib wiki page.

有关hglib wiki 页面的更多使用信息。

Why hglib is the best choice for Python 2 users

为什么 hglib 是 Python 2 用户的最佳选择

Because it is maintained by the Mercurial team, and it is what the Mercurial team recommend for interfacing with Mercurial.

因为它是由 Mercurial 团队维护的,也是 Mercurial 团队推荐用于与 Mercurial 交互的。

From Mercurial's wiki, the following statement on interfacing with Mercurial:

来自 Mercurial 的 wiki,关于与 Mercurial 接口的以下声明:

For the vast majority of third party code, the best approach is to use Mercurial's published, documented, and stable API: the command line interface. Alternately, use the CommandServeror the libraries which are based on it to get a fast, stable, language-neutral interface.

对于绝大多数第三方代码,最好的方法是使用 Mercurial 已发布、有文档记录且稳定的 API:命令行界面。或者,使用CommandServer或基于它的库来获得快速、稳定、语言中立的界面。

From the command server page:

从命令服务器页面:

[The command server allows] third-party applications and libraries to communicate with Mercurial over a pipe that eliminates the per-command start-up overhead. Libraries can then encapsulate the command generation and parsing to present a language-appropriate API to these commands.

[命令服务器允许] 第三方应用程序和库通过管道与 Mercurial 进行通信,从而消除了每个命令的启动开销。然后,库可以封装命令生成和解析,以向这些命令提供适合语言的 API。

The Python interface to the Mercurial command-server, as said, is hglib.

如前所述,Mercurial 命令服务器的 Python 接口是hglib.

The per-command overhead of the command line interface is no joke, by the way. I once built a very small test suite (only about 5 tests) that used hgvia subprocessto create, commit by commit, a handful of repos with e.g. merge situations. Throughout the project, the runtime of suite stayed between 5 to 30 seconds, with nearly all time spent in the hgcalls.

顺便说一下,命令行界面的每个命令开销不是开玩笑。我曾经建造了使用一个非常小的测试套件(仅约5测试)hg通过subprocess创建,提交按提交,如与合并的情况下回购了一把。在整个项目中,套件的运行时间保持在 5 到 30 秒之间,几乎所有时间都花在hg调用上。

If you're writing a hook, that discouraged internal interface is awfully convenient

如果你正在写一个钩子,那个不鼓励的内部接口非常方便

The signature of a Python hook function is like so:

Python 钩子函数的签名是这样的:

# In the hgrc:
# [hooks]
# preupdate.my_hook = python:/path/to/file.py:my_hook

def my_hook(
    ui, repo, hooktype, 
    ... hook-specific args, find them in `hg help config` ..., 
    **kwargs)

uiand repoare part of the aforementioned discouraged unofficial internal API. The fact that they are right there in your function args makes them terribly convenient to use, such as in this example of a preupdatehook that disallows merges between certain branches.

ui并且repo是上述不鼓励的非官方内部 API 的一部分。它们就在您的函数 args 中的事实使它们使用起来非常方便,例如在这个preupdate不允许某些分支之间合并的钩子示例中。

def check_if_merge_is_allowed(ui, repo, hooktype, parent1, parent2, **kwargs):
    from_ = repo[parent2].branch()
    to_ = repo[parent1].branch()
    ...
    # return True if the hook fails and the merge should not proceed.

If your hook code is not so important, and you're not publishing it, you might choose to use the discouraged unofficial internal API. If your hook is part of an extension that you're publishing, better use hglib.

如果您的钩子代码不是那么重要,并且您没有发布它,您可能会选择使用不鼓励的非官方内部 API。如果您的钩子是您发布的扩展的一部分,最好使用hglib.

回答by dfa

回答by Ry4an Brase

FWIW to avoid fetching that value on every page/view render, I just have my deploy put it into the settings.pyfile. Then I can reference settings.REVISIONwithout all the overhead of accessing mercurial and/or another process. Do you ever have this value change w/o reloading your server?

FWIW 为避免在每个页面/视图渲染中获取该值,我只是让我的部署将其放入settings.py文件中。然后我可以参考settings.REVISION而无需访问 mercurial 和/或其他进程的所有开销。您是否曾经在不重新加载服务器的情况下更改此值?

回答by Warren P

I wanted to do the same thing the OP wanted to do, get hg id -ifrom a script (get tip revision of the whole REPOSITORY, not of a single FILE in that repo) but I did not want to use popen, and the code from brendangot me started, but wasn't what I wanted.

我想做 OP 想做的事情,hg id -i从脚本中获取(获取整个 REPOSITORY 的最新修订,而不是该存储库中的单个 FILE),但我不想使用 popen,并且来自brendan我的代码开始了,但不是我想要的。

So I wrote this... Comments/criticism welcome. This gets the tip rev in hex as a string.

所以我写了这个......欢迎评论/批评。这将获取十六进制的tip rev 作为字符串。

from mercurial import ui, hg, revlog
# from mercurial.node import hex  # should I have used this?

def getrepohex(reporoot):
    repo = hg.repository(ui.ui(), reporoot)
    revs = repo.revs('tip')
    if len(revs)==1:
      return str(repo.changectx(revs[0]))
    else:
      raise Exception("Internal failure in getrepohex")