代码之家  ›  专栏  ›  技术社区  ›  Tim Long

如何防止用户将二进制文件提交到Subversion中?

  •  13
  • Tim Long  · 技术社区  · 15 年前

    我有一个任性的用户,他顽固地坚持将他的二进制文件(可执行文件、DLL)提交到我们的颠覆性存储库中。我会进去删除它们,但当然,没有什么是真正从颠覆中删除的。

    虽然有时我们需要提交二进制文件,但我不希望用户将其作为例行程序来执行。我可以设置一个ignore属性,但是如果用户真的确定了二进制文件,那么这不会阻止他们提交二进制文件。我想做的是能够控制按目录提交指定文件类型的能力,特别是.exe和.dll文件。

    有没有办法在SVN中做到这一点?如果有什么不同,我们使用的是VisualVN服务器和TortoissVN。

    7 回复  |  直到 11 年前
        1
  •  5
  •   Bret    13 年前

    提姆:

    您可以尝试这个python hook脚本。它(松散地)基于上面的一个,但允许拒绝路径的正则表达式模式,并允许通过一行开始的行覆盖检查。

    Overide:

    在日志消息中。它使用了新的python打印语法,因此需要更新版本的python(2.6+?).

    from __future__ import print_function
    
    import sys,os
    import subprocess 
    import re
    
    #this is a list of illegal patterns:
    illegal_patterns = [
        '\.exe$',
        '\.dll$',
        '[\^|/]bin/',
        '[\^|/]obj/',
    ]
    
    # Path to svnlook command:
    cmdSVNLOOK=r"{}bin\svnlook.exe".format(os.environ["VISUALSVN_SERVER"])
    
    print(illegal_patterns, file=sys.stderr)
    
    print("cmdSVNLook={}".format(cmdSVNLOOK), file=sys.stderr)
    
    def runSVNLook(subCmd, transact, repoPath):
        svninfo =  subprocess.Popen([cmdSVNLOOK, subCmd, '-t', transact, repoPath], 
                              stdout = subprocess.PIPE, stderr=subprocess.PIPE)
        (stdout, stderr) = svninfo.communicate()
    
        if len(stderr) > 0:
            print("svnlook generated stderr: " + stderr, file=sys.stderr)
            sys.exit(1)
    
        return [ line.strip() for line in stdout.split("\n") ]
    
    def findIllegalPattern(fileName):
        for pattern in illegal_patterns:
            if re.search(pattern, fileName):
                print("pattern: {} matched filename:{}".format(pattern, fileName))
                return pattern
        return None
    
    def containsOverRide(logOutput):
        retVal = False
        for line in logOutput:
            print("log line: {}".format(line), file=sys.stderr)
            if re.match("^override:", line.lower()):
                retVal = True
                break
        print("contiansOverRide={}".format(retVal), file=sys.stderr)
        return retVal
    
    def findIllegalNames(changeOutput):
        illegalNames = []
        prog = re.compile('(^[ACUDRM_])[ACUDRM]*\s+(.+)')  # regex for svnlook output
        for line in changeOutput:
            print("processing:{}".format(line), file=sys.stderr)
            if (line != ""):
                match=re.search(prog, line.strip())
                if match:
                    mode = match.group(1) 
                    ptFilename = match.group(2)
                    if mode == 'A':
                      pattern = findIllegalPattern(ptFilename)
                      if pattern:
                          illegalNames.append((pattern, ptFilename))
                else:
                    print("svnlook output parsing failed!", file=sys.stderr)
                    sys.exit(1)
        return illegalNames
    
    ######### main program ################
    def main(args):
        repopath = args[1]
        transact = args[2]
    
        retVal = 0
    
        overRidden = containsOverRide(runSVNLook("log", transact, repopath))
        illegalFiles = findIllegalNames(runSVNLook("changed", transact, repopath))
    
        if len(illegalFiles):
            msg = "****************************************************************************\n"
    
            if len(illegalFiles) == 1:
                msg += "* This commit contains a file which matches a forbidden pattern            *\n"
            else:
                msg += "* This commit contains files which match a forbidden pattern               *\n"
    
            if overRidden:
                msg += "* and contains an Override line so the checkin will be allowed            *\n"
            else:
                retVal = 1
    
                msg += "* and is being rejected.                                                   *\n"
                msg += "*                                                                          *\n"
                msg += "* Files which match these patterns are genreraly created by the            *\n"
                msg += "* built process and should not be added to svn.                            *\n"
                msg += "*                                                                          *\n"
                msg += "* If you intended to add this file to the svn repository, you neeed to     *\n"
                msg += "* modify your commit message to include a line that looks like:            *\n"
                msg += "*                                                                          *\n"
                msg += "* OverRide: <reason for override>                                          *\n"
                msg += "*                                                                          *\n"
            msg +=  "****************************************************************************\n"
    
            print(msg, file=sys.stderr)
    
            if len(illegalFiles) == 1:
                print("The file and the pattern it matched are:", file=sys.stderr)
            else:
                print("The files and the patterns they matched are:", file=sys.stderr)
    
            for (pattern, fileName) in illegalFiles:
                  print('\t{}\t{}'.format(fileName, str(pattern)), file=sys.stderr)
    
        return retVal
    
    if __name__ == "__main__":
        ret = main(sys.argv)
        sys.exit(ret)
    
        2
  •  5
  •   Peter Parker    15 年前

    下面是一个小钩子脚本,它执行您想要的操作: 您必须配置两件事:

    • 非法后缀 :包含所有后缀的python列表,应中止提交。
    • CMDVSnlook :svnlook程序的路径

    import sys
    import subprocess 
    import re
    
    #this is a list of illegal suffixes:
    illegal_suffixes = ['.exe','.dll']
    
    # Path to svnlook command:
    cmdSVNLOOK="/usr/bin/svnlook";
    
    def isIllegalSuffix(progname):
        for suffix in illegal_suffixes:
            if (ptFilename.endswith(suffix)):
                return True
        return False
    
    ######### main program ################
    repopath = sys.argv[1]
    transact = sys.argv[2]
    
    retVal = 0
    svninfo = subprocess.Popen([cmdSVNLOOK, 'changed', '-t', transact, repopath], 
                                                            stdout = subprocess.PIPE, stderr=subprocess.PIPE)
    (stdout, stderr) = svninfo.communicate();
    
    prog = re.compile('(^[ACUDRM_])[ACUDRM]*\s+(.+)')  # regex for svnlook output
    for line in stdout.split("\n"):
        if (line.strip()!=""):
            match=re.search(prog, line.strip())
            if match:
                mode = match.group(1) 
                ptFilename = match.group(2)
                if mode == 'A' and isIllegalSuffix(ptFilename): 
                  retVal = 1
                  sys.stderr.write("Please do not add the following ")
                  sys.stderr.write("filetypes to repository:\n")
                  sys.stderr.write(str(illegal_suffixes)+"\n")
                  break
            else:
                sys.stderr.write("svnlook output parsing failed!\n")
                retVal = 1
                break
        else:
            # an empty line is fine!
            retVal = 0
    sys.exit(retVal)
    
        3
  •  3
  •   oefe    15 年前

    编写一个预提交挂钩,检查添加的文件是否符合您的条件。

    你可以用 pre-commit-check.py 作为起点。

        4
  •  3
  •   Joel    15 年前

    在Tortoissesvn上,可以让用户将.dll、.exe等添加到忽略列表中。这样,用户就不会意外地将它们签入。有关详细信息,请参阅此处:

    http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-ignore.html

    在服务器端,如其他人所说,您可以使用hook脚本。

        5
  •  3
  •   Valentin Rocher    15 年前

    你可以使用 pre-commit 钩子。您必须编写一个简单的程序(任何语言),如果文件是二进制的,它将返回一个非零值。

    here 有关存储库挂钩的一般文档,以及 here 对于Apache中的python示例。

    您可以查看文件名,或者使用 file 看看他们的类型。

        6
  •  1
  •   Sebastian    11 年前

    您可以使用svnlook命令。下面是一个执行此任务的python类:

        SVNTransactionParser(object):
            def __init__(self, repos, txn):
                self.repos = repos
                self.txn = txn
                self.ms = magic.open(magic.MAGIC_NONE)
                self.ms.load()
    
            def tx_files(self):
                files_to_analyze = list()
                for l in self.__svnlook('changed')[0].readlines():
                    l = l.replace('\n', '');
                    if not l.endswith('/') and l[0] in ['A', 'U']:
                        files_to_analyze.append(l.split(' ')[-1:][0])
    
                files = dict()        
                for file_to_analyze in files_to_analyze:
                    files[file_to_analyze] = {
                                    'size': self.__svnlook('filesize', file_to_analyze)[0].readlines()[0].replace('\n', ''),
                                    'type': self.ms.buffer(self.__svnlook('cat', file_to_analyze)[0].readline(4096)),
                                    'extension': os.path.splitext(file_to_analyze)[1]}
    
                return files
    
            def __svnlook(self, command, extra_args=""):
                cmd = '%s %s %s -t "%s" %s' % (SVNLOOK, command, self.repos, self.txn, extra_args)
                out = popen2.popen3(cmd)
                return (out[0], out[2])
    

    TXX文件() 方法返回包含如下信息的映射:

    { 
        '/path/to/file1.txt': {'size': 10, 'type': 'ASCII', 'extension': '.txt'}, 
        '/path/to/file2.pdf': {'size': 10134, 'type': 'PDF', 'extension': '.dpf'}, 
    }
    

    你需要库中的巨蟒魔法( https://github.com/ahupp/python-magic )

        7
  •  0
  •   tangens    15 年前

    您可以使用预提交挂钩脚本来检查文件是二进制的还是文本的。