Browse Source

Migra usando repo git para marcos

pull/1916/head
Marcio Mazza 7 years ago
parent
commit
31cd0c83d0
  1. 1
      requirements/migration-requirements.txt
  2. 7
      sapl/legacy/migracao.py
  3. 25
      sapl/legacy/migracao_dados.py
  4. 81
      sapl/legacy/migracao_documentos.py
  5. 8
      sapl/legacy/migracao_usuarios.py

1
requirements/migration-requirements.txt

@ -1,3 +1,4 @@
-r dev-requirements.txt -r dev-requirements.txt
GitPython
mysqlclient==1.3.12 mysqlclient==1.3.12
pyaml pyaml

7
sapl/legacy/migracao.py

@ -3,15 +3,16 @@ import tarfile
from django.conf import settings from django.conf import settings
from sapl.legacy.migracao_dados import migrar_dados from sapl.legacy.migracao_dados import REPO, gravar_marco, migrar_dados
from sapl.legacy.migracao_documentos import migrar_documentos from sapl.legacy.migracao_documentos import migrar_documentos
from sapl.legacy.migracao_usuarios import migrar_usuarios from sapl.legacy.migracao_usuarios import migrar_usuarios
def migrar(interativo=False): def migrar(interativo=False):
migrar_dados(interativo=interativo) migrar_dados(interativo=interativo)
migrar_usuarios() migrar_usuarios(REPO.working_dir)
migrar_documentos() migrar_documentos(REPO)
gravar_marco()
def gerar_pacote(): def gerar_pacote():

25
sapl/legacy/migracao_dados.py

@ -8,6 +8,7 @@ from itertools import groupby
from operator import xor from operator import xor
from subprocess import PIPE, call from subprocess import PIPE, call
import git
import pkg_resources import pkg_resources
import pyaml import pyaml
import pytz import pytz
@ -1256,30 +1257,44 @@ AJUSTE_DEPOIS_SALVAR = {
TIME_FORMAT = '%H:%M:%S' TIME_FORMAT = '%H:%M:%S'
# permite a gravação de tempos puros pelo pretty-yaml
def time_representer(dumper, data): def time_representer(dumper, data):
return dumper.represent_scalar('!time', data.strftime(TIME_FORMAT)) return dumper.represent_scalar('!time', data.strftime(TIME_FORMAT))
UnsafePrettyYAMLDumper.add_representer(datetime.time, time_representer) UnsafePrettyYAMLDumper.add_representer(datetime.time, time_representer)
# permite a leitura de tempos puros pelo pyyaml (no padrão gravado acima)
def time_constructor(loader, node): def time_constructor(loader, node):
value = loader.construct_scalar(node) value = loader.construct_scalar(node)
return datetime.datetime.strptime(value, TIME_FORMAT).time() return datetime.datetime.strptime(value, TIME_FORMAT).time()
yaml.add_constructor(u'!time', time_constructor) yaml.add_constructor(u'!time', time_constructor)
DIR_MARCO = Path(DIR_DADOS_MIGRACAO, 'marcos', nome_banco_legado) REPO = git.Repo.init(Path(DIR_DADOS_MIGRACAO, 'repos', nome_banco_legado))
def grava_marco_base(): def gravar_marco():
"""Grava um dump de todos os dados como arquivos yaml no repo de marco
"""
# prepara ou localiza repositorio
dir_dados = Path(REPO.working_dir, 'dados')
# exporta dados como arquivos yaml
user_model = get_user_model() user_model = get_user_model()
models = get_models_a_migrar() + [ models = get_models_a_migrar() + [
Composicao, user_model, Group, ContentType] Composicao, user_model, Group, ContentType]
for model in models: for model in models:
info('Gravando marco de [{}]'.format(model.__name__)) info('Gravando marco de [{}]'.format(model.__name__))
dir_model = Path( dir_model = dir_dados.child(model._meta.app_label, model.__name__)
DIR_MARCO, 'dados', model._meta.app_label, model.__name__)
dir_model.mkdir(parents=True) dir_model.mkdir(parents=True)
for data in model.objects.all().values(): for data in model.objects.all().values():
nome_arq = Path(dir_model, data['id']) nome_arq = Path(dir_model, '{}.yaml'.format(data['id']))
with open(nome_arq, 'w') as arq: with open(nome_arq, 'w') as arq:
pyaml.dump(data, arq) pyaml.dump(data, arq)
# salva mudanças
REPO.git.add([dir_dados.name])
if 'master' not in REPO.heads or REPO.index.diff('HEAD'):
# se de fato existe mudança
REPO.index.commit('Grava marco')
REPO.git.execute('git tag marco'.split())

81
sapl/legacy/migracao_documentos.py

@ -1,6 +1,7 @@
import os import os
import re import re
from glob import glob from glob import glob
from os.path import join
import yaml import yaml
from django.db import transaction from django.db import transaction
@ -14,7 +15,6 @@ from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo, from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo,
DocumentoAdministrativo) DocumentoAdministrativo)
from sapl.sessao.models import SessaoPlenaria from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MEDIA_ROOT
# MIGRAÇÃO DE DOCUMENTOS ################################################### # MIGRAÇÃO DE DOCUMENTOS ###################################################
@ -34,25 +34,41 @@ DOCS = {
DocumentoAcessorioAdministrativo: [('arquivo', 'administrativo/{}')], DocumentoAcessorioAdministrativo: [('arquivo', 'administrativo/{}')],
} }
DOCS = {model: [(campo, os.path.join('sapl_documentos', origem)) DOCS = {model: [(campo, join('sapl_documentos', origem))
for campo, origem, in campos] for campo, origem, in campos]
for model, campos in DOCS.items()} for model, campos in DOCS.items()}
def em_media(caminho): def mover_documento(repo, origem, destino):
return os.path.join(MEDIA_ROOT, caminho) origem, destino = [join(repo.working_dir, c) if not os.path.isabs(c) else c
def mover_documento(origem, destino):
origem, destino = [em_media(c) if not os.path.isabs(c) else c
for c in (origem, destino)] for c in (origem, destino)]
os.makedirs(os.path.dirname(destino), exist_ok=True) os.makedirs(os.path.dirname(destino), exist_ok=True)
os.rename(origem, destino) repo.git.mv(origem, destino)
# conserta link do git annex (antes do commit)
# em geral é o mais seguro a fazer,
# mas foi especificamente necessário pois o conteúdo das imagens
# é acessado antes do commit pelo cropping de imagem
repo.git.execute('git annex fix'.split() + [destino])
def migrar_propriedades_da_casa(): def migrar_logotipo(repo, casa, propriedades):
print('.... Migrando logotipo da casa ....')
[(campo, origem)] = DOCS[CasaLegislativa]
# a extensão do logo pode ter sido ajustada pelo tipo real do arquivo
nome_nas_propriedades = os.path.splitext(propriedades['id_logo'])[0]
arquivos = glob(join(repo.working_dir, origem.format(nome_nas_propriedades)))
if arquivos:
assert len(arquivos) == 1, 'Há mais de um logotipo para a casa'
[logo] = arquivos
destino = join(CasaLegislativa._meta.get_field(campo).upload_to,
os.path.basename(logo))
mover_documento(repo, logo, destino)
casa.logotipo = destino
def migrar_propriedades_da_casa(repo):
print('#### Migrando propriedades da casa ####') print('#### Migrando propriedades da casa ####')
caminho = em_media('sapl_documentos/propriedades.yaml') caminho = join(repo.working_dir, 'sapl_documentos/propriedades.yaml')
with open(caminho, 'r') as arquivo: with open(caminho, 'r') as arquivo:
propriedades = yaml.safe_load(arquivo) propriedades = yaml.safe_load(arquivo)
casa = CasaLegislativa.objects.first() casa = CasaLegislativa.objects.first()
@ -72,31 +88,24 @@ def migrar_propriedades_da_casa():
for campo, prop in campos_para_propriedades: for campo, prop in campos_para_propriedades:
setattr(casa, campo, propriedades[prop]) setattr(casa, campo, propriedades[prop])
# Localidade # localidade
sql_localidade = ''' sql_localidade = '''
select nom_localidade, sgl_uf from localidade select nom_localidade, sgl_uf from localidade
where cod_localidade = {}'''.format(propriedades['cod_localidade']) where cod_localidade = {}'''.format(propriedades['cod_localidade'])
[(casa.municipio, casa.uf)] = exec_legado(sql_localidade) [(casa.municipio, casa.uf)] = exec_legado(sql_localidade)
print('.... Migrando logotipo da casa ....') # logotipo
[(campo, origem)] = DOCS[CasaLegislativa] migrar_logotipo(repo, casa, propriedades)
# a extensão do logo pode ter sido ajustada pelo tipo real do arquivo
id_logo = os.path.splitext(propriedades['id_logo'])[0]
[origem] = glob(em_media(origem.format(id_logo)))
destino = os.path.join(
CasaLegislativa._meta.get_field(campo).upload_to,
os.path.basename(origem))
mover_documento(origem, destino)
casa.logotipo = destino
casa.save() casa.save()
os.remove(caminho) repo.git.rm(caminho)
def migrar_docs_por_ids(model): def migrar_docs_por_ids(repo, model):
for campo, base_origem in DOCS[model]: for campo, base_origem in DOCS[model]:
print('#### Migrando {} de {} ####'.format(campo, model.__name__)) print('#### Migrando {} de {} ####'.format(campo, model.__name__))
dir_origem, nome_origem = os.path.split(em_media(base_origem)) dir_origem, nome_origem = os.path.split(join(repo.working_dir, base_origem))
nome_origem = nome_origem.format('(\d+)') nome_origem = nome_origem.format('(\d+)')
pat = re.compile('^{}\.\w+$'.format(nome_origem)) pat = re.compile('^{}\.\w+$'.format(nome_origem))
if not os.path.isdir(dir_origem): if not os.path.isdir(dir_origem):
@ -106,7 +115,7 @@ def migrar_docs_por_ids(model):
matches = [pat.match(arq) for arq in os.listdir(dir_origem)] matches = [pat.match(arq) for arq in os.listdir(dir_origem)]
ids_origens = [(int(m.group(1)), ids_origens = [(int(m.group(1)),
os.path.join(dir_origem, m.group(0))) join(dir_origem, m.group(0)))
for m in matches if m] for m in matches if m]
objetos = {obj.id: obj for obj in model.objects.all()} objetos = {obj.id: obj for obj in model.objects.all()}
upload_to = model._meta.get_field(campo).upload_to upload_to = model._meta.get_field(campo).upload_to
@ -117,7 +126,7 @@ def migrar_docs_por_ids(model):
obj = objetos.get(id) obj = objetos.get(id)
if obj: if obj:
destino = upload_to(obj, os.path.basename(origem)) destino = upload_to(obj, os.path.basename(origem))
mover_documento(origem, destino) mover_documento(repo, origem, destino)
setattr(obj, campo, destino) setattr(obj, campo, destino)
obj.save() obj.save()
else: else:
@ -125,16 +134,15 @@ def migrar_docs_por_ids(model):
print(msg.format(model.__name__, id, origem)) print(msg.format(model.__name__, id, origem))
def migrar_documentos(): def migrar_documentos(repo):
# aqui supomos que uma pasta chamada sapl_documentos está em MEDIA_ROOT # aqui supomos que uma pasta chamada sapl_documentos está em
# com o conteúdo da pasta de mesmo nome do zope # <repo.working_dir> com o conteúdo exportado do zope
# Os arquivos da pasta serão MOVIDOS para a nova estrutura! # Os arquivos da pasta serão (git) MOVIDOS para a nova estrutura!
# A pasta, após conferência do que não foi migrado, deve ser apagada.
# #
# Isto significa que para rodar novamente esta função é preciso # Isto significa que para rodar novamente esta função é preciso
# restaurar a pasta sapl_documentos ao estado inicial # restaurar a pasta sapl_documentos ao estado inicial
migrar_propriedades_da_casa() migrar_propriedades_da_casa(repo)
for model in [ for model in [
Parlamentar, Parlamentar,
@ -146,10 +154,11 @@ def migrar_documentos():
DocumentoAdministrativo, DocumentoAdministrativo,
DocumentoAcessorioAdministrativo, DocumentoAcessorioAdministrativo,
]: ]:
migrar_docs_por_ids(model) migrar_docs_por_ids(repo, model)
sobrando = [os.path.join(dir, file) sobrando = [join(dir, file)
for (dir, _, files) in os.walk(em_media('sapl_documentos')) for (dir, _, files) in os.walk(join(repo.working_dir,
'sapl_documentos'))
for file in files] for file in files]
if sobrando: if sobrando:
print('\n#### Encerrado ####\n\n' print('\n#### Encerrado ####\n\n'

8
sapl/legacy/migracao_usuarios.py

@ -1,8 +1,8 @@
import yaml import yaml
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from unipath import Path
from sapl.hashers import zope_encoded_password_to_django from sapl.hashers import zope_encoded_password_to_django
from sapl.settings import MEDIA_ROOT
PERFIL_LEGADO_PARA_NOVO = {legado: Group.objects.get(name=novo) PERFIL_LEGADO_PARA_NOVO = {legado: Group.objects.get(name=novo)
for legado, novo in [ for legado, novo in [
@ -44,9 +44,9 @@ def decode_nome(nome):
return nome return nome
def migrar_usuarios(): def migrar_usuarios(dir_repo):
""" """
o arquivo media/usuarios.yaml e importa os usuários nele listados, o arquivo <dir_repo>/usuarios.yaml e importa os usuários nele listados,
com senhas e perfis. com senhas e perfis.
Os usuários são criados se necessário e seus perfis ajustados. Os usuários são criados se necessário e seus perfis ajustados.
@ -68,7 +68,7 @@ def migrar_usuarios():
Também podemos assumir que essa é uma tarefa de um administrador Também podemos assumir que essa é uma tarefa de um administrador
""" """
ARQUIVO_USUARIOS = MEDIA_ROOT.child('usuarios.yaml') ARQUIVO_USUARIOS = Path(dir_repo).child('usuarios.yaml')
with open(ARQUIVO_USUARIOS, 'r') as f: with open(ARQUIVO_USUARIOS, 'r') as f:
usuarios = yaml.load(f) usuarios = yaml.load(f)
# conferimos de que só há um nome de usuário # conferimos de que só há um nome de usuário

Loading…
Cancel
Save