====== 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}}