Browse Source

Merge branch 'migracao' into 3.1.x

pull/1916/head
Marcio Mazza 7 years ago
parent
commit
b01e6eaa89
  1. 1
      requirements/migration-requirements.txt
  2. 19
      sapl/base/urls.py
  3. 25
      sapl/base/views.py
  4. 24
      sapl/legacy/management/commands/migracao_25_31.py
  5. 35
      sapl/legacy/migracao.py
  6. 85
      sapl/legacy/migracao_dados.py
  7. 92
      sapl/legacy/migracao_documentos.py
  8. 8
      sapl/legacy/migracao_usuarios.py
  9. 81
      sapl/legacy/scripts/exporta_zope/exporta_zope.py
  10. 2
      sapl/legacy/scripts/exporta_zope/requirements.txt
  11. 4
      sapl/legacy/scripts/exporta_zope/variaveis_comuns.py
  12. 21
      sapl/legacy/scripts/migra_um_db.sh
  13. 40
      sapl/legacy/scripts/normaliza_dump_mysql.py
  14. 28
      sapl/legacy/scripts/normaliza_dump_mysql.sh
  15. 8
      sapl/legacy_migration_settings.py
  16. 5
      sapl/urls.py

1
requirements/migration-requirements.txt

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

19
sapl/base/urls.py

@ -1,20 +1,22 @@
import os
from django.conf.urls import include, url
from django.contrib.auth import views
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.views import (password_reset, password_reset_complete,
password_reset_confirm,
password_reset_done)
from django.views.generic.base import TemplateView
from django.views.generic.base import RedirectView, TemplateView
from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud
from sapl.settings import EMAIL_SEND_USER
from sapl.settings import EMAIL_SEND_USER, MEDIA_URL
from .apps import AppConfig
from .forms import LoginForm, NovaSenhaForm, RecuperarSenhaForm
from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
CreateUsuarioView, DeleteUsuarioView, EditUsuarioView,
HelpTopicView, ListarUsuarioView, RelatorioAtasView,
RelatorioDataFimPrazoTramitacaoView,
HelpTopicView, ListarUsuarioView, LogotipoView,
RelatorioAtasView, RelatorioDataFimPrazoTramitacaoView,
RelatorioHistoricoTramitacaoView,
RelatorioMateriasPorAnoAutorTipoView,
RelatorioMateriasPorAutorView,
@ -120,4 +122,13 @@ urlpatterns = [
url(r'^sistema/search/', SaplSearchView(), name='haystack_search'),
# Folhas XSLT e extras referenciadas por documentos migrados do sapl 2.5
url(r'^sapl/XSLT/HTML/(?P<path>.*)$', RedirectView.as_view(
url=os.path.join(MEDIA_URL, 'sapl/public/XSLT/HTML/%(path)s'),
permanent=False)),
# url do logotipo usada em documentos migrados do sapl 2.5
url(r'^sapl/sapl_documentos/props_sapl/logo_casa',
LogotipoView.as_view(), name='logotipo'),
] + recuperar_senha + alterar_senha + admin_user

25
sapl/base/views.py

@ -1,5 +1,6 @@
from django.conf import settings
from django.contrib.auth import get_user_model, update_session_auth_hash
import os
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import Group
from django.contrib.auth.tokens import default_token_generator
@ -12,14 +13,15 @@ from django.template import TemplateDoesNotExist
from django.template.loader import get_template
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (CreateView, DeleteView, DetailView, FormView,
ListView, UpdateView)
from django.views.generic.base import TemplateView
from django.utils.translation import string_concat
from django.views.generic import (CreateView, DeleteView, FormView, ListView,
UpdateView)
from django.views.generic.base import RedirectView, TemplateView
from django_filters.views import FilterView
from haystack.views import SearchView
from sapl import settings
from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm
from sapl.base.models import Autor, TipoAutor
from sapl.crud.base import CrudAux, make_pagination
@ -759,3 +761,14 @@ class AlterarSenha(FormView):
user.save()
return super().form_valid(form)
STATIC_LOGO = os.path.join(settings.STATIC_URL, 'img/logo.png')
class LogotipoView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
casa = get_casalegislativa()
logo = casa and casa.logotipo and casa.logotipo.name
return os.path.join(settings.MEDIA_URL, logo) if logo else STATIC_LOGO

24
sapl/legacy/management/commands/migracao_25_31.py

@ -1,33 +1,13 @@
from django.core import management
from django.core.management.base import BaseCommand
from sapl.legacy.migracao import migrar, migrar_dados
from sapl.legacy.migracao import migrar
class Command(BaseCommand):
help = 'Migração de dados do SAPL 2.5 para o SAPL 3.1'
def add_arguments(self, parser):
parser.add_argument(
'--force',
action='store_true',
default=False,
dest='force',
help='Não interativa: pula confirmação de exclusão dos dados',
)
parser.add_argument(
'--dados',
action='store_true',
default=False,
dest='dados',
help='migra somente dados',
)
def handle(self, *args, **options):
management.call_command('migrate')
somente_dados, interativo = options['dados'], not options['force']
if somente_dados:
migrar_dados(interativo=interativo)
else:
migrar(interativo=interativo)
migrar(interativo=False)

35
sapl/legacy/migracao.py

@ -1,36 +1,45 @@
import subprocess
import tarfile
from django.conf import settings
from sapl.legacy.migracao_dados import migrar_dados
from sapl.legacy.migracao_dados import (REPO, TAG_MARCO, gravar_marco, info,
migrar_dados)
from sapl.legacy.migracao_documentos import migrar_documentos
from sapl.legacy.migracao_usuarios import migrar_usuarios
from sapl.legacy.scripts.exporta_zope.variaveis_comuns import TAG_ZOPE
from sapl.legacy_migration_settings import DIR_REPO, NOME_BANCO_LEGADO
def adornar_msg(msg):
return '\n{1}\n{0}\n{1}'.format(msg, '#' * len(msg))
def migrar(interativo=False):
if TAG_MARCO in REPO.tags:
info('A migração já está feita.')
return
assert TAG_ZOPE in REPO.tags, adornar_msg(
'Antes de migrar '
'é necessário fazer a exportação de documentos do zope')
migrar_dados(interativo=interativo)
migrar_usuarios()
migrar_documentos()
migrar_usuarios(REPO.working_dir)
migrar_documentos(REPO)
gravar_marco()
gerar_pacote()
def gerar_pacote():
banco = settings.DATABASES['legacy']['NAME']
# backup do banco
print('Gerando backup do banco... ', end='', flush=True)
arq_backup = settings.MEDIA_ROOT.child('{}.backup'.format(banco))
arq_backup = DIR_REPO.child('{}.backup'.format(NOME_BANCO_LEGADO))
backup_cmd = '''
pg_dump --host localhost --port 5432 --username postgres --no-password
--format custom --blobs --verbose --file {} {}'''.format(
arq_backup, banco)
arq_backup, NOME_BANCO_LEGADO)
subprocess.check_output(backup_cmd.split(), stderr=subprocess.DEVNULL)
print('SUCESSO')
# tar de media/sapl
print('Criando tar de media... ', end='', flush=True)
tar_media = settings.MEDIA_ROOT.child('{}.media.tgz'.format(banco))
dir_media = settings.MEDIA_ROOT.child('sapl')
with tarfile.open(tar_media, "w:gz") as tar:
tar.add(dir_media, arcname=dir_media.name)
arq_tar = DIR_REPO.child('{}.media.tar'.format(NOME_BANCO_LEGADO))
subprocess.check_output(['tar', 'cfh', arq_tar, '-C', DIR_REPO, 'sapl'])
print('SUCESSO')

85
sapl/legacy/migracao_dados.py

@ -1,4 +1,5 @@
import datetime
import os
import re
import traceback
from collections import OrderedDict, defaultdict, namedtuple
@ -8,6 +9,7 @@ from itertools import groupby
from operator import xor
from subprocess import PIPE, call
import git
import pkg_resources
import pyaml
import pytz
@ -26,8 +28,12 @@ from unipath import Path
from sapl.base.models import AppConfig as AppConf
from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor
from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.legacy import scripts
from sapl.legacy.models import NormaJuridica as OldNormaJuridica
from sapl.legacy.models import TipoNumeracaoProtocolo
from sapl.legacy_migration_settings import (DATABASES, DIR_DADOS_MIGRACAO,
DIR_REPO, NOME_BANCO_LEGADO,
PROJECT_DIR)
from sapl.materia.models import (AcompanhamentoMateria, MateriaLegislativa,
Proposicao, StatusTramitacao, TipoDocumento,
TipoMateriaLegislativa, TipoProposicao,
@ -40,9 +46,9 @@ from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
StatusTramitacaoAdministrativo)
from sapl.sessao.models import (ExpedienteMateria, OrdemDia, RegistroVotacao,
TipoResultadoVotacao)
from sapl.settings import DATABASES, PROJECT_DIR
from sapl.utils import normalize
from .scripts.normaliza_dump_mysql import normaliza_dump_mysql
from .timezonesbrasil import get_timezone
# BASE ######################################################################
@ -139,6 +145,7 @@ for nome_novo, nome_antigo in (('comissao', 'cod_comissao'),
class CampoVirtual(namedtuple('CampoVirtual', 'model related_model')):
null = True
CAMPOS_VIRTUAIS_PROPOSICAO = {
TipoMateriaLegislativa: CampoVirtual(Proposicao, MateriaLegislativa),
TipoDocumento: CampoVirtual(Proposicao, DocumentoAdministrativo)
@ -171,6 +178,7 @@ for related, campo_antigo in [(Parlamentar, 'cod_parlamentar'),
def info(msg):
print('INFO: ' + msg)
ocorrencias = defaultdict(list)
@ -717,31 +725,26 @@ def fill_dados_basicos():
appconf.save()
def get_last_pk(model):
last_value = model.objects.all().aggregate(Max('pk'))
return last_value['pk__max'] or 0
def reinicia_sequence(model, id):
sequence_name = '%s_id_seq' % model._meta.db_table
exec_sql('ALTER SEQUENCE %s RESTART WITH %s MINVALUE -1;' % (
sequence_name, id))
DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand()
PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml')
DIR_RESULTADOS = DIR_DADOS_MIGRACAO.child('resultados')
REPO = git.Repo.init(DIR_REPO)
def dict_representer(dumper, data):
return dumper.represent_dict(data.items())
yaml.add_representer(OrderedDict, dict_representer)
# configura timezone de migração
nome_banco_legado = DATABASES['legacy']['NAME']
match = re.match('sapl_cm_(.*)', nome_banco_legado)
match = re.match('sapl_cm_(.*)', NOME_BANCO_LEGADO)
sigla_casa = match.group(1)
PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml')
with open(PATH_TABELA_TIMEZONES, 'r') as arq:
tabela_timezones = yaml.load(arq)
municipio, uf, nome_timezone = tabela_timezones[sigla_casa]
@ -784,7 +787,21 @@ def populate_renamed_fields(new, old):
setattr(new, field.name, value)
def roda_comando_shell(cmd):
res = os.system(cmd)
assert res == 0, 'O comando falhou: {}'.format(cmd)
def migrar_dados(interativo=True):
# restaura dump
arq_dump = Path(DIR_DADOS_MIGRACAO.child(
'dumps_mysql', '{}.sql'.format(NOME_BANCO_LEGADO)))
assert arq_dump.exists(), 'Dump do mysql faltando: {}'.format(arq_dump)
info('Restaurando dump mysql de [{}]'.format(arq_dump))
normaliza_dump_mysql(arq_dump)
roda_comando_shell('mysql -uroot < {}'.format(arq_dump))
# executa ajustes pré-migração, se existirem
arq_ajustes_pre_migracao = DIR_DADOS_MIGRACAO.child(
'ajustes_pre_migracao', '{}.sql'.format(sigla_casa))
@ -817,18 +834,16 @@ def migrar_dados(interativo=True):
info('Começando migração: ...')
try:
ocorrencias.clear()
dir_ocorrencias = DIR_RESULTADOS.child(date.today().isoformat())
dir_ocorrencias.mkdir(parents=True)
migrar_todos_os_models()
except Exception as e:
ocorrencias['traceback'] = str(traceback.format_exc())
raise e
finally:
# grava ocorrências
arq_ocorrencias = dir_ocorrencias.child(
nome_banco_legado + '.yaml')
arq_ocorrencias = Path(REPO.working_dir, 'ocorrencias.yaml')
with open(arq_ocorrencias, 'w') as arq:
pyaml.dump(ocorrencias, arq, vspacing=1)
REPO.git.add([arq_ocorrencias.name])
info('Ocorrências salvas em\n {}'.format(arq_ocorrencias))
# recria tipos de autor padrão que não foram criados pela migração
@ -883,10 +898,14 @@ def migrar_model(model):
def get_id_do_legado(old):
return getattr(old, nome_pk)
ultima_pk_legado = model_legado.objects.all().aggregate(
Max('pk'))['pk__max'] or 0
else:
# a pk no legado tem mais de um campo
old_records = iter_sql_records(tabela_legado)
get_id_do_legado = None
ultima_pk_legado = model_legado.objects.count()
ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model)
ajuste_depois_salvar = AJUSTE_DEPOIS_SALVAR.get(model)
@ -929,10 +948,13 @@ def migrar_model(model):
if ajuste_depois_salvar:
ajuste_depois_salvar()
# se configuramos ids explicitamente devemos reiniciar a sequence
# reiniciamos a sequence logo após a última pk do legado
#
# É importante que seja do legado (e não da nova base),
# pois numa nova versão da migração podemos inserir registros
# não migrados antes sem conflito com pks criadas até lá
if get_id_do_legado:
last_pk = get_last_pk(model)
reinicia_sequence(model, last_pk + 1)
reinicia_sequence(model, ultima_pk_legado + 1)
# apaga registros migrados do legado
if sql_delete_legado:
@ -1256,30 +1278,47 @@ AJUSTE_DEPOIS_SALVAR = {
TIME_FORMAT = '%H:%M:%S'
# permite a gravação de tempos puros pelo pretty-yaml
def time_representer(dumper, data):
return dumper.represent_scalar('!time', data.strftime(TIME_FORMAT))
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):
value = loader.construct_scalar(node)
return datetime.datetime.strptime(value, TIME_FORMAT).time()
yaml.add_constructor(u'!time', time_constructor)
TAG_MARCO = 'marco'
DIR_MARCO = Path(DIR_DADOS_MIGRACAO, 'marcos', nome_banco_legado)
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')
def grava_marco_base():
# exporta dados como arquivos yaml
user_model = get_user_model()
models = get_models_a_migrar() + [
Composicao, user_model, Group, ContentType]
for model in models:
info('Gravando marco de [{}]'.format(model.__name__))
dir_model = Path(
DIR_MARCO, 'dados', model._meta.app_label, model.__name__)
dir_model = dir_dados.child(model._meta.app_label, model.__name__)
dir_model.mkdir(parents=True)
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:
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 -f'.split() + [TAG_MARCO])

92
sapl/legacy/migracao_documentos.py

@ -1,9 +1,11 @@
import os
import re
from glob import glob
from os.path import join
import yaml
from django.db import transaction
from image_cropping.fields import ImageCropField
from sapl.base.models import CasaLegislativa
from sapl.legacy.migracao_dados import exec_legado
@ -14,7 +16,6 @@ from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo,
DocumentoAdministrativo)
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MEDIA_ROOT
# MIGRAÇÃO DE DOCUMENTOS ###################################################
@ -34,25 +35,37 @@ DOCS = {
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 model, campos in DOCS.items()}
def em_media(caminho):
return os.path.join(MEDIA_ROOT, caminho)
def mover_documento(origem, destino):
origem, destino = [em_media(c) if not os.path.isabs(c) else c
def mover_documento(repo, origem, destino):
origem, destino = [join(repo.working_dir, c) if not os.path.isabs(c) else c
for c in (origem, destino)]
os.makedirs(os.path.dirname(destino), exist_ok=True)
os.rename(origem, destino)
repo.git.mv(origem, 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 ####')
caminho = em_media('sapl_documentos/propriedades.yaml')
caminho = join(repo.working_dir, 'sapl_documentos/propriedades.yaml')
repo.git.execute('git annex get'.split() + [caminho])
with open(caminho, 'r') as arquivo:
propriedades = yaml.safe_load(arquivo)
casa = CasaLegislativa.objects.first()
@ -72,31 +85,25 @@ def migrar_propriedades_da_casa():
for campo, prop in campos_para_propriedades:
setattr(casa, campo, propriedades[prop])
# Localidade
# localidade
sql_localidade = '''
select nom_localidade, sgl_uf from localidade
where cod_localidade = {}'''.format(propriedades['cod_localidade'])
[(casa.municipio, casa.uf)] = exec_legado(sql_localidade)
print('.... Migrando logotipo da casa ....')
[(campo, origem)] = DOCS[CasaLegislativa]
# 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
# logotipo
migrar_logotipo(repo, casa, propriedades)
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]:
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+)')
pat = re.compile('^{}\.\w+$'.format(nome_origem))
if not os.path.isdir(dir_origem):
@ -106,10 +113,11 @@ def migrar_docs_por_ids(model):
matches = [pat.match(arq) for arq in os.listdir(dir_origem)]
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]
objetos = {obj.id: obj for obj in model.objects.all()}
upload_to = model._meta.get_field(campo).upload_to
tem_cropping = isinstance(model._meta.get_field(campo), ImageCropField)
with transaction.atomic():
for id, origem in ids_origens:
@ -117,24 +125,33 @@ def migrar_docs_por_ids(model):
obj = objetos.get(id)
if obj:
destino = upload_to(obj, os.path.basename(origem))
mover_documento(origem, destino)
mover_documento(repo, origem, destino)
setattr(obj, campo, destino)
if tem_cropping:
# conserta link do git annex (antes do commit)
# pois o conteúdo das imagens é acessado pelo cropping
repo.git.execute('git annex fix'.split() + [destino])
obj.save()
else:
msg = ' {} (pk={}) não encontrado para documento em [{}]'
print(msg.format(model.__name__, id, origem))
def migrar_documentos():
# aqui supomos que uma pasta chamada sapl_documentos está em MEDIA_ROOT
# com o conteúdo da pasta de mesmo nome do zope
# Os arquivos da pasta serão MOVIDOS para a nova estrutura!
# A pasta, após conferência do que não foi migrado, deve ser apagada.
def migrar_documentos(repo):
# aqui supomos que as pastas XSLT e sapl_documentos estão em
# <repo.working_dir> com o conteúdo exportado do zope
# Os arquivos das pastas serão (git) MOVIDOS para a nova estrutura!
#
# Isto significa que para rodar novamente esta função é preciso
# restaurar a pasta sapl_documentos ao estado inicial
# restaurar o repo ao estado anterior
mover_documento(repo, 'XSLT', 'sapl/public/XSLT')
migrar_propriedades_da_casa(repo)
migrar_propriedades_da_casa()
# garante que o conteúdo das fotos dos parlamentares esteja presente
# (necessário para o cropping de imagem)
repo.git.execute('git annex get sapl_documentos/parlamentar'.split())
for model in [
Parlamentar,
@ -146,10 +163,11 @@ def migrar_documentos():
DocumentoAdministrativo,
DocumentoAcessorioAdministrativo,
]:
migrar_docs_por_ids(model)
migrar_docs_por_ids(repo, model)
sobrando = [os.path.join(dir, file)
for (dir, _, files) in os.walk(em_media('sapl_documentos'))
sobrando = [join(dir, file)
for (dir, _, files) in os.walk(join(repo.working_dir,
'sapl_documentos'))
for file in files]
if sobrando:
print('\n#### Encerrado ####\n\n'

8
sapl/legacy/migracao_usuarios.py

@ -1,8 +1,8 @@
import yaml
from django.contrib.auth.models import Group, User
from unipath import Path
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)
for legado, novo in [
@ -44,9 +44,9 @@ def decode_nome(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.
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
"""
ARQUIVO_USUARIOS = MEDIA_ROOT.child('usuarios.yaml')
ARQUIVO_USUARIOS = Path(dir_repo).child('usuarios.yaml')
with open(ARQUIVO_USUARIOS, 'r') as f:
usuarios = yaml.load(f)
# conferimos de que só há um nome de usuário

81
sapl/legacy/scripts/exporta_zope/exporta_zope.py

@ -16,23 +16,30 @@ from functools import partial
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
from variaveis_comuns import DIR_DADOS_MIGRACAO, TAG_ZOPE
EXTENSOES = {
'application/msword': '.doc',
'application/pdf': '.pdf',
'application/vnd.oasis.opendocument.text': '.odt',
'application/vnd.ms-excel': '.xls',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa
'application/vnd.oasis.opendocument.text-template': '.ott',
'application/vnd.ms-powerpoint': '.ppt',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx', # noqa
'application/vnd.oasis.opendocument.spreadsheet': '.ods',
'application/xml': '.xml',
'text/xml': '.xml',
'application/zip': '.zip',
'application/x-rar': '.rar',
'image/jpeg': '.jpeg',
'image/png': '.png',
'image/gif': '.gif',
@ -46,7 +53,9 @@ EXTENSOES = {
'audio/x-wav': '.wav',
'video/mp4': '.mp4',
'image/x-icon': '.ico',
'application/vnd.oasis.opendocument.text-template': '.ott',
'image/x-ms-bmp': '.bmp',
'video/x-ms-asf': '.asf',
'audio/mpeg': '.mp3',
# TODO rever...
'text/richtext': '.rtf',
@ -54,7 +63,9 @@ EXTENSOES = {
# sem extensao
'application/octet-stream': '', # binário
'inode/x-empty': '', # vazio
'text/x-unknown-content-type': '',
'application/x-empty': '', # vazio
'text/x-unknown-content-type': '', # desconhecido
'application/CDFV2-unknown': '', # desconhecido
}
@ -83,10 +94,7 @@ def guess_extension(fullname, buffer):
raise Exception(msg, e)
def dump_file(doc, path, salvar):
name = doc['__name__']
fullname = os.path.join(path, name)
def get_conteudo_file(doc):
# A partir daqui usamos dict.pop('...') nos __Broken_state__
# para contornar um "vazamento" de memória que ocorre
# ao percorrer a árvore de objetos
@ -107,10 +115,24 @@ def dump_file(doc, path, salvar):
while pdata:
output.write(pdata.pop('data'))
pdata = br(pdata.pop('next', None))
salvar(fullname, output.getvalue())
return output.getvalue()
def dump_file(doc, path, salvar, get_conteudo=get_conteudo_file):
name = doc['__name__']
fullname = os.path.join(path, name)
conteudo = get_conteudo(doc)
if conteudo:
# pula arquivos vazios
salvar(fullname, conteudo)
return name
def get_conteudo_dtml_method(doc):
return doc['raw']
def enumerate_by_key_list(folder, key_list, type_key):
for entry in folder.get(key_list, []):
id, meta_type = entry['id'], entry[type_key]
@ -145,8 +167,8 @@ def logando_nao_identificados():
if nao_identificados:
print('#' * 80)
print('#' * 80)
print(u'FORAM ENCONTRADOS ARQUIVOS DE FORMATO NÃO IDENTIFICADO!!!')
print(u'REFAÇA A EXPORTAÇÃO\n')
print('FORAM ENCONTRADOS ARQUIVOS DE FORMATO NÃO IDENTIFICADO!!!')
print('REFAÇA A EXPORTAÇÃO\n')
print(nao_identificados)
print('#' * 80)
print('#' * 80)
@ -214,6 +236,8 @@ def dump_sde(strdoc, path, salvar, tipo):
DUMP_FUNCTIONS = {
'File': dump_file,
'Image': dump_file,
'DTML Method': partial(dump_file,
get_conteudo=get_conteudo_dtml_method),
'Folder': partial(dump_folder, enum=enumerate_folder),
'BTreeFolder2': partial(dump_folder, enum=enumerate_btree),
'SDE-Document': partial(dump_sde, tipo='sde.document'),
@ -284,9 +308,6 @@ def _dump_sapl(data_fs_path, destino, salvar):
close_db()
DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand()
def repo_execute(repo, cmd, *args):
return repo.git.execute(cmd.split() + list(args))
@ -299,8 +320,7 @@ def get_annex_hashes(repo):
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
if extensao not in ['.xsl', '.xslt', '.yaml', '.css']:
extensao = guess_extension(fullname, conteudo)
return base + extensao
@ -326,6 +346,7 @@ def build_salvar(repo):
def dump_sapl(sigla):
sigla = sigla[-3:] # ignora prefixo (por ex. 'sapl_cm_')
data_fs_path = DIR_DADOS_MIGRACAO.child('datafs',
'Data_cm_{}.fs'.format(sigla))
assert data_fs_path.exists(), 'Origem não existe: {}'.format(data_fs_path)
@ -333,18 +354,28 @@ def dump_sapl(sigla):
destino = DIR_DADOS_MIGRACAO.child('repos', nome_banco_legado)
destino.mkdir(parents=True)
repo = git.Repo.init(destino)
if TAG_ZOPE in repo.tags:
info('A exportação de documentos já está feita.')
return
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'):
# se de fato existe mudança
repo.index.commit('Exporta documentos do zope')
try:
finalizado = False
_dump_sapl(data_fs_path, destino, salvar)
finalizado = True
finally:
# 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'):
# se de fato existe mudança
status = 'completa' if finalizado else 'parcial'
repo.index.commit(u'Exportação do zope {}'.format(status))
if finalizado:
repo.git.execute('git tag -f'.split() + [TAG_ZOPE])
if __name__ == "__main__":

2
sapl/legacy/scripts/exporta_zope/requirements.txt

@ -4,3 +4,5 @@ PyYAML
Unipath
GitPython
pyaml
python-magic
ipython

4
sapl/legacy/scripts/exporta_zope/variaveis_comuns.py

@ -0,0 +1,4 @@
from unipath import Path
DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand()
TAG_ZOPE = 'zope'

21
sapl/legacy/scripts/migra_um_db.sh

@ -1,10 +1,7 @@
#!/bin/bash
# rodar esse script na raiz do projeto
if [ $# -ge 2 ]; then
# proteje pasta com dumps de alterações acidentais
# chmod -R -w ~/migracao_sapl/sapl_dumps
if [ $# -eq 1 ]; then
DIR_MIGRACAO=~/migracao_sapl
@ -20,23 +17,11 @@ if [ $# -ge 2 ]; then
echo "########################################" | tee -a $LOG
echo >> $LOG
if [ $3 ]; then
# se há senha do mysql
mysql -u$2 -p"$3" -N -s -e "DROP DATABASE IF EXISTS $1; CREATE DATABASE $1;"
mysql -u$2 -p"$3" < $DIR_MIGRACAO/dumps_mysql/$1.sql
else
# se não há senha do mysql
mysql -u$2 -N -s -e "DROP DATABASE IF EXISTS $1; CREATE DATABASE $1;"
mysql -u$2 < $DIR_MIGRACAO/dumps_mysql/$1.sql
fi;
echo "O banco legado foi restaurado" |& tee -a $LOG
echo >> $LOG
echo "--- MIGRACAO ---" | tee -a $LOG
echo >> $LOG
DATABASE_NAME=$1 ./manage.py migracao_25_31 --force --dados --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG
DATABASE_NAME=$1 ./manage.py migracao_25_31 --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG
echo >> $LOG
else
echo "USO:"
echo " $0 <nome_database> <usuário mysql> [senha mysql]"
echo " $0 <nome_database>"
fi;

40
sapl/legacy/scripts/normaliza_dump_mysql.py

@ -0,0 +1,40 @@
#!/usr/bin/env python
import re
import sys
from unipath import Path
cabecalho = '''
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*!40000 DROP DATABASE IF EXISTS `{banco}`*/;
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{banco}` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `{banco}`;
'''
def normaliza_dump_mysql(nome_arquivo):
arquivo = Path(nome_arquivo).expand()
banco = arquivo.stem
conteudo = arquivo.read_file()
inicio = re.finditer('--\n-- Table structure for table .*\n--\n', conteudo)
inicio = next(inicio).start()
conteudo = cabecalho.format(banco=banco) + conteudo[inicio:]
arquivo.write_file(conteudo)
if __name__ == "__main__":
nome_aquivo = sys.argv[1]
normaliza_dump_mysql(nome_aquivo)

28
sapl/legacy/scripts/normaliza_dump_mysql.sh

@ -1,28 +0,0 @@
#!/bin/bash
ARQUIVO=$1
BANCO=`basename $1 | cut -f1 -d.`
TMP=__tmp.sql
cat << EOF > $TMP
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*!40000 DROP DATABASE IF EXISTS \`$BANCO\`*/;
CREATE DATABASE /*!32312 IF NOT EXISTS*/ \`$BANCO\` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE \`$BANCO\`;
EOF
sed 1,`grep -n '^USE ' $ARQUIVO |cut -f1 -d:`d $ARQUIVO >> $TMP
mv $TMP $ARQUIVO

8
sapl/legacy_migration_settings.py

@ -3,6 +3,9 @@ import os
from decouple import Config, RepositoryEnv
from dj_database_url import parse as db_url
from sapl.legacy.scripts.exporta_zope.variaveis_comuns import \
DIR_DADOS_MIGRACAO
from .settings import * # flake8: noqa
config = Config(RepositoryEnv(BASE_DIR.child('legacy', '.env')))
@ -35,3 +38,8 @@ DEBUG = True
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor'
SHELL_PLUS_DONT_LOAD = ['legacy']
NOME_BANCO_LEGADO = DATABASES['legacy']['NAME']
DIR_REPO = Path(DIR_DADOS_MIGRACAO, 'repos', NOME_BANCO_LEGADO)
MEDIA_ROOT = DIR_REPO

5
sapl/urls.py

@ -21,6 +21,7 @@ from django.views.generic.base import RedirectView, TemplateView
from django.views.static import serve as view_static_server
import sapl.api.urls
import sapl.audiencia.urls
import sapl.base.urls
import sapl.comissoes.urls
import sapl.compilacao.urls
@ -33,7 +34,6 @@ import sapl.protocoloadm.urls
import sapl.redireciona_urls.urls
import sapl.relatorios.urls
import sapl.sessao.urls
import sapl.audiencia.urls
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='index.html'),
@ -62,9 +62,6 @@ urlpatterns = [
url(r'^favicon\.ico$', RedirectView.as_view(
url='/static/img/favicon.ico', permanent=True)),
# Folhas XSLT e extras referenciadas por documentos migrados do sapl 2.5
url(r'^XSLT/HTML/(?P<path>.*)$', RedirectView.as_view(
url='/static/XSLT/HTML/%(path)s', permanent=False)),
url(r'', include(sapl.redireciona_urls.urls)),
]

Loading…
Cancel
Save