2021-02-24 10:55:56 +04:00
|
|
|
#!/usr/bin/env python2
|
2013-08-27 15:14:44 +04:00
|
|
|
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
|
|
|
|
|
|
u"""%(scriptname)s: afficher le hash SHA-1 d'un fichier exprimé en base 36
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
USAGE
|
|
|
|
%(scriptname)s [options]
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
OPTIONS
|
|
|
|
-s, --skip
|
|
|
|
Ignorer les premières lignes modeline + empty. Le dernier saut de ligne
|
|
|
|
est toujours ignoré pour compatibilité avec le code PHP de MediaWiki.
|
|
|
|
-f, --input INPUT
|
|
|
|
Lire INPUT au lieu de STDIN
|
|
|
|
--mediawiki MWDIR
|
|
|
|
Mode de fonctionnement pour le script mediawiki. Une liste de fichiers
|
|
|
|
est lu sur STDIN, et pour chacun de ces fichiers afficher une ligne de
|
|
|
|
la forme 'name,path,hash,' où name est le nom du fichier, path son
|
|
|
|
chemin relativement à MWDIR, et hash le hash SHA-1 exprimé en base 36."""
|
|
|
|
|
|
|
|
import os, sys, re, csv
|
|
|
|
from os import path
|
|
|
|
|
|
|
|
try:
|
|
|
|
from hashlib import sha1
|
|
|
|
except ImportError:
|
|
|
|
from sha import new
|
|
|
|
sha1 = new
|
|
|
|
|
|
|
|
from ulib.base.base import strip_nl
|
|
|
|
from ulib.base.args import build_options, get_args
|
|
|
|
|
|
|
|
DIGIT_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz'
|
|
|
|
def hex2b36(input):
|
|
|
|
input = input.lower()
|
|
|
|
inDigits = [DIGIT_CHARS.index(c) for c in input]
|
|
|
|
outChars = ''
|
|
|
|
while inDigits:
|
|
|
|
work = 0
|
|
|
|
workDigits = []
|
|
|
|
for digit in inDigits:
|
|
|
|
work *= 16
|
|
|
|
work += digit
|
|
|
|
if work < 36:
|
|
|
|
if workDigits:
|
|
|
|
workDigits.append(0)
|
|
|
|
else:
|
|
|
|
workDigits.append(int(work / 36))
|
|
|
|
work = work % 36
|
|
|
|
outChars = DIGIT_CHARS[work] + outChars
|
|
|
|
inDigits = workDigits
|
|
|
|
while len(outChars) < 31:
|
|
|
|
outChars = '0' + outChars
|
|
|
|
return outChars
|
|
|
|
|
|
|
|
RE_MODELINE = re.compile(r'^#')
|
|
|
|
RE_BLANKLINE = re.compile(r'^$')
|
|
|
|
def get_digest(inf, skip=False):
|
|
|
|
skip_modeline = skip
|
|
|
|
skip_blankline = False
|
|
|
|
m = sha1()
|
|
|
|
prevnl = None
|
|
|
|
while True:
|
|
|
|
l = inf.readline()
|
|
|
|
if l == '': break
|
|
|
|
|
|
|
|
if prevnl is not None:
|
|
|
|
m.update(prevnl)
|
|
|
|
l0 = strip_nl(l)
|
|
|
|
prevnl = l[len(l0):]
|
|
|
|
l = l0
|
|
|
|
|
|
|
|
if skip_modeline:
|
|
|
|
if RE_MODELINE.match(l) is not None:
|
|
|
|
prevnl = None
|
|
|
|
continue
|
|
|
|
skip_modeline = False
|
|
|
|
skip_blankline = True
|
|
|
|
if skip_blankline:
|
|
|
|
if RE_BLANKLINE.match(l) is not None:
|
|
|
|
prevnl = None
|
|
|
|
continue
|
|
|
|
skip_blankline = False
|
|
|
|
|
|
|
|
m.update(l)
|
|
|
|
|
|
|
|
hexdigest = m.hexdigest()
|
|
|
|
return hex2b36(hexdigest)
|
|
|
|
|
|
|
|
HEADERS = ['title', 'path', 'hash', 'doublon']
|
|
|
|
def do_mediawiki(inf, mwdir, skip=False, outf=None):
|
|
|
|
if not mwdir.endswith('/'): mwdir += '/'
|
|
|
|
if outf is None: outf = sys.stdout
|
|
|
|
outcsv = csv.writer(outf, lineterminator='\n')
|
|
|
|
|
|
|
|
outcsv.writerow(HEADERS)
|
|
|
|
while True:
|
|
|
|
fp = inf.readline()
|
|
|
|
if fp == '': break
|
|
|
|
fp = strip_nl(fp)
|
|
|
|
if fp.startswith(mwdir): fpath = fp[len(mwdir):]
|
|
|
|
else: fpath = fp
|
|
|
|
ftitle = path.splitext(path.basename(fpath))[0]
|
|
|
|
fpinf = open(fp, 'rb')
|
|
|
|
try:
|
|
|
|
fhash = get_digest(fpinf, skip)
|
|
|
|
finally:
|
|
|
|
fpinf.close()
|
|
|
|
outcsv.writerow([ftitle, fpath, fhash, ''])
|
|
|
|
|
|
|
|
def display_help():
|
|
|
|
uprint(__doc__ % globals())
|
|
|
|
|
|
|
|
def run_b36sha1():
|
|
|
|
options, longoptions = build_options([
|
|
|
|
('h', 'help', "Afficher l'aide"),
|
|
|
|
('s', 'skip', "Ignorer les premières lignes et le dernier saut de ligne"),
|
|
|
|
('f:', 'input=', "Spécifier un fichier à lire"),
|
|
|
|
('m:', 'mediawiki=', "Support pour le script mediawiki"),
|
|
|
|
])
|
|
|
|
options, args = get_args(None, options, longoptions)
|
|
|
|
skip = False
|
|
|
|
inputfile = None
|
|
|
|
mwdir = None
|
|
|
|
for option, value in options:
|
|
|
|
if option in ('-h', '--help'):
|
|
|
|
display_help()
|
|
|
|
sys.exit(0)
|
|
|
|
elif option in ('-s', '--skip'):
|
|
|
|
skip = True
|
|
|
|
elif option in ('-f', '--input'):
|
|
|
|
inputfile = value
|
|
|
|
elif option in ('-m', '--mediawiki'):
|
|
|
|
mwdir = value
|
|
|
|
|
|
|
|
if inputfile is None or inputfile == '-':
|
|
|
|
inf = sys.stdin
|
|
|
|
close = False
|
|
|
|
else:
|
|
|
|
inf = open(inputfile, 'rb')
|
|
|
|
close = True
|
|
|
|
|
|
|
|
try:
|
|
|
|
if mwdir is None: print get_digest(inf, skip)
|
|
|
|
else: do_mediawiki(inf, mwdir, skip)
|
|
|
|
finally:
|
|
|
|
if close: inf.close()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
run_b36sha1()
|