Mercurial перехватывает запрет на фиксацию больших двоичных файлов
Я хочу иметь перехватчик Mercurial, который будет запускаться перед фиксацией транзакции, которая прервет транзакцию, если фиксируемый двоичный файл больше 1 мегабайта. Я нашел следующий код, который работает нормально, за исключением одной проблемы. Если моя ревизия включает удаление файла, эта ловушка вызовет исключение.
Крючок (я использую 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
Исключение:
$ hg commit -m 'commit message'
error: pretxncommit hook raised an exception: apps/helpers/templatetags/include_extends.py@bced6272d8f4: not found in manifest
transaction abort!
rollback completed
abort: apps/helpers/templatetags/include_extends.py@bced6272d8f4: not found in manifest!
Я не знаком с написанием Mercurial-хуков, поэтому я не совсем понимаю, что происходит. Почему хук заботится о том, чтобы файл был удален, если hg уже знает об этом? Есть ли способ исправить этот хук, чтобы он работал постоянно?
Обновление (решено): я изменил ловушку, чтобы отфильтровать файлы, которые были удалены из набора изменений.
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
2 ответа
for f in ctx.files()
будет включать в себя удаленные файлы, вам нужно отфильтровать их.
(и вы можете заменить for rev in range(ctx.rev(), tip+1):
от for rev in xrange(ctx.rev(), len(repo)):
и удалить tip = ...
)
Если вы используете современный HG, вы не делаете ctx = context.changectx(repo, node)
но ctx = repo[node]
вместо.
Это действительно легко сделать в хуке оболочки в недавнем 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
Что тут происходит? Сначала у нас есть набор файлов, чтобы найти все измененные файлы, которые являются проблематичными (см. "Hg help filesets" в hg 1.9). Команда 'locate' похожа на состояние, за исключением того, что она просто перечисляет файлы и возвращает 0, если она что-то находит. И мы указываем '-r tip', чтобы посмотреть ожидающий коммит.