====== Script update-opac.py ======
Este es el script de actualización del OPAC, migrado a Python desde [[update-opac.sh|update-opac.sh]]. Abajo se incluye el archivo de configuración, ''opac.conf''.
Versión de 2008.02.26
#!/usr/bin/python
# coding=windows-1252
# coding is explained here: http://www.python.org/dev/peps/pep-0263/
# NOTE: Using utf-8 brings problems with delimiter "¦" used occasionally with mx
# TO-DO: verificar que los cisis (mx, id2i, msrt, etc.) estén en el PATH
# TO-DO: realizar una comparación exhaustiva con update-opac.sh
# TO-DO: generar log a un archivo. Ver http://docs.python.org/lib/module-logging.html
# Logging to multiple destinations: http://docs.python.org/lib/multiple-destinations.html
# Python Standard Logging: http://www.onlamp.com/lpt/a/5914
def error(msg = 'Error'):
'''Displays an error message and exits.'''
sys.exit(msg + '\n')
def run(command, msg = 'Error'):
'''Runs a system command and checks for an error.'''
'''
Accepts a string:
run('mx tmp count=3 pft=mfn/ now')
a list:
run(['mx', 'tmp', 'count=3', 'pft=mfn/', 'now'])
and a "broken" list:
run([
"mx",
"tmp",
"count=3",
"pft=mfn,x3,'!'/",
"now"
])
'''
try:
# NOTE: ENV is a global variable; shell=True is needed on Linux to avoid using lists for commands with arguments
subprocess.check_call(command, env=ENV, shell=True)
except subprocess.CalledProcessError:
error(msg + ':\n ' + command)
def emptydir(dir):
'''Removes every file in a directory.'''
# TO-DO: hacerlo recursivo. See 'rmall.py' in Programming Python:
# http://books.google.com/books?id=E6FcH4d-hAAC&pg=PA233&lpg=PA233&dq=python+rmall&source=web&ots=Xx3ulBkFBS&sig=pleFTG4fmym0b9UB6kXe-bplX9Y
# http://safari.oreilly.com/0596000855/python2-CHP-5-SECT-7
try:
for f in os.listdir(dir):
os.remove(os.path.join(dir, f))
except:
error("Error al vaciar el directorio " + dir)
raise
def read_config():
# TO-DO: see also
# - http://docs.python.org/lib/module-ConfigParser.html
# - http://cfgparse.sourceforge.net/
config_file = os.path.join(os.path.dirname(sys.argv[0]), "../opac.conf")
try:
config = ConfigParser.ConfigParser()
config.optionxform = str # make option names case sensitive
config.read(config_file)
return config
#execfile(config_file)
except:
error("No se ha podido leer el archivo de configuración.")
def build_env():
# Builds the environment dictionary, used for calling cisis commands.
# GENERAMOS EL ARCHIVO CIPAR
# Hay que usar el path *absoluto* para el cipar
CIPAR = os.path.join(OPACMARC_DIR, 'opac', 'opac.cip')
try:
f1 = open(CIPAR + '.dist', 'r') # archivo CIPAR de la distribución
f2 = open(CIPAR, 'w')
#for line in f1: f2.write(line.replace('__OPACMARC_DIR__', OPACMARC_DIR))
f2.write(
f1.read().replace('__OPACMARC_DIR__', OPACMARC_DIR)
)
f1.close()
f2.close()
except:
error("No se pudo generar el archivo cipar.")
# Este diccionario es pasado en las llamadas al sistema
env = {
'CIPAR': CIPAR,
# Las variables que siguen son definidas en conf.py
'PATH': os.getenv('PATH') + os.pathsep + CONFIG.get('Global', 'PATH_CISIS'),
'SUBJ_TAGS': CONFIG.get('Global', 'SUBJ_TAGS'),
'NAME_TAGS': CONFIG.get('Global', 'NAME_TAGS'),
'TITLE_TAGS': CONFIG.get('Global', 'TITLE_TAGS'),
'IGNORE_SUBJ_HEADINGS': CONFIG.get('Global', 'IGNORE_SUBJ_HEADINGS')
}
return env
def print_usage():
# The name of this script
SCRIPT_NAME = os.path.basename(sys.argv[0])
# A message to explain the script's usage
usage_msg = '''
''' + SCRIPT_NAME + '''
Genera las bases de datos y archivos auxiliares para OPACMARC.
Uso:
update-opac.py []
Ejemplos:
update-opac.py demo
update-opac.py /var/bases/opac/demo 100
Para correr este script, se necesitan los siguientes archivos:
- opac.conf archivo de configuración
- common/*.*
- opac/*.*
'''
print usage_msg
sys.exit()
def goto_work_dir():
# Directorio de trabajo
WORK_DIR = os.path.join(OPACMARC_DIR, 'work', DB_NAME)
if not os.path.isdir(WORK_DIR):
error("No se ha encontrado el directorio de trabajo para la base " + DB_NAME +":\n " + WORK_DIR)
# Nos ubicamos en el directorio de trabajo
try:
os.chdir(WORK_DIR)
except:
error("No se puede ingresar al directorio de trabajo, " + WORK_DIR + ".")
#TO-DO: eliminar en WORK_DIR todos los archivos *.* (sólo nos interesa conservar la carpeta 'original')
# Creamos el directorio temporal, si es necesario
if not os.path.isdir('tmp'):
try:
os.mkdir('tmp')
except:
error("No se pudo crear el directorio tmp.")
# Y si ya existe, lo vaciamos
else:
emptydir('tmp')
def get_biblio_db():
# --------------------------------------------------------------
# BASE DE DATOS ORIGINAL
# --------------------------------------------------------------
#
# La base de datos original puede estar en diversos formatos:
#
# Formato Archivos esperados Se leen con
# ---------------------------------------------------------------------------------------------------
# ZIP dbname.zip o biblio.zip (contenido: biblio.mst y biblio.xrf) Python (zipfile module)
# TGZ dbname.tgz o dbname.tar.gz [PENDIENTE] Python (tarfile module)
# MST/XRF biblio.mst y biblio.xrf mx
# MRC dbname.mrc mx 5.x
# ISO dbname.iso o biblio.iso mx
# ID dbname.id o biblio.id id2i
# TO-DO: remove %s from strings
# En este directorio se encuentra la base original
SOURCE_DIR = os.path.join('.', 'original')
sep = os.path.sep
print
if os.path.isfile(SOURCE_DIR + '/' + DB_NAME + '.zip'):
#unzip -oq $SOURCE_DIR/$DB_NAME.zip -d tmp || error
zipfile.ZipFile(SOURCE_DIR + '/' + DB_NAME + '.zip', 'r') # ??? Ver http://www.thescripts.com/forum/thread25297.html
print "Usando como base original: %s" + sep + "%s.zip" % (SOURCE_DIR, DB_NAME)
elif os.path.isfile(SOURCE_DIR + '/biblio.zip'):
#unzip -oq $SOURCE_DIR/biblio.zip -d tmp || error
print "Usando como base original: " + SOURCE_DIR + sep + "biblio.zip"
elif os.path.isfile(SOURCE_DIR + '/biblio.mst') and os.path.isfile(SOURCE_DIR + '/biblio.xrf'):
shutil.copy(SOURCE_DIR + '/biblio.mst', 'tmp')
shutil.copy(SOURCE_DIR + '/biblio.xrf', 'tmp')
print "Usando como base original: " + SOURCE_DIR + sep + "biblio.{mst,xrf}"
elif os.path.isfile(SOURCE_DIR + '/' + DB_NAME + '.mrc'):
print
print "Importando archivo $SOURCE_DIR/$DB_NAME.mrc..."
# FIXME -- para importar mrc podemos usar mx 5
#php $OPACMARC_DIR/bin/mrc2isis.php $SOURCE_DIR/$DB_NAME.mrc > tmp/$DB_NAME.id || error "Falla al ejecutar mrc2isis.php"
run('''id2i tmp/''' + DB_NAME + '''.id create=tmp/biblio''')
elif os.path.isfile(SOURCE_DIR + '/' + DB_NAME + '.iso'):
run('mx iso=%s/%s.iso create=tmp/biblio now -all' % (SOURCE_DIR, DB_NAME))
print "Usando como base original: %s" + sep + "%s.iso" % (SOURCE_DIR, DB_NAME)
elif os.path.isfile(SOURCE_DIR + '/biblio.iso'):
run('mx iso=%s/biblio.iso create=tmp/biblio now -all' % SOURCE_DIR)
print "Usando como base original: %s" + sep + "biblio.iso" % SOURCE_DIR
elif os.path.isfile(SOURCE_DIR + '/' + DB_NAME + '.id'):
run('id2i %s/%s.id create=tmp/biblio' % (SOURCE_DIR, DB_NAME))
print "Usando como base original: %s" + sep + "%s.id" % (SOURCE_DIR, DB_NAME)
elif os.path.isfile(SOURCE_DIR + '/biblio.id'):
run('id2i %s/biblio.id create=tmp/biblio' % SOURCE_DIR)
print "Usando como base original: %s" + sep + "biblio.id" % SOURCE_DIR
else:
error("No se encuentra la base de datos original.")
# El 2do parámetro (opcional) indica cuántos registros procesar
if len(sys.argv) > 2 and sys.argv[2] > 0:
MAXCOUNT = sys.argv[2]
else:
MAXCOUNT = '999999' # FIXME -- límite artificial
run('mx tmp/biblio count=' + MAXCOUNT + ' create=tmp/bibliotmp now -all')
try:
shutil.move('tmp/bibliotmp.mst', 'tmp/biblio.mst')
shutil.move('tmp/bibliotmp.xrf', 'tmp/biblio.xrf')
except:
error("Error al mover archivos.")
raise
def get_secs_db():
# ------------------------------------------------------------------
# Para la base bibima, tenemos que añadir a la base biblio los registros del SeCS
# Como input necesitamos:
# * base secstitle (la base title de SeCS, en formato linux)
# * archivo EMA.001 (listado de existencias, generado desde SeCS)
# * base oem2ansi (el gizmo para cambio de codificación)
# * archivo secs2marc.proc (migración SeCS => MARC21)
#
# TO-DO: Independizarse del nombre de la base (usar conf.py)
# ------------------------------------------------------------------
# TO-DO SeCS
pass
def process_img():
# Si hay imágenes de tapa, creamos un campo 985
DIR_IMG = os.path.join(CONFIG.get('Global', 'DIR_IMG'), DB_NAME)
if not os.path.isdir(DIR_IMG):
print
print "No hay directorio de imágenes"
else:
print
print "Procesando imágenes de tapas..."
file = open('tmp/lista_img.txt', 'w')
pattern = re.compile(r'00[0-9]{4}\.[a-z]{3}$') # TO-DO: revisar esta expresión regular
for filename in os.listdir(DIR_IMG):
if pattern.match(filename):
file.write(filename)
file.close()
run('''mx seq=tmp/lista_img.txt create=tmp/lista_img now -all''')
run('''mx tmp/lista_img "proc='d1a1#',v1.6,'^f',v1*7.3,'#'" copy=tmp/lista_img now -all''') # avoid problems with quotes
run('''mx tmp/lista_img "fst=1 0 v1^*" fullinv=tmp/lista_img''')
# Oct. 19, 2006
#ATENCION: tenemos un error en el MFN 4009 de bibima
# fatal: recupdat/mfn
# en la base vemos:
# 004008 10^aVariational calculus and optimal con..
# 925907264 10^aDiscriminants, resultants, and multi..
# 004010 00^aAnalysis on manifolds /^cJames R. Mu..x
# pero antes de ejecutar este comando el registro 4009 se ve sano.
# Oct. 20, 2006: el problema desaparece al recrear la base usando $MAXCOUNT
# Quizás sea mejor hacer un loop sobre los archivos de imagenes y solo acceder a los registros afectados,
# en vez de acceder a todos los registros para solo modificar unos pocos
run('''mx tmp/biblio "proc=if l(['tmp/lista_img']v1) > 0 then 'd985a985!##^a',ref(['tmp/lista_img']l(['tmp/lista_img']v1),v1^f),'!' fi" copy=tmp/biblio tell=''' + TELL + ''' now -all''')
def biblio_db():
# ------------------------------------------------------------------
# BASE BIBLIO (1ra pasada)
# ------------------------------------------------------------------
print
print "Creamos una copia (texto) de la base bibliografica..."
# BUG en i2id: aun sin haber errores, el exit status es diferente de cero (e.g. 17, 19). Se testea con 'echo $?'
# A causa de ese bug, aquí usamos subprocess.call en lugar de subprocess.check_call
subprocess.call('''i2id tmp/biblio tell=''' + TELL + ''' > tmp/biblio1.id''', env=ENV, shell=True)
print
print "Intentamos normalizar la puntuacion final, filtramos encabezamientos"
print "tematicos, y asignamos un numero (provisorio) a cada campo"
print "de encabezamientos en el subcampo ^9..."
# FIXED -- mx "seq=tmp/biblio1.id\n" molesta en Windows, cambiar por mx "seq=tmp/biblio1.id\\n" (aparece en varios comandos)
run('''mx "seq=tmp/biblio1.id\\n" lw=3000 "pft=@HEAD.PFT" now tell=''' + TELL + ''' > tmp/biblio2.id''')
def build_subj_db():
# ------------------------------------------------------------------
# BASE SUBJ
# ------------------------------------------------------------------
print
print "-----------------------------------------------------"
print " Base de encabezamientos tematicos"
print "-----------------------------------------------------"
print "Creamos el listado de encabezamientos tematicos..."
run('''mx "seq=tmp/biblio2.id\\n" lw=1000 "pft=if getenv('SUBJ_TAGS') : v1*1.4 then @SUBJ.PFT fi" now tell=''' + TELL + '> tmp/subj1.id')
print
print "Convertimos el listado en una base (desordenada y con duplicados)..."
run('''id2i tmp/subj1.id create/app=tmp/subj1 tell=''' + TELL)
print
print "Regularizamos la puntuacion final de los encabezamientos generados..."
run('''mx tmp/subj1 "proc='d2a2¦',v1,'¦'" "proc='d1a1¦',@REGPUNT.PFT,'¦'" "proc='d2'" copy=tmp/subj1 now -all tell=''' + TELL)
print
print "Almacenamos en un campo auxiliar la clave de ordenacion..."
run('''mx tmp/subj1 uctab=UC-ANSI.TAB "proc='d99a99¦',@HEADSORT.PFT,'¦'" copy=tmp/subj1 now -all tell=''' + TELL)
print
print "Ordenamos la base de encabezamientos tematicos..."
run('''msrt tmp/subj1 100 v99 tell=''' + TELL)
print
print "Generamos la tabla para mapear los numeros de encabezamientos..."
run('''mx tmp/subj1 "pft=if s(v1) <> ref(mfn-1,v1) then putenv('HEADING_CODE='v9) fi, v9,'|',getenv('HEADING_CODE')/" now -all tell=''' + TELL + ' > tmp/subjcode.seq')
print
print "Eliminamos los encabezamientos duplicados..."
run('''mx tmp/subj1 lw=1000 "pft=@ELIMDUP2.PFT" now tell=''' + TELL + ''' > tmp/subj.id''')
print
print "Creamos la base de encabezamientos tematicos (ordenada y sin duplicados)..."
run('''id2i tmp/subj.id create/app=subj tell=''' + TELL)
def build_name_db():
# TO-DO: fusionar con subj_db()?
# ------------------------------------------------------------------
# BASE NAME
# ------------------------------------------------------------------
print
print "-----------------------------------------------------"
print " Base de encabezamientos de nombres"
print "-----------------------------------------------------"
print "Creamos el listado de encabezamientos de nombres..."
run('''mx "seq=tmp/biblio2.id\\n" lw=1000 "pft=if getenv('NAME_TAGS') : v1*1.4 then @NAME.PFT fi" now tell=''' + TELL + ' > tmp/name1.id')
print
print "Convertimos el listado en una base (desordenada y con duplicados)..."
run('id2i tmp/name1.id create/app=tmp/name1 tell=' + TELL)
print
print "Regularizamos la puntuacion final de los encabezamientos generados..."
run('''mx tmp/name1 "proc='d2a2¦',v1,'¦'" "proc='d1a1¦',@REGPUNT.PFT,'¦'" "proc='d2'" copy=tmp/name1 now -all tell=''' + TELL)
print
print "Almacenamos en un campo auxiliar la clave de ordenacion..."
run('''mx tmp/name1 uctab=UC-ANSI.TAB "proc='d99a99¦',@HEADSORT.PFT,'¦'" copy=tmp/name1 now -all tell=''' + TELL)
print
print "Ordenamos la base de encabezamientos de nombres..."
run('''msrt tmp/name1 100 v99 tell=''' + TELL)
print
print "Generamos la tabla para mapear los numeros de encabezamientos..."
run('''mx tmp/name1 "pft=if s(v1) <> ref(mfn-1,v1) then putenv('HEADING_CODE='v9) fi, v9,'|',getenv('HEADING_CODE')/" now -all tell=''' + TELL + ' > tmp/namecode.seq')
print
print "Eliminamos los encabezamientos duplicados..."
run('''mx tmp/name1 lw=1000 "pft=@ELIMDUP2.PFT" now tell=''' + TELL + '''> tmp/name.id''')
print
print "Creamos base de encabezamientos de nombres (ordenada y sin duplicados)..."
run('''id2i tmp/name.id create/app=name tell=''' + TELL)
def recode_headings():
print
# -----------------------------------------------------------------
print "Reasignamos numeros a los encabezamientos en los registros"
print "bibliograficos (subcampo 9)..."
# -----------------------------------------------------------------
run('''mx seq=tmp/subjcode.seq create=tmp/subjcode now -all''')
run('''mx tmp/subjcode "fst=1 0 v1" fullinv=tmp/subjcode''')
run('''mx seq=tmp/namecode.seq create=tmp/namecode now -all''')
run('''mx tmp/namecode "fst=1 0 v1" fullinv=tmp/namecode''')
run('''mx "seq=tmp/biblio2.id\\n" lw=1000 "pft=@RECODE.PFT" now tell=''' + TELL + ''' > tmp/biblio3.id''')
def build_title_db():
# ------------------------------------------------------------------
# BASE TITLE
# ------------------------------------------------------------------
print
print "-----------------------------------------------------"
print " Base de titulos"
print "-----------------------------------------------------"
print "Creamos listado de titulos..."
run('''mx "seq=tmp/biblio3.id\\n" lw=1000 "pft=if getenv('TITLE_TAGS') : v1*1.4 then ,@TITLE.PFT, fi" now tell=''' + TELL + ' > tmp/title1.id')
print
print "Convertimos el listado en una base (desordenada y con duplicados)..."
run('''id2i tmp/title1.id create/app=tmp/title1 tell=''' + TELL)
print
print "Almacenamos en un campo auxiliar (99) la clave de ordenacion de titulos."
run('''mx tmp/title1 uctab=UC-ANSI.TAB "proc='d99a99¦',@HEADSORT.PFT,'¦'" copy=tmp/title1 now -all tell=''' + TELL)
print
print "Ordenamos la base de titulos."
run('''msrt tmp/title1 100 v99 tell=''' + TELL)
print
print "Eliminamos los titulos duplicados."
run('''mx tmp/title1 lw=1000 "pft=@ELIMDUP2.PFT" now tell=''' + TELL + ''' > tmp/title.id''')
print
print "Creamos la base de titulos (ordenada y sin duplicados)."
run('''id2i tmp/title.id create/app=title tell=''' + TELL)
def biblio_db_2():
# ------------------------------------------------------------------
# BASE BIBLIO (2da pasada)
# ------------------------------------------------------------------
print
print "-----------------------------------------------------"
print "Base bibliografica"
print "-----------------------------------------------------"
print "Recreamos la base bibliografica."
run('''id2i tmp/biblio3.id create=biblio tell=''' + TELL)
print
print "Ordenamos la base bibliografica."
run('''msrt biblio 100 @LOCATION_SORT.PFT tell=''' + TELL)
def fullinv():
# ------------------------------------------------------------------
# FULLINV
# ------------------------------------------------------------------
# -------------------------------------------------------------------
# Generación de archivos invertidos.
# ATENCION: AC-ANSI.TAB envia los numeros al diccionario.
# -------------------------------------------------------------------
print
print " Archivo invertido - Base de temas..."
run('''mx subj fst=@HEADINGS.FST actab=AC-ANSI.TAB uctab=UC-ANSI.TAB fullinv=subj tell=''' + TELL)
print
print " Archivo invertido - Base de nombres..."
run('''mx name fst=@HEADINGS.FST actab=AC-ANSI.TAB uctab=UC-ANSI.TAB fullinv=name tell=''' + TELL)
print
print " Archivo invertido - Base de titulos..."
run('''mx title "fst=2 0 '~',@HEADSORT.PFT" actab=AC-ANSI.TAB uctab=UC-ANSI.TAB fullinv=title tell=''' + TELL)
print
print " Archivo invertido - Base bibliografica..."
# Antes de la FST, aplicamos un gizmo a los campos que generan puntos de acceso
run('''mx biblio gizmo=DICTGIZ,100,110,111,130,700,710,711,730,800,810,811,830 gizmo=DICTGIZ,240,245,246,440,740,600,610,611,630,650,651,653,655,656 fst=@BIBLIO.FST actab=AC-ANSI.TAB uctab=UC-ANSI.TAB stw=@BIBLIO.STW fullinv=biblio tell=''' + TELL)
def process_analytics():
# ------------------------------------------------------------------
# REGISTROS ANALÍTICOS
# ------------------------------------------------------------------
print
print "Detectando registros analíticos..."
# Para los registros analíticos, creamos un 773$9 donde guardar el MFN
# del registro asociado, y así ahorrar futuros lookups en el diccionario
# ATENCION: esto debe hacerse *después* de aplicado el msrt y generado el diccionario
run('''mx biblio "proc=if p(v773^w) then 'd773a773¦',v773,'^9',f(l('-NC=',v773^w),1,0),'¦', fi" copy=biblio now -all tell=''' + TELL)
def compact_db():
# Compactamos la base
run('mx biblio create=bibliotmp now -all')
try:
shutil.move('bibliotmp.mst', 'biblio.mst')
shutil.move('bibliotmp.xrf', 'biblio.xrf')
except:
error()
#echo
#cecho "blue" "Títulos de seriadas..."
#mx biblio "-BIBLEVEL=S" "pft=replace(v245*2,'^','~')" now -all > title_serial.txt
def compute_postings():
# POSTINGS
print
# --------------------------------------------------------
print "Asignamos postings a los terminos del indice de temas."
# --------------------------------------------------------
run('''mx subj "proc='d11a11#',f(npost(['biblio']'_SUBJ_'v9),1,0),'#'" copy=subj now -all tell=''' + TELL)
print
# ----------------------------------------------------------
print "Asignamos postings a los terminos del indice de nombres."
# ----------------------------------------------------------
run('''mx name "proc='d11a11#',f(npost(['biblio']'_NAME_'v9),1,0),'#'" copy=name now -all tell=''' + TELL)
# TO-DO: necesitamos postings para los títulos controlados (series, títulos uniformes).
# Para eso necesitamos un subcampo $9 en la base de títulos.
def build_agrep_dictionaries():
# DICCIONARIOS PARA AGREP
print
# -----------------------------------------------------
print "Generamos diccionarios para AGREP."
# Solo nos interesan claves asociadas a ciertos tags.
# /100 restringe la cantidad de postings (de lo contrario, da error).
# ATENCION: los sufijos NAME, SUBJ, TITLE van en mayusculas o minusculas
# en base a los valores que tome el parámetro CGI correspondiente.
# -----------------------------------------------------
print " - subj"
# Para bibima usamos la base MSC; para el resto, la base SUBJ
# TO-DO: la base subj también sirve para bibima; usar cat & uniq
# TO-DO: independizarse del nombre de la base (usar conf.py)
if DB_NAME == 'bibima':
run('''mx dict=MSC "pft=v1^*/" k1=a k2=zz now > dictSUBJ.txt''')
else:
run('''mx dict=subj "pft=v1^*/" k1=a k2=zz now > dictSUBJ.txt''')
print " - name"
run('''mx dict=name "pft=v1^*/" k1=a k2=zz now > dictNAME.txt''')
print " - title (incluye series)"
#mx dict=biblio,1,2/100 "pft=if v2^t : '204' then v1^*/ fi" k1=a now > dicttitle.txt
run('''ifkeys biblio +tags from=a to=zzzz > tmp/titlekeys.txt''')
run('''mx seq=tmp/titlekeys.txt "pft=if '204~404' : right(v2,3) then v3/ fi" now > tmp/titlekeys2.txt''')
#cat tmp/titlekeys2.txt | uniq > dictTITLE.txt || error
run('''mx seq=tmp/titlekeys2.txt "pft=if v1 <> ref(mfn-1, v1) then v1/ fi" now > dictTITLE.txt''')
print " - any"
# union de los diccionarios anteriores (eliminando términos duplicados)
# TO-DO: es un poco lento, ver cómo apurarlo.
#cat dict*.txt | sort | uniq > dictANY.txt || error
# con Python sería algo así?
#list(set(open())).sort()
file1 = open('tmp/alldict.txt', 'w')
for type in ['SUBJ', 'NAME', 'TITLE']:
file2 = open('dict' + type + '.txt', 'r')
file1.write(file2.read())
file2.close()
file1.close()
#all = [line for line in file('dictALL.txt')]
#uniq = list(set(all))
#uniq.sort()
run('''mx seq=tmp/alldict.txt create=tmp/alldict now -all''')
run('''msrt tmp/alldict 100 v1''')
run('''mx tmp/alldict "pft=if v1 <> ref(mfn-1, v1) then v1/ fi " now > dictANY.txt''')
def build_aux_files():
# ARCHIVOS AUXILIARES
print
# -----------------------------------------------------
print "Lista de codigos de idioma."
# -----------------------------------------------------
run('''mx seq=LANG.TXT create=tmp/lang now -all''')
run('''mx tmp/lang fst=@LANG.FST fullinv=tmp/lang''')
run('''mx dict=biblio "k1=-LANG=A" "k2=-LANG=ZZZ" "pft=v1^**6.3,'|',v1^t/" now > tmp/langcode.txt''')
run('''mx seq=tmp/langcode.txt create=tmp/langcode now -all''')
run('''msrt tmp/langcode 30 "ref(['tmp/lang']l(['tmp/lang']v1.3),s(mpu,v3))"''')
run('''mx tmp/langcode "pft=v1,'^p',v2,'^',/" now -all > langcode.txt''')
# TO-DO: independizarse del nombre de la base (usar conf.py)
if DB_NAME == "bibima":
print
# -----------------------------------------------------
print "Actualizamos los postings para cada código MSC"
# -----------------------------------------------------
run('''mx MSC "proc=if l(['biblio']'-MSC='v1) > 0 then 'd7a7@',f(npost(['biblio']'-MSC='v1),1,0),'@' fi" copy=MSC now -all tell=''' + TELL)
# TO-DO: compactar la base MSC
print
# -----------------------------------------------------
print "Lista de codigos de bibliotecas."
# -----------------------------------------------------
run('''mx dict=biblio "k1=-BIB=A" "k2=-BIB=ZZZ" "pft=v1^**5,'^p',v1^t/" now > bibcode.txt''')
print
# -----------------------------------------------------
print "Fechas extremas."
# -----------------------------------------------------
run('''mx dict=biblio "k1=-F=1" "k2=-F=2999" "pft=v1^**3/" now > tmp/dates1.txt''')
run('''mx tmp to=1 "proc='a1~',replace(s(cat('tmp/dates1.txt')),s(#),'&'),'~'" "pft=v1.4,'-',s(right(v1,5)).4" > dates.txt''')
# -----------------------------------------------------
# Total de registros disponibles
# -----------------------------------------------------
run('''mx biblio count=1 "pft=proc('a5001~',f(maxmfn-1,1,0),'~'),'BIBLIOGRAPHIC_TOTAL=',left(v5001,size(v5001)-3),if size(v5001) > 3 then '.' fi,right(v5001,3)/" > bases.txt''')
run('''mx name count=1 "pft=proc('a5001~',f(maxmfn-1,1,0),'~'),'NAME_TOTAL=',left(v5001,size(v5001)-3),if size(v5001) > 3 then '.' fi,right(v5001,3)/" >> bases.txt''')
run('''mx subj count=1 "pft=proc('a5001~',f(maxmfn-1,1,0),'~'),'SUBJ_TOTAL=',left(v5001,size(v5001)-3),if size(v5001) > 3 then '.' fi,right(v5001,3)/" >> bases.txt''')
run('''mx title count=1 "pft=proc('a5001~',f(maxmfn-1,1,0),'~'),'TITLE_TOTAL=',left(v5001,size(v5001)-3),if size(v5001) > 3 then '.' fi,right(v5001,3)/" >> bases.txt''')
# -----------------------------------------------------
# Total de ejemplares disponibles
# -----------------------------------------------------
# ATENCION: necesitamos una buena definición de "ejemplares" (los "items" de FRBR)
# Por ahora, vamos a contar los nros. de inventario, 859$p
# En lugar de wc, usar archivo temporal y count = len(open(thefilepath, 'rU').readlines( )) -- ver Recipe 2.5. Counting Lines in a File
run('''mx biblio "pft=(v859^p/)" now > tmp/items.txt''')
itemcount = len(open('tmp/items.txt', 'rU').readlines( ))
file = open('tmp/items-total.txt', 'w')
file.write(str(itemcount))
file.close()
#run('''mx biblio "pft=(v859^p/)" now | wc -l > tmp/items-total.txt''')
run('''mx seq=tmp/items-total.txt "pft=proc('d1a1|',replace(v1,' ',''),'|'), if size(v1) > 3 then left(v1,size(v1)-3),'.',right(v1,3), else v1, fi" now > tmp/items-total-punto.txt''')
#echo "ITEMS_TOTAL=`cat tmp/items-total-punto.txt`" >> bases.txt
f1 = open('tmp/items-total-punto.txt')
f2 = open('bases.txt', 'a') # 'a': append (>>)
f2.write('ITEMS_TOTAL=')
f2.write(f1.read())
#print f2.read() # FIXME -- Mostramos bases.txt
f1.close()
f2.close()
# Mostramos bases.txt
#cat bases.txt
print
# -----------------------------------------------------
print "Listado de novedades."
# -----------------------------------------------------
# TO-DO: generalizar para cualquier año y/o mes, y para otros criterios (e.g. en ABCI por inventario)
run('''mx biblio "pft=if v859^y[1]*6 = '2006' then v1/ fi" now | sort > novedades.txt''') # FIXME (sort)
print
# -----------------------------------------------------
print "Fecha de esta actualizacion."
# -----------------------------------------------------
run('''mx tmp "pft=s(date)*6.2,'/',s(date)*4.2,'/',s(date).4,' a las ',s(date)*9.2,':',s(date)*11.2" to=1 > updated.txt''')
def remove_tmp_files():
# Eliminamos archivos temporales generados por este script
print
print "Eliminando archivos temporales..."
try:
shutil.rmtree('tmp')
except:
print "ERROR: No se puede eliminar el directorio tmp"
#rm -rf *.ln* 2>/dev/null
#rm -rf *.lk* 2>/dev/null
pattern = re.compile(r'\.l[kn][12]$') # FIXME -- se comporta como si tuviera ^ al comienzo!
for f in os.listdir('.'):
if pattern.match(f):
os.remove(f)
def move_files():
# Movemos los archivos generados. Previamente vaciamos TARGET_DIR.
# TO-DO: supongamos que alguien quiere mover la versión para Windows de las bases...
print
print "Moviendo los archivos generados..."
TARGET_DIR = os.path.join(CONFIG.get('Global', 'TARGET_DIR'), DB_NAME)
emptydir(TARGET_DIR)
try:
for f in os.listdir('.'):
if '.' in f: # solo archivos *.* (excluyo directorios)
shutil.move(f, TARGET_DIR)
except:
raise
error("No se puede mover los archivos a " + TARGET_DIR)
raise
def end():
print
print "*** Ejecución finalizada. ***"
print
sys.exit(0)
# ---------------------
# MAIN
# ---------------------
# Import modules
import os # path.*, mkdir, listdir, etc
import sys # argv for processing script arguments
import shutil # shell utils (copy, move, rmtree...)
import re # regular expressions
import zipfile # for reading .zip files
import subprocess # for running system commands (mx, i2id, etc)
import ConfigParser # for reading config file
#Check mandatory argument
if len(sys.argv) < 2:
print_usage()
# Read config file and define global variables
DB_NAME = sys.argv[1]
OPACMARC_DIR = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
CONFIG = read_config()
TELL = CONFIG.get('Global', 'TELL') # used by many calls to cisis utilities
ENV = build_env()
# Prepare the input data
goto_work_dir()
get_biblio_db()
get_secs_db() # if...
process_img() # if...
# Do the hard work
biblio_db()
build_subj_db()
build_name_db()
recode_headings()
build_title_db()
biblio_db_2()
fullinv()
process_analytics()
compact_db()
compute_postings()
build_agrep_dictionaries()
build_aux_files()
# Clean and/or move files if needed
if CONFIG.get('Global', 'CLEAN') == 1: remove_tmp_files()
if CONFIG.get('Global', 'MOVE') == 1: move_files()
# Say goodbye
end()
===== opac.conf =====
# coding=latin-1
# ------------------------------------------------------------------
# CONFIGURACION para update-opac.py
# ------------------------------------------------------------------
# Using module ConfigParser, a section header is mandatory
[Global]
# Ubicación de mx y demás utilitarios
PATH_CISIS = /home/fernando/bin/cisis
# *** IGNORE ESTA SECCION POR EL MOMENTO ***
# En este directorio está la base bibliográfica original. El valor predeterminado
# es OPACMARC_DIR/work/DB_NAME/original
# Si update-opac.sh se ejecuta en la misma máquina donde se alojan las bases
# de Catalis, etonces puede indicar aquí la ruta correspondiente:
# SOURCE_DIR=/var/www/bases/catalis_pack/catalis/DB_NAME
# *** IGNORE HASTA ACA ***
# En este directorio están almacenadas las imágenes de las tapas (si las hay).
# ATENCION: no incluir al final de la ruta el directorio con el nombre de la base.
DIR_IMG = /home/fernando/www/html/catalis_pack_devel/opac/img/
# A este directorio van a parar los archivos generados (si se usa MOVE=1).
# ATENCION: no incluir al final de la ruta el directorio con el nombre de la base.
TARGET_DIR = /home/fernando/www/bases/catalis_pack_devel/opac/
# Use MOVE=1 para mover los archivos generados al directorio destino (TARGET_DIR).
MOVE = 1
# Use CLEAN=1 para eliminar archivos temporales creados durante la generación del OPAC.
CLEAN = 1
# Use CONVERT_WINDOWS=1 si desea usar en un servidor Windows las bases generadas.
CONVERT_WINDOWS = 0
# ------------------------------------------------------------------
# En la mayoría de las situaciones, las opciones que siguen
# pueden dejarse tal como están
# ------------------------------------------------------------------
# Valor del parámetro tell del mx
TELL = 5000
# Lista de tags de los cuales vamos a extraer los encabezamientos
# subject headings
SUBJ_TAGS = v600v610v611v630v650v651v653v655v656
# name headings
NAME_TAGS = v100v110v111v700v710v711
# Lista de campos que se incluyen en la base title.
# ATENCION: completar/revisar. Ver title.pft.
# Faltarian: subcampos $t de campos 505 y 7xx; campos de relación: 76x-78x
TITLE_TAGS = v130v240v245v246v730v740v765v773v440v830
# Valores del 2do indicador que no deseamos considerar en campos 6xx
IGNORE_SUBJ_HEADINGS = #6
{{tag>opacmarc admin}}