¿Cómo puedo evitar que los usuarios cometan binarys en subversión?

Tengo un usuario testarudo que insiste obstinadamente en comprometer sus binarys (ejecutables, DLL) en nuestros repositorys de subversión. Yo iría y los eliminaría, pero por supuesto nada se elimina realmente de la subversión.

Si bien hay momentos en los que necesitamos cometer binarys, no quiero que los usuarios lo hagan por rutina. Puedo configurar una propiedad de ignorar, pero eso no impide que los usuarios cometan binarys si están realmente determinados. Lo que me gustaría hacer es poder controlar la capacidad de enviar types de files nominados, particularmente files .exe y .dll, directory por directory.

¿Hay alguna manera de hacerlo en SVN? Si hace alguna diferencia, estamos usando el server VisualSVN y TortoiseSVN.

Tim:

Puede probar este script de hook de python. Está (vagamente) basado en el anterior, pero permite patrones de expresión regulares para las routes de rechazo y permite anular el control al tener una línea que comienza

Overide:

en el post de logging. Utiliza la nueva syntax de printing de python, por lo que requiere una versión bastante reciente de 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) 

Aquí hay un pequeño script de ganchos que está haciendo lo que desea: debe configurar 2 cosas:

  • illegal_suffixes : una list de python con todos los sufijos que deberían abortar la confirmación
  • cmdSVNLOOK : la ruta al progtwig 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) 

En TortoiseSVN puede hacer que el usuario agregue .dll, .exe, etc. a la list de ignorar. De esta forma, el usuario no los registrará accidentalmente. Consulte aquí para get más información:

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

En el lado del server, como han indicado otros, puede usar un script de enlace.

Escriba un enlace precompromiso que verifique los files agregados si se ajustan a sus criterios.

Puede usar precommit-check.py como punto de partida.

Puede usar un gancho de precompromiso . Tendrá que escribir un progtwig simple (en cualquier idioma) que devuelva un valor distinto de cero si el file es binary.

Vea aquí la documentation genérica sobre los ganchos del repository, y aquí un ejemplo de Python de Apache.

Puede mirar los nombres de los files o usar el file para ver sus types.

Puede usar el command svnlook. Aquí hay una class de python que hace este trabajo:

  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]) 

El método tx_files () devuelve un map con información como esta:

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

Necesitarás la biblioteca python-magic ( https://github.com/ahupp/python-magic )

Podría usar un script de enlace precompromiso que verifique si el file es binary o textual.