简体   繁体   English

在预提交挂钩中-如何访问/比较文件的当前版本和先前版本

[英]In a pre-commit hook - how to access/compare current and previous versions of files

I'm trying to add to our existing pre-commit SVN hook so that it will check for and block an increase in file size for files in specific directory/s. 我正在尝试添加到我们现有的预提交SVN挂钩中,以便它将检查并阻止特定目录中文件的文件大小增加。

I've written a python script to compare two file sizes, which takes two files as arguments and uses sys.exit(0) or (1) to return the result, this part seems to work fine. 我已经编写了一个python脚本来比较两个文件大小,该文件将两个文件作为参数并使用sys.exit(0)或(1)返回结果,这部分工作正常。

My problem is in calling the python script from the batch file, how to reference the newly committed and previous versions of each file? 我的问题是从批处理文件调用python脚本,如何引用每个文件的新提交和以前的版本? The existing code is new to me and a mess of %REPOS%, %TXN%s etc and I'm not sure how to go about using them. 现有的代码对我来说是新的,还有%REPOS%,%TXN%s等杂乱无章的消息,我不确定如何使用它们。 Is there a simple, standard way of doing this? 有没有简单,标准的方法可以做到这一点?

It also already contains code to loop through the changed files using svnlook changed, so that part shouldn't be an issue. 它还已经包含使用svnlook change遍历更改的文件的代码,因此该部分不应成为问题。

Thanks very much 非常感谢

If comparing file sizes is all you need to do, look no further than the svnlook filesize command. 如果只需要比较文件大小, svnlook filesize需要svnlook filesize命令即可。 The default invocation - svnlook filesize repo path - will give you the size of the HEAD revision of path . 默认调用- svnlook filesize repo path -会给你的HEAD修订的大小path To get the size of the path in the incoming commit use svnlook filesize repo path -t argv[2] . 要获取传入提交中路径的大小,请使用svnlook filesize repo path -t argv[2]

Still, here is an example of listing all revisions of a versioned path (except the incoming one, since this is pre-commit hook). 仍然,这里是一个示例,列出了版本化路径的所有修订版(传入的版本除外,因为这是预提交的钩子)。

#!/usr/bin/env python

from sys import argv, stderr, exit
from subprocess import check_output

repo = argv[1]
transaction = argv[2]

def path_history(path, limit=5):
    path = '/%s' % path
    cmd = ('svnlook', 'history', '-l', str(limit), repo, path)
    out = check_output(cmd).splitlines()[2:]

    for rev, _path in (i.split() for i in out):
        if _path == path:
            yield rev

def commit_changes():
    cmd = ('svnlook', 'changed', repo, '-t', transaction)
    out = check_output(cmd).splitlines()

    for line in out:
        yield line.split()

def filesize(path, rev=None, trans=None):
    cmd = ['svnlook', 'filesize', repo, path]
    if rev:     cmd.extend(('-r', str(rev)))
    elif trans: cmd.extend(('-t', str(trans)))

    out = check_output(cmd)
    return out.rstrip()

def filesize_catwc(path, rev=None, trans=None):
    '''A `svnlook filesize` substitute for older versions of svn. 
    Uses `svnlook cat ... | wc -c` and should be very inefficient
    for large files.'''

    arg = '-r %s' % rev if rev else '-t %s' % trans
    cmd = 'svnlook cat %s %s %s | wc -c' % (arg, repo, path)

    out = check_output(cmd, shell=True)
    return out.rstrip()


for status, path in commit_changes():
    if status in ('A', 'M', 'U'):
        # get the last 5 revisions of the added/modified path
        revisions = list(path_history(path))
        headrev = revisions[0]

        oldsize = filesize(path, rev=headrev)
        newsize = filesize(path, trans=transaction)

It is probably easier to write a whole pre-commit script in python. 用python编写整个pre-commit脚本可能会更容易。 According to the subversion handbook , there are three inputs to pre-commit ; 根据颠覆手册 ,有三个输入要预先提交

  • Two command line arguments 两个命令行参数
    • repository path 资料库路径
    • commit transaction name 提交交易名称
  • lock-token info on standard input 标准输入上的锁令牌信息

If you want to know which files have changed, I suggest you use the subprocess.check_output() function to call svnlook changed . 如果您想知道哪些文件已更改,建议您使用subprocess.check_output()函数来调用svnlook changed For the files which contents have changed, you should call svnlook filesize , to get the size of the file as it is in the last revision in the repository. 对于内容已更改的文件,应调用svnlook filesize ,以获取文件库中最新版本中文件的大小。 The size of the equivalent file in the working directory you'd have to query with os.stat() , as shown in the function getsizes() . 您必须使用os.stat()查询的工作目录中等效文件的大小,如getsizes()函数所示。

import subprocess
import sys
import os

repo = sys.argv[1]
commit_name = sys.argv[2]

def getsizes(rname, rfile):
   '''Get the size of the file in rfile from the repository rname. 
   Derive the filename in the working directory from rfile, and use 
   os.stat to get the filesize. Return the two sizes.
   '''
   localname = rfile[10:].strip() # 'U   trunk/foo/bar.txt' -> 'foo/bar.txt'
   reposize = subprocess.check_output(['svnlook', 'filesize', rname, rfile])
   reposize = int(reposize)
   statinfo = os.stat(localname)
   return (reposize, statinfo.st_size)

lines = subprocess.check_output(['svnlook', 'changed', repo]).splitlines()
for line in lines:
    if line.startswith('U ') or line.startswith('UU'):
       # file contents have changed
       reposize, wdsize = getsizes(repo, line)
       # do something with the sizes here...
    elif line.startswith('_U'):
       # properties have changed
       pass

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM