Svn 如何防止用户将二进制文件提交到subversion?
我有一个固执的用户,他固执地坚持将他的二进制文件(可执行文件、DLL)提交到我们的subversion存储库中。我会进去删除它们,但当然,从subversion中没有真正删除的东西 虽然有时我们需要提交二进制文件,但我不希望用户将其作为例行公事。我可以设置一个ignore属性,但如果用户真的确定了,这并不能阻止他们提交二进制文件。我想做的是能够控制提交指定文件类型的能力,特别是.exe和.dll文件,逐个目录Svn 如何防止用户将二进制文件提交到subversion?,svn,permissions,visualsvn,Svn,Permissions,Visualsvn,我有一个固执的用户,他固执地坚持将他的二进制文件(可执行文件、DLL)提交到我们的subversion存储库中。我会进去删除它们,但当然,从subversion中没有真正删除的东西 虽然有时我们需要提交二进制文件,但我不希望用户将其作为例行公事。我可以设置一个ignore属性,但如果用户真的确定了,这并不能阻止他们提交二进制文件。我想做的是能够控制提交指定文件类型的能力,特别是.exe和.dll文件,逐个目录 在SVN中有这样做的方法吗?如果有任何不同,我们将使用VisualSVN服务器和Tor
在SVN中有这样做的方法吗?如果有任何不同,我们将使用VisualSVN服务器和TortoiseSVN。编写一个预提交钩子,检查添加的文件是否符合您的标准 您可以使用作为起点。您可以使用挂钩。如果文件是二进制文件,您必须编写一个简单的程序(用任何语言)返回一个非零值 有关存储库挂钩的一般文档,以及Apache中的python示例,请参阅
您可以查看文件名,或使用查看其类型。您可以使用预提交钩子脚本检查文件是否为二进制或文本。在OrtoiseSVN上,您可以让用户将.dll、.exe等添加到忽略列表中。这样,用户就不会意外地将其签入。有关更多信息,请参见此处:
在服务器端,正如其他人所说,您可以使用钩子脚本。下面是一个小钩子脚本,它正在执行您想要的操作: 您必须配置两件事:
- 非法后缀:包含所有后缀的python列表,这些后缀应中止提交
- cmdSVNLOOK:指向svnlook程序的路径
from\uuuuu future\uuuuu导入打印功能
导入系统,操作系统
导入子流程
进口稀土
#这是非法模式的列表:
非法_模式=[
“\.exe$”,
“\.dll$”,
“[\^ |/]bin/”,
“[\^ |/]obj/”,
]
#svnlook命令的路径:
cmdSVNLOOK=r“{}bin\svnlook.exe”。格式(os.environ[“VISUALSVN_服务器])
打印(非法的_模式,文件=sys.stderr)
打印(“cmdSVNLook={}”。格式(cmdSVNLook),文件=sys.stderr)
def RUNSVLOOK(subCmd、transact、repoPath):
svninfo=subprocess.Popen([cmdSVNLOOK,subCmd,'-t',transact,repoPath],
stdout=subprocess.PIPE,stderr=subprocess.PIPE)
(stdout,stderr)=svninfo.communicate()
如果len(stderr)>0:
打印(“svnlook生成的stderr:+stderr,file=sys.stderr)
系统出口(1)
返回[line.strip(),用于stdout.split中的行(“\n”)]
def findIllegalPattern(文件名):
对于非法_模式中的模式:
如果重新搜索(模式、文件名):
打印(“模式:{}匹配的文件名:{}”。格式(模式,文件名))
返回模式
一无所获
def containsOverRide(注销输出):
retVal=False
对于登录输出中的行:
打印(“日志行:{}”。格式(行),文件=sys.stderr)
如果重新匹配(“^override:”,line.lower()):
retVal=True
打破
打印(“contiansOverRide={}.format(retVal),file=sys.stderr)
返回返回
def findIllegalNames(更改输出):
非法名称=[]
prog=re.compile('(^[ACUDRM])[ACUDRM]*\s+(.+)')#regex,用于svnlook输出
对于changeOutput中的行:
打印(“处理:{}”。格式(行),文件=sys.stderr)
如果(行!=“”):
匹配=重新搜索(prog,line.strip())
如果匹配:
模式=匹配。组(1)
ptFilename=match.group(2)
如果模式=='A':
pattern=findIllegalPattern(ptFilename)
如果模式:
illegalNames.append((模式,ptFilename))
其他:
打印(“svnlook输出解析失败!”,文件=sys.stderr)
系统出口(1)
返回非法姓名
#########主程序################
def主(args):
repopath=args[1]
transact=args[2]
retVal=0
overrided=containsOverRide(runSVNLook(“log”、transact、repopath))
illegalFiles=findIllegalNames(runSVNLook(“已更改”、事务处理、repopath))
如果是len(非法文件):
msg=“***************************************************************************************************************************************\n”
如果len(非法文件)==1:
msg+=“*此提交包含与禁止模式匹配的文件*\n”
其他:
msg+=“*此提交包含与禁止模式匹配的文件*\n”
如果被覆盖:
msg+=“*并包含覆盖行,因此将允许签入*\n”
其他:
retVal=1
msg+=“*正在被拒绝。*\n”
msg+=“***\n”
msg+=“*与这些模式匹配的文件通常由*\n”
msg+=“*已生成进程,不应添加到svn.*\n”
msg+=“***\n”
msg+=“*如果要将此文件添加到svn存储库,您需要*\n”
msg+=“*修改您的提交消息,使其包含如下行:*\n”
msg+=“***\n”
msg+=“*覆盖:
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)
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)
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])
{
'/path/to/file1.txt': {'size': 10, 'type': 'ASCII', 'extension': '.txt'},
'/path/to/file2.pdf': {'size': 10134, 'type': 'PDF', 'extension': '.dpf'},
}