#!/usr/bin/env python2 # -*- 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 USAGE %(scriptname)s [options] 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()