2009-12-16 28 views
4

我想使用mercurial命令API從mercurial存儲庫檢索日誌。不幸的是,mercurial.commands.log將消息輸出到stdout,而不是返回一些很好的修訂列表,例如。 pysvn的確如此。可以輕鬆實現嗎?我想爲我的程序添加mercurial支持,並希望儘可能輕鬆地完成此操作,因爲這是可能的。使用API​​從mercurial檢索日誌

回答

7

你應該做的事情沿着這行:

 
from mercurial import ui, hg 
u = ui.ui() 
repo = hg.repo() 
for rev in repo: 
    print repo[rev] 

下標的對象是上下文對象。它有很多有用的方法,如description()branch()user()。有關它可以做什麼的完整列表,請參閱the source(或在其上執行dir())。

+0

哦,這太棒了。我知道,mercurial必須有一些很酷且直接的方式來做到這一點,但只是不知道這會很容易。非常感謝:-) – gruszczy

+0

好的,這並不如我所願。那麼http回購呢?我無法遍歷它們或使用len。 – gruszczy

+0

您必須對本地回購對象執行此操作。這正是hg工作的方式,真的。爲什麼你不能只是做一個hg {clone,pull},然後用它作爲遠程更改的本地緩存? – durin42

2

簡單的答案就是在你調用log命令之前使用ui.pushbuffer(),在你調用它之後使用log_output = ui.popbuffer()。通過這樣做,log_output將包含log命令的輸出。

您是否確實在尋找直接日誌輸出,或者您是否真的想要diff或其他類型的數據?如果我們知道你想要得到的是什麼(例如:「X和Y之間每個變更集的提交信息」),我們可能會向你展示更好的方法。

編輯:Mercurial API wiki page看看,看看如何獲​​得大部分的公共信息從repoctx對象。

+0

我不想獲取日誌消息,因爲我不得不解析它們 - 而不是我想要做的事情。相反,我想獲得一些對象,它會保存每個修訂版本的相關信息。 pysvn返回字典列表,每個字典都有日期,作者,消息等。 – gruszczy

2

是的我有同樣的問題..似乎它設計爲不允許遠程檢索日誌。網絡界面提供了一些rss feed,但對我來說這還不夠歷史。所以我們創建了我們自己定製的rss feed ...

它並不是最精緻的東西,並且根據我們的喜好定製,您可以混合print_item()中的字段來更改提要的外觀。您也可以對其進行修改,以根據需要返回特定變更集的日誌信息。

您將有一個腳本別名添加到Apache,像(更多信息請參見http://httpd.apache.org/docs/2.0/howto/cgi.html):

ScriptAlias /feed.cgi /usr/local/systems/hg/script/feed.cgi 

feed.cgi文件內容:

#!/usr/bin/env python2.5 
# -*- python -*- 

""" 
Creates a rss feed from commit log messages in a repository/branch. 
Can be filtered on commit logs from a set date eg date=2009-12-12 
or by a number of days previous eg. days=7 

Usage: 
* retrieve all logs: http://hg.server/feed.cgi?repository=MyRepo 
* retrieve logs from set date: http://hg.server/feed.cgi?repository=DMyRepo&date=2009-11-11 
* retrieve logs from last 77 days: http://hg.server/feed.cgi?repository=DMyRepo&days=77 
* retrieve all logs from a branch: http://hg.server/feed.cgi?repository=MyRepo&branch=myBranch 

Script Location on server: /usr/local/systems/hg/script/feed.cgi 
""" 

defaultdateformats = (
'%Y-%m-%d %H:%M:%S', 
'%Y-%m-%d %I:%M:%S%p', 
'%Y-%m-%d %H:%M', 
'%Y-%m-%d %I:%M%p', 
'%Y-%m-%d', 
'%m-%d', 
'%m/%d', 
'%m/%d/%y', 
'%m/%d/%Y', 
'%a %b %d %H:%M:%S %Y', 
'%a %b %d %I:%M:%S%p %Y', 
'%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822" 
'%b %d %H:%M:%S %Y', 
'%b %d %I:%M:%S%p %Y', 
'%b %d %H:%M:%S', 
'%b %d %I:%M:%S%p', 
'%b %d %H:%M', 
'%b %d %I:%M%p', 
'%b %d %Y', 
'%b %d', 
'%H:%M:%S', 
'%I:%M:%S%p', 
'%H:%M', 
'%I:%M%p', 
) 

import os, sys, cgi, cgitb, datetime, time 
cgitb.enable() 

from mercurial import ui, hg, util 
from mercurial.node import short 

def find_repository(name): 
    base = '/usr/local/systems/hg/repos/' 
    path = os.path.join(base, name) 

    repos = hg.repository(None, path) 
    return repos 

def find_changes(repos, branch, date): 

    # returns true if d2 is newer than d1 
    def newerDate(d1, d2): 
     d1 = datetime.datetime.fromtimestamp(d1) 
     d2 = datetime.datetime.fromtimestamp(d2) 
     return d1 < d2 

    #for ctx in repos.changelog: 
    # print ctx 

    changes = repos.changelog 

    out = [] 
    # filter on branch 
    if branch != '': 
     changes = [change for change in changes if repos.changectx(change).branch() == branch ] 

    # filter on date 
    if date != '': 
     changes = [change for change in changes if newerDate(date, repos.changectx(change).date()[0]) ] 

    return changes 

def print_item(change, link_template): 
    def _element(name, content): 
     content = cgi.escape(content) 

     print "  <%(name)s>%(content)s</%(name)s>" % { 
      'name': name, 
      'content': content 
      } 

    link = link_template % {'node': short(change.node())} 
    print " <item>" 
    _element('title', str(change.rev())) 
    _element('description', change.description()) 
    _element('guid', str(change.rev())) 
    _element('author', change.user()) 
    _element('link', link) 
    _element('pubdate', str(datetime.datetime.fromtimestamp(change.date()[0]))) 
    print " </item>" 

def print_rss(changes, repos, template): 
    print """<?xml version="1.0" encoding="UTF-8"?> 
<rss version="2.0"> 
    <channel> 
    <link>N/A</link> 
    <language>en-us</language> 

    <title>Changelog</title> 
    <description>Changelog</description> 
""" 
    for change in changes: 
     ctx = repos.changectx(change) 
     print_item(ctx, template) 

    print """ 
    </channel> 
</rss> 
""" 

if __name__=="__main__": 

    # -*- python -*- 
    print "Content-Type: application/rss+xml; charset=UTF-8" 
    print 

    f = cgi.FieldStorage() 

    if not f.has_key("repository"): 
     print "Need to specify repository." 
     sys.exit() 

    repository = f['repository'].value 
    branch = '' 
    if f.has_key('branch'): 
     branch = f['branch'].value 

    date = '' 
    if f.has_key('date') and not f.has_key('days'): 
     try: 
      #date = datetime.datetime.strptime(f['date'].value, '%Y-%m-%d') 
      date = util.parsedate(f['date'].value)[0] 
     except: 
      print 'Error in date format, use one of the following formats:', defaultdateformats 
      sys.exit() 
    elif f.has_key('days') and not f.has_key('date'): 
     days = int(f['days'].value) 
     try: 
      date = datetime.datetime.now() - datetime.timedelta(days=days) 
      date = time.mktime(date.timetuple()) 
     except: 
      print 'Error in days, please use a standard number eg. days=7' 
      sys.exit() 
    elif f.has_key('days') and f.has_key('date'): 
     print 'Error, please only supply a dayrange OR a date, not both' 
     sys.exit() 

    repos = find_repository(repository) 
    changes = find_changes(repos, branch, date) 
    rev_link_template = 'http://hg.server/hg/%(repos)s/rev/%%(node)s' % { 
     'repos': repository 
     } 
    print_rss(changes, repos, rev_link_template) 
+0

這很好。謝謝 :-) – gruszczy