diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index ffcbc2d8c..2c687bc07 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -5,6 +5,8 @@ # Esse script precisa rodar em python 2 # e depende apenas do descrito no arquivo requiments.txt +import cStringIO +import hashlib import mimetypes import os import sys @@ -16,9 +18,10 @@ import git import magic import pyaml import yaml +from unipath import Path + import ZODB.DB import ZODB.FileStorage -from unipath import Path from ZODB.broken import Broken EXTENSOES = { @@ -62,29 +65,25 @@ def br(obj): return obj -def guess_extension(caminho): - mime = magic.from_file(caminho, mime=True) +def guess_extension(fullname, buffer): + mime = magic.from_buffer(buffer, mime=True) try: return EXTENSOES[mime] except KeyError as e: - msg = '\n'.join([ - 'Extensão não conhecida para o arquivo:', - caminho, - 'E mimetype:', - mime, - ' Algumas possibilidades são:', ] + + possibilidades = '\n'.join( [" '{}': '{}',".format(mime, ext) - for ext in mimetypes.guess_all_extensions(mime)] + - ['Atualize o código do dicionário EXTENSOES!'] - ) + for ext in mimetypes.guess_all_extensions(mime)]) + msg = '''Extensão não conhecida para o arquivo: {} + e mimetype: {} + Algumas possibilidades são: + {} + Atualize o código do dicionário EXTENSOES! + '''.format(fullname, mime, possibilidades) print(msg) raise Exception(msg, e) -nomes_arquivos_exportados = {} - - -def dump_file(doc, path): +def dump_file(doc, path, salvar): name = doc['__name__'] fullname = os.path.join(path, name) @@ -104,23 +103,11 @@ def dump_file(doc, path): doc['data'] = pdata pdata = doc - with open(fullname, 'w') as arq: - while pdata: - arq.write(pdata.pop('data')) - pdata = br(pdata.pop('next', None)) - - base, original_extension = os.path.splitext(fullname) - extension = guess_extension(fullname) - if extension == '.xml' and original_extension in ['.xsl', '.xslt']: - # não trocamos as extensões XSL e XSLT - final_name = fullname - else: - # trocamos a extensão pela adivinhada - final_name = base + extension - os.rename(fullname, final_name) - nomes_arquivos_exportados[fullname] = final_name - print(final_name) - + output = cStringIO.StringIO() + while pdata: + output.write(pdata.pop('data')) + pdata = br(pdata.pop('next', None)) + salvar(fullname, output.getvalue()) return name @@ -165,7 +152,7 @@ def logando_nao_identificados(): print('#' * 80) -def dump_folder(folder, path='', enum=enumerate_folder): +def dump_folder(folder, path, salvar, enum=enumerate_folder): name = folder['id'] path = os.path.join(path, name) if not os.path.exists(path): @@ -175,7 +162,7 @@ def dump_folder(folder, path='', enum=enumerate_folder): if dump == '?': nao_identificados[meta_type].append(path + '/' + id) elif dump: - id_interno = dump(obj, path) + id_interno = dump(obj, path, salvar) assert id == id_interno return name @@ -211,18 +198,16 @@ def read_sde(element): return data -def save_as_yaml(path, name, obj): +def save_as_yaml(path, name, obj, salvar): fullname = os.path.join(path, name) - with open(fullname, 'w') as arquivo: - yaml.safe_dump(obj, arquivo, allow_unicode=True) - print(fullname) - return fullname + conteudo = yaml.safe_dump(obj, allow_unicode=True) + salvar(fullname, conteudo) -def dump_sde(strdoc, path, tipo): +def dump_sde(strdoc, path, salvar, tipo): id = strdoc['id'] sde = read_sde(strdoc) - save_as_yaml(path, '{}.{}.yaml'.format(id, tipo), sde) + save_as_yaml(path, '{}.{}.yaml'.format(id, tipo), sde, salvar) return id @@ -243,7 +228,7 @@ DUMP_FUNCTIONS = { def get_app(data_fs_path): - storage = ZODB.FileStorage.FileStorage(data_fs_path) + storage = ZODB.FileStorage.FileStorage(data_fs_path, read_only=True) db = ZODB.DB(storage) connection = db.open() root = connection.root() @@ -265,60 +250,79 @@ def find_sapl(app): return sapl -def dump_propriedades(docs, path, encoding='iso-8859-1'): +def dump_propriedades(docs, path, salvar, encoding='iso-8859-1'): props_sapl = br(docs['props_sapl']) ids = [p['id'] for p in props_sapl['_properties']] props = {id: props_sapl[id] for id in ids} props = {id: p.decode(encoding) if isinstance(p, str) else p for id, p in props.items()} - save_as_yaml(path, 'sapl_documentos/propriedades.yaml', props) + save_as_yaml(path, 'sapl_documentos/propriedades.yaml', props, salvar) -def dump_usuarios(sapl, path): +def dump_usuarios(sapl, path, salvar): users = br(br(sapl['acl_users'])['data']) users = {k: br(v) for k, v in users['data'].items()} - save_as_yaml(path, 'usuarios.yaml', users) - - -def grava_nomes_arquivos_exportados(destino): - """Grava nomes dos arquivos exportados (originais -> definitivos) - """ - destino = Path(destino) - - def rel(caminho): - return str(destino.rel_path_to(caminho)) - - with open(destino.child('arquivos_exportados.yaml'), 'w') as arq: - nomes = {rel(k): rel(v) for k, v in nomes_arquivos_exportados.items()} - pyaml.dump(nomes, arq) + save_as_yaml(path, 'usuarios.yaml', users, salvar) -def _dump_sapl(data_fs_path, destino='../../../../media'): +def _dump_sapl(data_fs_path, destino, salvar): assert Path(data_fs_path).exists() app, close_db = get_app(data_fs_path) - nomes_arquivos_exportados.clear() # apaga nomes dos arquivos migrados try: sapl = find_sapl(app) # extrai folhas XSLT - dump_folder(br(sapl['XSLT']), destino) + dump_folder(br(sapl['XSLT']), destino, salvar) # extrai usuários com suas senhas e perfis - dump_usuarios(sapl, destino) + dump_usuarios(sapl, destino, salvar) # extrai documentos docs = br(sapl['sapl_documentos']) with logando_nao_identificados(): - dump_folder(docs, destino) - dump_propriedades(docs, destino) + dump_folder(docs, destino, salvar) + dump_propriedades(docs, destino, salvar) finally: close_db() - grava_nomes_arquivos_exportados(destino) DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() -def repo_execute(repo, cmd): - return repo.git.execute(cmd.split()) +def repo_execute(repo, cmd, *args): + return repo.git.execute(cmd.split() + list(args)) + + +def get_annex_hashes(repo): + hashes = repo_execute( + repo, 'git annex find', '--format=${keyname}\n', '--include=*') + return {os.path.splitext(h)[0] for h in hashes.splitlines()} + + +def ajusta_extensao(fullname, conteudo): + base, extensao = os.path.splitext(fullname) + if extensao not in ['.xsl', '.xslt', '.yaml']: + # não trocamos as extensões XSL, XSLT e YAML + extensao = guess_extension(fullname, conteudo) + return base + extensao + + +def build_salvar(repo): + """Constroi função salvar que pula arquivos que já estão no annex + """ + hashes = get_annex_hashes(repo) + + def salvar(fullname, conteudo): + sha = hashlib.sha256() + sha.update(conteudo) + if sha.hexdigest() not in hashes: + fullname = ajusta_extensao(fullname, conteudo) + if os.path.exists(fullname): + # destrava arquivo pré-existente (o conteúdo mudou) + repo_execute(repo, 'git annex unlock', fullname) + with open(fullname, 'w') as arq: + arq.write(conteudo) + print(fullname) + + return salvar def dump_sapl(sigla): @@ -329,9 +333,13 @@ def dump_sapl(sigla): destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado) destino.mkdir(parents=True) repo = git.Repo.init(destino) - _dump_sapl(data_fs_path, destino) - # grava mundaças repo_execute(repo, 'git annex init') + repo_execute(repo, 'git config annex.thin true') + + salvar = build_salvar(repo) + _dump_sapl(data_fs_path, destino, salvar) + + # grava mundaças repo_execute(repo, 'git annex add sapl_documentos') repo.git.add(A=True) if 'master' not in repo.heads or repo.index.diff('HEAD'):