2010-03-31 3 views
10

Je souhaite avoir un hook Mercurial qui sera exécuté avant de valider une transaction qui interrompra la transaction si un fichier binaire en cours de validation est supérieur à 1 mégaoctet. J'ai trouvé le code suivant qui fonctionne bien, sauf pour un problème. Si mon changeset implique la suppression d'un fichier, ce hook lèvera une exception.Crochet Mercurial pour interdire la validation de gros fichiers binaires

Le crochet (j'utilise pretxncommit = python:checksize.newbinsize):

from mercurial import context, util 
from mercurial.i18n import _ 
import mercurial.node as dpynode 

'''hooks to forbid adding binary file over a given size 

Ensure the PYTHONPATH is pointing where hg_checksize.py is and setup your 
repo .hg/hgrc like this: 

[hooks] 
pretxncommit = python:checksize.newbinsize 
pretxnchangegroup = python:checksize.newbinsize 
preoutgoing = python:checksize.nopull 

[limits] 
maxnewbinsize = 10240 
''' 

def newbinsize(ui, repo, node=None, **kwargs): 
    '''forbid to add binary files over a given size''' 
    forbid = False 
    # default limit is 10 MB 
    limit = int(ui.config('limits', 'maxnewbinsize', 10000000)) 
    tip = context.changectx(repo, 'tip').rev() 
    ctx = context.changectx(repo, node) 
    for rev in range(ctx.rev(), tip+1): 
     ctx = context.changectx(repo, rev) 
     print ctx.files() 
     for f in ctx.files(): 
      fctx = ctx.filectx(f) 
      filecontent = fctx.data() 
      # check only for new files 
      if not fctx.parents(): 
       if len(filecontent) > limit and util.binary(filecontent): 
        msg = 'new binary file %s of %s is too large: %ld > %ld\n' 
        hname = dpynode.short(ctx.node()) 
        ui.write(_(msg) % (f, hname, len(filecontent), limit)) 
        forbid = True 
    return forbid 

L'exception:

$ hg commit -m 'commit message' 
error: pretxncommit hook raised an exception: apps/helpers/templatetags/[email protected]: not found in manifest 
transaction abort! 
rollback completed 
abort: apps/helpers/templatetags/[email protected]: not found in manifest! 

Je ne suis pas familier avec l'écriture des crochets Mercurial, donc je suis assez confus au sujet de ce qui est passe. Pourquoi le crochet tient-il compte qu'un fichier a été enlevé si hg le sait déjà? Y at-il un moyen de réparer ce crochet afin qu'il fonctionne tout le temps?

Mise à jour (résolue): J'ai modifié le crochet pour filtrer les fichiers qui ont été supprimés dans le changeset.

def newbinsize(ui, repo, node=None, **kwargs): 
    '''forbid to add binary files over a given size''' 
    forbid = False 
    # default limit is 10 MB 
    limit = int(ui.config('limits', 'maxnewbinsize', 10000000)) 
    ctx = repo[node] 
    for rev in xrange(ctx.rev(), len(repo)): 
     ctx = context.changectx(repo, rev) 

     # do not check the size of files that have been removed 
     # files that have been removed do not have filecontexts 
     # to test for whether a file was removed, test for the existence of a filecontext 
     filecontexts = list(ctx) 
     def file_was_removed(f): 
      """Returns True if the file was removed""" 
      if f not in filecontexts: 
       return True 
      else: 
       return False 

     for f in itertools.ifilterfalse(file_was_removed, ctx.files()): 
      fctx = ctx.filectx(f) 
      filecontent = fctx.data() 
      # check only for new files 
      if not fctx.parents(): 
       if len(filecontent) > limit and util.binary(filecontent): 
        msg = 'new binary file %s of %s is too large: %ld > %ld\n' 
        hname = dpynode.short(ctx.node()) 
        ui.write(_(msg) % (f, hname, len(filecontent), limit)) 
        forbid = True 
    return forbid 

Répondre

4

for f in ctx.files() comprendra les fichiers supprimés, vous devez filtrer les out.

(et vous pouvez remplacer par for rev in range(ctx.rev(), tip+1):for rev in xrange(ctx.rev(), len(repo)):, et enlever tip = ...)

Si vous utilisez un hg moderne, vous ne faites pas ctx = context.changectx(repo, node) mais ctx = repo[node] à la place.

+0

Comment filtrer les fichiers supprimés de ctx.files()? – hekevintran

+0

Peu importe, j'ai été capable de le comprendre. Merci. – hekevintran

+0

attraper l'exception est suffisante;) – tonfa

5

C'est vraiment facile à faire dans un crochet shell au cours des dernières Mercurial:

if hg locate -r tip "set:(added() or modified()) and binary() and size('>100k')"; then 
    echo "bad files!" 
    exit 1 
else 
    exit 0 
fi 

Qu'est-ce qui se passe ici? Nous avons d'abord un ensemble de fichiers pour trouver tous les fichiers modifiés qui posent problème (voir 'hg help filesets' dans hg 1.9). La commande 'locate' est comme status, sauf qu'elle ne fait que lister les fichiers et renvoie 0 si elle trouve quelque chose. Et nous spécifions '-r tip' pour regarder la validation en attente.

Questions connexes