2010-01-29 33 views
13

Tengo un usuario obstinado que insiste tercamente en comprometer sus binarios (ejecutables, DLL) en nuestros repositorios de subversión. Yo iría y los eliminaría, pero por supuesto nada se elimina realmente de la subversión.¿Cómo puedo evitar que los usuarios cometan binarios en subversión?

Si bien hay momentos en los que tenemos que cometer binarios, no quiero que los usuarios lo hagan de forma rutinaria. Puedo configurar una propiedad de ignorar, pero eso no impide que los usuarios cometan binarios si están realmente determinados. Lo que me gustaría hacer es poder controlar la capacidad de enviar tipos de archivos nominados, particularmente archivos .exe y .dll, directorio por directorio.

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

+0

Bueno, con tres respuestas tan rápidas e imposibles de elegir, estoy seguro de que un script de ejemplo aseguraría el estado "aceptado" :) –

+2

¿Qué le parece disciplinar a su usuario? No todas las soluciones son técnicas, ¿sabes? –

+0

@Lasse: Estoy de acuerdo, pero en realidad considero que esto es útil para evitar que * yo * * accidentalmente * coloque binarios en el repositorio SVN (es decir, configurar Tortoise en una máquina nueva y olvidar agregar el "contenedor" y " obj "excepciones) – Aaronaught

Respuesta

5

Tim:

Es posible probar este script gancho pitón. Es (libremente) en base a la anterior, pero permite que los patrones de expresión regulares por las sendas rechazar y permite anular el cheque por tener una línea que comienza

overide:

en el mensaje de registro. Utiliza la nueva sintaxis de impresión 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) 
+0

Esto es perfecto. Tengo IronPython en el servidor y este script funciona perfectamente para mis necesidades. Me gusta el concepto de dar a los usuarios la capacidad de anular el enganche. Sin embargo, VisualSVN requiere un archivo de proceso por lotes, así que tuve que crear un diseño único para llamar al script de Python. –

3

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

Puede usar pre-commit-check.py como punto de partida.

+0

¿Cómo sugeriría que controle esto por directorio? Algunos directorios necesito permitir que los binarios sean registrados, otros no. Preferiría no tener que codificar esta información en un script. –

+0

Su secuencia de comandos podría leer la lista de rutas permitidas desde un archivo (probablemente desee almacenar el archivo en el servidor, no en el repositorio, para que el usuario no pueda cambiarlo) Si desea almacenar la información en el repositorio , puedes usar propiedades en el directorio en su lugar. Esto hace que la información sea más local y manejará automáticamente nuevas ramas/etiquetas. – oefe

3

Puede usar un gancho pre-commit. Tendrá que escribir un programa simple (en cualquier idioma) que devuelva un valor distinto de cero si el archivo es binario.

Consulte here para documentación genérica sobre los ganchos del repositorio, y here para un ejemplo de python de Apache.

Puede consultar los nombres de los archivos o utilizar file para ver sus tipos.

+0

Esto: en general, es posible que también desee comprobar los nombres de archivos .dll, .exe, etc ... dada la persistencia obstinada de este usuario. –

0

Puede utilizar un script de enlace de precompilación que comprueba si el archivo es binario o textual.

+0

Mala idea, no puede agregar imágenes para un sitio web, por ejemplo. La verificación de la extensión es mucho mejor –

3

En TortoiseSVN puede hacer que el usuario agregue .dll, .exe, etc. a la lista de ignorar. . De esa manera, el usuario no va a querer comprobar en Ver aquí para más información:

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

En el lado del servidor, como otros han mencionado, se puede utilizar un script gancho.

+2

Bueno, es un usuario testarudo con el que estoy tratando aquí. Le han pedido varias veces que no cometa binarios, pero aún lo hace. No creo que sea una cuestión de recordar. Es por eso que necesito _forzar_ la política. –

+0

Para ser franco, una forma de hacer cumplir este problema es despedirlo. No me refiero a que este sea su primer método para manejarlo, pero si se llega a la meta, los jugadores que no pertenecen al equipo no tienen lugar en un equipo. –

+0

También puede denegar cualquier acceso de confirmación. Entonces él solo puede enviar sus diferencias como parches a sus colegas. Esta es la forma en que Subversion restringe su acceso de escritura a su repositorio: tienes que demostrar que escribes el código correcto enviando parches a la lista de correo –

5

Aquí es un pequeño script ganchos que está haciendo lo que quiere: Tiene que configurar 2 cosas:

  • illegal_suffixes: una lista de pitón con todos los sufijos que debe abortar el envío
  • cmdSVNLOOK: la ruta de acceso al programa de 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) 
+0

Gracias, le agradezco que se haya tomado el tiempo de publicarlo. Desafortunadamente, estamos usando el servidor VisualSVN que contiene Windows. Necesitaré VBScript, JScript o un archivo por lotes de DOS. Sin embargo, +1 para publicar el script. –

+0

puede usar python en windows, y svnlook está disponible con svn visual: https: //www.visualsvn.com/support/svnbook/ref/svnlook/ –

+0

Desarrollé esto bajo windwos ;-) se prueba en linux y windows. Puede usar python para hooks y svnlook es parte de VisualSVN, de lo contrario puede (y debe) instalar svn-commandline –

1

Puede usar el comando svnlook. Aquí es una clase Python que hacer 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]) 

tx_files() método devuelve un mapa con información como la siguiente:

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

Tendrá la biblioteca python-magia (https://github.com/ahupp/python-magic)

Cuestiones relacionadas