diff options
author | Norbert Preining <preining@logic.at> | 2009-09-15 19:05:43 +0000 |
---|---|---|
committer | Norbert Preining <preining@logic.at> | 2009-09-15 19:05:43 +0000 |
commit | 4ca6cb2aecf9e81762fea86200e6ea0ca1600df1 (patch) | |
tree | 024775825685182fb7916c15fc632cae7f5bfda0 /Master/tlpkg/dev | |
parent | a58e7147a33948e4a6a8218bde253c4f36bce7da (diff) |
move tlpkg/lib to tlpkg/dev/lib
git-svn-id: svn://tug.org/texlive/trunk@15304 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/tlpkg/dev')
-rw-r--r-- | Master/tlpkg/dev/lib/C/Makefile | 7 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/C/tlp-config.c | 75 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/C/tlp-config.h | 23 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/C/tlp-src.c | 321 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/C/tlp-src.h | 75 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/C/tlp-utils.c | 182 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/C/tlp-utils.h | 73 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/bash/TeXLiveInfra.sh | 261 | ||||
-rw-r--r-- | Master/tlpkg/dev/lib/python/TeXLive.py | 1744 |
9 files changed, 2761 insertions, 0 deletions
diff --git a/Master/tlpkg/dev/lib/C/Makefile b/Master/tlpkg/dev/lib/C/Makefile new file mode 100644 index 00000000000..396b9744290 --- /dev/null +++ b/Master/tlpkg/dev/lib/C/Makefile @@ -0,0 +1,7 @@ +CFLAGS = -Wall -I. +SO = dylib + +all: libtlp.$(SO) + +libtlp.$(SO): tlp-src.o tlp-config.o tlp-utils.o + $(CC) $^ -dynamiclib -o $@ diff --git a/Master/tlpkg/dev/lib/C/tlp-config.c b/Master/tlpkg/dev/lib/C/tlp-config.c new file mode 100644 index 00000000000..5633db611dd --- /dev/null +++ b/Master/tlpkg/dev/lib/C/tlp-config.c @@ -0,0 +1,75 @@ +/* tlp-config.c - module exporting configuration stuff + * + * Copyright 2007 Jjgod Jiang + * Derived from the Perl implementation by Norbert Preining + * + * This file is licensed under the GNU General Public License version 2 + * or any later version. */ + +#include <tlp-utils.h> +#include <stdlib.h> + +#define TLP_META_CATEGORIES "Collection", "Scheme" +#define TLP_NORMAL_CATEGORIES "Package", "TLCore", "Documentation" +#define TLP_DEFAULT_CATEGORY "Package" + +const char *_tlp_meta_categories[] = { + TLP_META_CATEGORIES, +}; + +const char *_tlp_normal_categories[] = { + TLP_NORMAL_CATEGORIES, +}; + +const char *_tlp_categories[] = { + TLP_META_CATEGORIES, + TLP_NORMAL_CATEGORIES, +}; + +tlp_str_list *tlp_meta_categories; +tlp_str_list *tlp_normal_categories; +tlp_str_list *tlp_categories; +tlp_str tlp_default_category; + +#define ARR_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +/* TODO: we might have more complicated implementation later. */ +tlp_result tlp_config_init() +{ + tlp_meta_categories = tlp_str_list_from_array(_tlp_meta_categories); + if (tlp_meta_categories == NULL) + goto failed1; + + tlp_normal_categories = tlp_str_list_from_array(_tlp_normal_categories); + if (tlp_normal_categories == NULL) + goto failed2; + + tlp_categories = tlp_str_list_from_array(_tlp_categories); + if (tlp_categories == NULL) + goto failed3; + + tlp_default_category = tlp_str_from_bytes(TLP_DEFAULT_CATEGORY); + if (tlp_default_category == NULL) + goto failed4; + + return TLP_OK; + +failed4: + tlp_str_list_free(tlp_categories); +failed3: + tlp_str_list_free(tlp_normal_categories); +failed2: + tlp_str_list_free(tlp_meta_categories); +failed1: + return TLP_FAILED; +} + +void tlp_config_free() +{ + tlp_str_list_free(tlp_meta_categories); + tlp_str_list_free(tlp_normal_categories); + tlp_str_list_free(tlp_categories); + + tlp_str_free(tlp_default_category); +} + diff --git a/Master/tlpkg/dev/lib/C/tlp-config.h b/Master/tlpkg/dev/lib/C/tlp-config.h new file mode 100644 index 00000000000..c00e2143c84 --- /dev/null +++ b/Master/tlpkg/dev/lib/C/tlp-config.h @@ -0,0 +1,23 @@ +/* tlp-config.c - header exporting configuration stuff + * + * Copyright 2007 Jjgod Jiang + * Derived from the Perl implementation by Norbert Preining + * + * This file is licensed under the GNU General Public License version 2 + * or any later version. */ + +#ifndef __TLP_CONFIG__ +#define __TLP_CONFIG__ + +/* We use the following pointers to encapsulate the real config module + * implementation: we could use static allocated arrays, or we could + * use dynamic allocated ones, as long as we follow the rule (put a + * NULL pointer at the end of it), internal implementation does not + * matter. */ + +extern tlp_str_list tlp_meta_categories; +extern tlp_str_list tlp_normal_categories; +extern tlp_str_list tlp_categories; + +#endif + diff --git a/Master/tlpkg/dev/lib/C/tlp-src.c b/Master/tlpkg/dev/lib/C/tlp-src.c new file mode 100644 index 00000000000..a67aacbb74f --- /dev/null +++ b/Master/tlpkg/dev/lib/C/tlp-src.c @@ -0,0 +1,321 @@ +/* tlp-src.c - module for using tlpsrc files + * + * Copyright 2007 Jjgod Jiang + * Derived from the Perl implementation by Norbert Preining + * + * This file is licensed under the GNU General Public License version 2 + * or any later version. */ + +#include <tlp-src.h> +#include <stdio.h> + +/* internal function prototypes {{{ */ + +tlp_result tlp_src_process_line(tlp_src *src, tlp_str line, + int *started, int *finished, + const char *file); + +tlp_result tlp_str_get_word(tlp_str str, tlp_str word, int max); + +tlp_result tlp_src_get_name(tlp_str line, + tlp_src *src, + int *started, + const char *file); + +tlp_result tlp_src_get_category(tlp_str line, + tlp_src *src, + int *started, + const char *file); + +/* }}} */ + +/* internal data structures {{{ */ + +struct tlp_src_field { + const char *key; + tlp_result (*func)(tlp_str line, + tlp_src *src, + int *started, + const char *file); +}; + +/* for lines start with "name", we use function tlp_src_get_name() to + * process it, and feed it with the current tlp_src instance. */ + +struct tlp_src_field tlp_src_fields[] = { + { "name", tlp_src_get_name }, + { "category", tlp_src_get_category }, /* + { "shortdesc", tlp_src_get_shortdesc }, + { "longdesc", tlp_src_get_longdesc }, + { "catalogue", tlp_src_get_catalogue }, + + { "runpatterns", tlp_src_get_runpatterns }, + { "srcpatterns", tlp_src_get_srcpatterns }, + { "docpatterns", tlp_src_get_docpatterns }, + { "binpatterns", tlp_src_get_binpatterns }, + + { "execute", tlp_src_get_execute }, + { "depend", tlp_src_get_depend }, */ +}; + +#define TLP_SRC_TOTAL_FIELDS (sizeof(tlp_src_fields) / sizeof(tlp_src_fields[0])) + +/* }}} */ + +/* tlp_src related {{{ */ + +tlp_src *tlp_src_new(tlp_str name, + tlp_str category, + tlp_str shortdesc, + tlp_str longdesc, + tlp_str catalogue, + tlp_pattern *runpatterns, + tlp_pattern *srcpatterns, + tlp_pattern *docpatterns, + tlp_pattern *binpatterns, + tlp_execute *executes, + tlp_depend *depends) +{ + tlp_src *src = tlp_new(tlp_src); + if (! src) + return NULL; + + src->name = tlp_str_copy(name); + src->category = tlp_str_copy(category); + src->shortdesc = tlp_str_copy(shortdesc); + src->longdesc = tlp_str_copy(longdesc); + src->catalogue = tlp_str_copy(catalogue); + + src->runpatterns = runpatterns; + src->srcpatterns = srcpatterns; + src->docpatterns = docpatterns; + src->binpatterns = binpatterns; + + src->executes = executes; + src->depends = depends; + + return src; +} + +void tlp_src_free(tlp_src *src) +{ + if (! src) + return; + + tlp_str_free(src->name); + tlp_str_free(src->category); + tlp_str_free(src->shortdesc); + tlp_str_free(src->longdesc); + tlp_str_free(src->catalogue); + + tlp_patterns_free(src->runpatterns); + tlp_patterns_free(src->srcpatterns); + tlp_patterns_free(src->docpatterns); + tlp_patterns_free(src->binpatterns); + + tlp_executes_free(src->executes); + tlp_depends_free(src->depends); + + free(src); + src = NULL; +} + +tlp_src *tlp_src_from_file(char *file) +{ + FILE *fp; + tlp_src *src; + tlp_char line[TLP_SRC_LINE_MAX]; + int started, finished; + + fp = fopen(file, "r"); + if (! fp) + return NULL; + + src = tlp_new(tlp_src); + + /* TODO: if the argument is not readable as is, try looking + * for it in the hierarchy where we are.*/ + if (! src) + return NULL; + + started = finished = 0; + + while (tlp_fgets(line, TLP_SRC_LINE_MAX, fp)) + { + if (tlp_src_process_line(src, line, + &started, + &finished, + file) != TLP_OK) + goto failed; + } + + fclose(fp); + return src; + +failed: + tlp_src_free(src); + fclose(fp); + return NULL; +} + +tlp_result tlp_src_process_line(tlp_src *src, tlp_str line, + int *started, int *finished, + const char *file) +{ + int i; + + /* skip all leading spaces */ + for (i = 0; tlp_char_is_space(line[i]); i++) + ; + + /* skip comment lines */ + if (line[i] == TLP_CHAR_COMMENT) + return TLP_OK; + + if (tlp_char_is_eol(line[i])) + { + if (! *started || *finished) + return TLP_OK; + + tlp_error_msg("%s: empty line not allowed in tlpsrc\n", file); + return TLP_FAILED; + } + + /* something like " name ..." is not allowed */ + if (line[0] == ' ') + { + tlp_error_msg("%s: continuation line not allowed in tlpsrc: ", file); + tlp_error_str(line); + + return TLP_FAILED; + } + + for (i = 0; i < TLP_SRC_TOTAL_FIELDS; i++) + if (tlp_str_start_with_bytes(line, tlp_src_fields[i].key)) + return tlp_src_fields[i].func(line, src, started, file); + + tlp_error_msg("%s: unknown tlpsrc directive, please fix: %s", + file, line); + return TLP_OK; +} + +tlp_result tlp_src_get_name(tlp_str line, + tlp_src *src, + int *started, + const char *file) +{ + tlp_char name[TLP_SRC_NAME_MAX]; + + if (*started) + { + tlp_error_msg("%s: tlpsrc cannot have two name directives", file); + return TLP_FAILED; + } + + if (tlp_str_get_word(line + tlp_str_len(TLP_STR("name")), + name, TLP_SRC_NAME_MAX) == TLP_OK) + { + src->name = tlp_str_copy(name); + *started = 1; + + return TLP_OK; + } + else + return TLP_FAILED; +} + +tlp_result tlp_src_get_category(tlp_str line, + tlp_src *src, + int *started, + const char *file) +{ + if (! *started) + { + tlp_error_msg("%s: first tlpsrc directive must be 'name'", file); + return TLP_FAILED; + } + + return TLP_OK; +} + +/* }}} */ + +/* tlp_pattern related {{{ */ + +void tlp_pattern_free(tlp_pattern *pat) +{ + if (pat != NULL) + return; + + switch (pat->type) + { + case TLP_PATTERN_T: + tlp_str_list_free(pat->u.t); + break; + + case TLP_PATTERN_F: + tlp_str_free(pat->u.f); + break; + + case TLP_PATTERN_D: + tlp_str_free(pat->u.d); + break; + + case TLP_PATTERN_R: + tlp_str_free(pat->u.r); + break; + } + + free(pat); + pat = NULL; +} + +void tlp_patterns_free(tlp_pattern *pat) +{ + tlp_pattern *node = pat, *temp; + + while (node != NULL) + { + temp = node->next; + tlp_pattern_free(node); + node = temp; + } + + pat = NULL; +} + +/* }}} */ + +/* remaining stuff used in tlp_src processing {{{ */ + +tlp_result tlp_str_get_word(tlp_str str, tlp_str word, int max) +{ + int i, j; + + /* skip all leading spaces */ + for (i = 0; tlp_char_is_space(str[i]); i++) + ; + + j = 0; + for (; ! tlp_char_is_eol(str[i]); i++) + { + if (str[i] != TLP_CHAR('-') && + ! tlp_char_in_word(str[i])) + return TLP_FAILED; + + if (j >= max) + return TLP_FAILED; + + word[j++] = str[i]; + } + + if (j == 0) + return TLP_FAILED; + + word[j] = TLP_CHAR_END; + return TLP_OK; +} + +/* }}} */ + +/* vim:set ts=4 sts=4 sw=4 expandtab foldmethod=marker: */ diff --git a/Master/tlpkg/dev/lib/C/tlp-src.h b/Master/tlpkg/dev/lib/C/tlp-src.h new file mode 100644 index 00000000000..cf04de32dc7 --- /dev/null +++ b/Master/tlpkg/dev/lib/C/tlp-src.h @@ -0,0 +1,75 @@ +/* tlp-src.h - header for using tlpsrc files + * + * Copyright 2007 Jjgod Jiang + * Derived from the Perl implementation by Norbert Preining + * + * This file is licensed under the GNU General Public License version 2 + * or any later version. */ + +#ifndef __TLP_SRC__ +#define __TLP_SRC__ + +#include <tlp-utils.h> + +enum tlp_src_limits { + TLP_SRC_LINE_MAX = 1024, + TLP_SRC_NAME_MAX = 256, +}; + +enum tlp_pattern_type { + TLP_PATTERN_T, TLP_PATTERN_F, + TLP_PATTERN_D, TLP_PATTERN_R +}; + +typedef struct tlp_pattern { + enum tlp_pattern_type type; + + union { + tlp_str_list *t; + tlp_str f; + tlp_str d; + tlp_str r; + } u; + + struct tlp_pattern *next; +} tlp_pattern; + +typedef struct tlp_src { + /* name of the package */ + tlp_str name; + /* Collection Scheme TLCore Package Documentation */ + tlp_str category; + /* short one line desc */ + tlp_str shortdesc; + /* longer multiline dscription */ + tlp_str longdesc; + /* name of the respective Catalogue entry */ + tlp_str catalogue; + + tlp_pattern *runpatterns; + tlp_pattern *srcpatterns; + tlp_pattern *docpatterns; + tlp_pattern *binpatterns; + + tlp_execute *executes; + tlp_depend *depends; +} tlp_src; + +tlp_src *tlp_src_new(tlp_str name, + tlp_str category, + tlp_str shortdesc, + tlp_str longdesc, + tlp_str catalogue, + tlp_pattern *runpatterns, + tlp_pattern *srcpatterns, + tlp_pattern *docpatterns, + tlp_pattern *binpatterns, + tlp_execute *executes, + tlp_depend *depends); + +void tlp_src_free(tlp_src *src); +void tlp_patterns_free(tlp_pattern *pat); +void tlp_pattern_free(tlp_pattern *pat); + +#endif + diff --git a/Master/tlpkg/dev/lib/C/tlp-utils.c b/Master/tlpkg/dev/lib/C/tlp-utils.c new file mode 100644 index 00000000000..864b7a0597c --- /dev/null +++ b/Master/tlpkg/dev/lib/C/tlp-utils.c @@ -0,0 +1,182 @@ +/* tlp-utils.h - module for general tlp utilities + * + * Copyright 2007 Jjgod Jiang + * Derived from the Perl implementation by Norbert Preining + * + * This file is licensed under the GNU General Public License version 2 + * or any later version. */ + +#include <tlp-utils.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +tlp_str tlp_str_from_bytes(const char *bytes) +{ + return (tlp_str) strdup(bytes); +} + +tlp_str tlp_str_copy(tlp_str str) +{ + if (str == NULL) + return NULL; + + return strdup(str); +} + +void tlp_str_free(tlp_str str) +{ + free(str); +} + +tlp_str_list *tlp_str_list_new() +{ + tlp_str_list *list = tlp_new(tlp_str_list); + if (list == NULL) + return NULL; + + list->head = list->tail = NULL; + return list; +} + +tlp_str_list *tlp_str_list_from_array(const char *array[]) +{ + tlp_str_list *list = tlp_str_list_new(); + int i, size; + + if (list == NULL) + return NULL; + + size = sizeof(array) / sizeof(array[0]); + for (i = 0; i < size; i++) + if (tlp_str_list_append_bytes(list, array[i]) != TLP_OK) + { + tlp_str_list_free(list); + return NULL; + } + + return list; +} + +tlp_result tlp_str_list_append(tlp_str_list *list, tlp_str str) +{ + tlp_str_list_node *node = tlp_new(tlp_str_list_node); + + if (node == NULL) + return TLP_FAILED; + + node->str = str; + node->next = NULL; + + if (list->head == NULL) + list->head = node; + + if (list->tail == NULL) + list->tail = node; + + else + { + list->tail->next = node; + list->tail = node; + } + + return TLP_OK; +} + +tlp_result tlp_str_list_append_bytes(tlp_str_list *list, const char *bytes) +{ + tlp_str str = tlp_str_from_bytes(bytes); + if (str == NULL) + return TLP_FAILED; + + return tlp_str_list_append(list, str); +} + +void tlp_str_list_free(tlp_str_list *list) +{ + tlp_str_list_node *node = list->head, *temp; + + while (node != NULL) + { + temp = node->next; + + tlp_str_free(node->str); + free(node); + + node = temp; + } + + free(list); + list = NULL; +} + +tlp_str tlp_fgets(tlp_str s, int n, FILE *fp) +{ + return (tlp_str) fgets((char *) s, n, fp); +} + +void tlp_str_output(FILE *fp, tlp_str str) +{ + fprintf(stderr, "%s", (char *) str); +} + +size_t tlp_str_len(tlp_str str) +{ + return strlen((const char *) str); +} + +int tlp_str_start_with(tlp_str str, tlp_str prefix) +{ + int len = tlp_str_len(prefix); + + if (tlp_str_len(str) < len) + return 0; + + return strncmp((const char *) str, + (const char *) prefix, len); +} + +int tlp_str_start_with_bytes(tlp_str str, const char *prefix) +{ + tlp_str prefix_str; + int ret; + + prefix_str = tlp_str_from_bytes(prefix); + if (prefix_str == NULL) + return 0; + + ret = tlp_str_start_with(str, prefix_str); + + tlp_str_free(prefix_str); + return ret; +} + +int tlp_char_is_space(tlp_char ch) +{ + return isspace((int) ch); +} + +int tlp_char_is_eol(tlp_char ch) +{ + return (ch == '\r' || ch == '\n'); +} + +int tlp_char_in_word(tlp_char ch) +{ + return (isalnum(ch) || ch == '_'); +} + +void tlp_error_msg(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void tlp_error_str(tlp_str str) +{ + tlp_str_output(stderr, str); +} + diff --git a/Master/tlpkg/dev/lib/C/tlp-utils.h b/Master/tlpkg/dev/lib/C/tlp-utils.h new file mode 100644 index 00000000000..a2332bf8d4f --- /dev/null +++ b/Master/tlpkg/dev/lib/C/tlp-utils.h @@ -0,0 +1,73 @@ +/* tlp-utils.h - header for general tlp definitions + * + * Copyright 2007 Jjgod Jiang + * Derived from the Perl implementation by Norbert Preining + * + * This file is licensed under the GNU General Public License version 2 + * or any later version. */ + +#ifndef __TLP_UTILS__ +#define __TLP_UTILS__ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +typedef char tlp_char; +typedef tlp_char *tlp_str; + +#define TLP_CHAR(x) ((tlp_char) x) + +enum tlp_special_chars { + TLP_CHAR_COMMENT = TLP_CHAR('#'), + TLP_CHAR_END = TLP_CHAR('\0'), +}; + +typedef struct tlp_str_list_node { + tlp_str str; + struct tlp_str_list_node *next; +} tlp_str_list_node; + +typedef struct tlp_str_list { + struct tlp_str_list_node *head; + struct tlp_str_list_node *tail; +} tlp_str_list; + +typedef tlp_str_list tlp_execute; +typedef tlp_str_list tlp_depend; + +#define tlp_executes_free(x) tlp_str_list_free(x) +#define tlp_depends_free(x) tlp_str_list_free(x) + +typedef enum tlp_result { + TLP_FAILED = 0, TLP_OK = 1 +} tlp_result; + +#define tlp_new(x) ((x *) malloc(sizeof(x))) + +tlp_str tlp_str_from_bytes(const char *bytes); +tlp_str tlp_str_copy(tlp_str str); +void tlp_str_free(tlp_str str); + + +tlp_str_list *tlp_str_list_new(); +tlp_str_list *tlp_str_list_from_array(const char *array[]); +tlp_result tlp_str_list_append(tlp_str_list *list, tlp_str str); +tlp_result tlp_str_list_append_bytes(tlp_str_list *list, const char *bytes); +void tlp_str_list_free(tlp_str_list *list); + +tlp_str tlp_fgets(tlp_str s, int n, FILE *fp); +size_t tlp_str_len(tlp_str str); +void tlp_str_output(FILE *fp, tlp_str str); +int tlp_str_start_with(tlp_str str, tlp_str prefix); +int tlp_str_start_with_bytes(tlp_str str, const char *prefix); + +int tlp_char_is_space(tlp_char ch); +int tlp_char_is_eol(tlp_char ch); +int tlp_char_in_word(tlp_char ch); + +void tlp_error_msg(const char *fmt, ...); +void tlp_error_str(tlp_str str); + +#endif + diff --git a/Master/tlpkg/dev/lib/bash/TeXLiveInfra.sh b/Master/tlpkg/dev/lib/bash/TeXLiveInfra.sh new file mode 100644 index 00000000000..f3eca766017 --- /dev/null +++ b/Master/tlpkg/dev/lib/bash/TeXLiveInfra.sh @@ -0,0 +1,261 @@ +# $Id$ +# TeXLiveInfra.sh - shell library for the access to TLDB and TLP +# +# Copyright 2007 Norbert Preining +# This file is licensed under the GNU General Public License version 2 +# or any later version. + +die() { + echo $* + exit 1 +} + +test_tlp() { + tlpfile="$1" + if [ ! -r "$tlpfile" ] ; then + die "tlp file not readable: $tlpfile" + fi +} + +# we read the whole tlp again and again +# if we could use some multi-line grepping this could be speed up +# but I guess we would need perl regexp grepping +# BETTER: use an awk program for this, but I am not able to write +# such an awk program. And do we have it available everywhere? +_tlp_get_multi() { + entry="$1" + tlpfile="$2" + arch="$3" + test_tlp "$tlpfile" + ( SAVEDIFS=$IFS ; IFS= ; cat "$tlpfile" | __tlp_get_multi "$entry" "$arch" ) +} +__tlp_get_multi() { + entry="$1" + arch="$2" + if [ "$arch" = "" ] ; then + pat="$entry*" + else + pat="$entry*arch=$arch*" + fi + reading_multi=0 + while read line ; do + case "$line" in + $pat) + reading_multi=1 + ;; + \ *) + if [ $reading_multi = 1 ] ; then + ( IFS=$SAVEDIFS ; echo $line ) + fi + ;; + *) + if [ $reading_multi = 1 ] ; then + # we already have read the interesting part, return now + return + fi + ;; + esac + done +} + +_tlp_get_multi_simple() { + entry="$1" + tlpfile="$2" + test_tlp "$tlpfile" + grep "^$entry" "$tlpfile" | sed -e "s@^$entry[ \t]*@@" +} + +_tlp_get_simple() { + entry="$1" + tlpfile="$2" + field="$3" + prefix="$4" + test_tlp "$tlpfile" + cat "$tlpfile" | __tlp_get_simple $entry $field $prefix +} + +__tlp_get_simple() { + entry="$1" + field="$2" + prefix="$3" + if [ "$field" = "" ] ; then + grep -m 1 "^$entry " | sed -e "s@^$entry[ \t]*@@" | sed -e "s@^$prefix@@" + else + grep -m 1 "^$entry " | awk "{print\$${field}}" | sed -e "s@^$prefix@@" + fi +} + +tlp_get_name() +{ + _tlp_get_simple name "$1" +} +tlp_get_revision() +{ + _tlp_get_simple revision "$1" +} +tlp_get_category () +{ + _tlp_get_simple category "$1" +} +tlp_get_shortdesc () +{ + _tlp_get_simple shortdesc "$1" +} +tlp_get_catalogue () +{ + _tlp_get_simple catalogue "$1" +} +tlp_get_longdesc () +{ + _tlp_get_multi longdesc "$1" +} +tlp_get_depends () +{ + _tlp_get_multi_simple depend "$1" +} +tlp_get_executes () +{ + _tlp_get_multi_simple execute "$1" +} +tlp_get_srcfiles () +{ + _tlp_get_multi srcfiles "$1" +} +tlp_get_docfiles () { + _tlp_get_multi docfiles "$1" +} +tlp_get_runfiles () { + _tlp_get_multi runfiles "$1" +} +tlp_get_srcsize () { + _tlp_get_simple srcfiles "$1" 2 "size=" +} +tlp_get_docsize () +{ + _tlp_get_simple docfiles "$1" 2 "size=" +} +tlp_get_runsize () +{ + _tlp_get_simple runfiles "$1" 2 "size=" +} + +tlp_get_binsize () +{ + tlpfile="$1" + arch="$2" + _tlp_get_simple "binfiles[ \t]*arch=$arch" "$1" 3 "size=" +} +tlp_get_binfiles () +{ + _tlp_get_multi binfile "$1" "$2" +} + +tlp_get_available_arch () +{ + test_tlp "$tlpfile" + grep 'binfiles[ \t]*arch=' "$tlpfile" | awk '{print$2}' | sed -e 's/arch=//' +} + +test_tldb() { + tldbfile="$1" + if [ ! -r "$tldbfile" ] ; then + die "tldb file not readable: $tldbfile" + fi +} + +_tldb_tlp_get_multi() +{ + tldb="$1" + tlp="$2" + entry="$3" + arch="$4" + test_tldb "$tldb" + foundpackage=0 + ( SAVEDIFS=$IFS ; IFS= ; while read line ; do + case "$line" in + name\ $tlp*) + foundpackage=1 + __tlp_get_multi $entry $arch + ;; + *) + if [ $foundpackage = 1 ] ; then + return + fi + ;; + esac + done ) <$tldb +} +_tldb_tlp_get_simple() +{ + tldb="$1" + tlp="$2" + entry="$3" + field="$4" + prefix="$5" + test_tldb "$tldb" + foundpackage=0 + ( SAVEDIFS=$IFS ; IFS= ; while read line ; do + case "$line" in + name\ $tlp*) + foundpackage=1 + __tlp_get_simple $entry $field $prefix + ;; + *) + if [ $foundpackage = 1 ] ; then + return + fi + ;; + esac + done ) <$tldb +} + + +tldb_tlp_get_revision() +{ + _tldb_tlp_get_simple "$1" "$2" revision "$3" "$4" +} +tldb_tlp_get_category () +{ + _tldb_tlp_get_simple "$1" "$2" category "$3" "$4" +} +tldb_tlp_get_shortdesc () +{ + _tldb_tlp_get_simple "$1" "$2" shortdesc "$3" "$4" +} +tldb_tlp_get_catalogue () +{ + _tldb_tlp_get_simple "$1" "$2" catalogue "$3" "$4" +} +tldb_tlp_get_longdesc () +{ + _tldb_tlp_get_multi "$1" "$2" longdesc "$3" +} +tldb_tlp_get_srcfiles () +{ + _tldb_tlp_get_multi "$1" "$2" srcfiles "$3" +} +tldb_tlp_get_docfiles () { + _tldb_tlp_get_multi "$1" "$2" docfiles "$3" +} +tldb_tlp_get_runfiles () { + _tldb_tlp_get_multi "$1" "$2" runfiles "$3" +} +tldb_tlp_get_binfiles () +{ + _tldb_tlp_get_multi "$1" "$2" binfile "$3" +} + +tldb_get_installed_packages () +{ + tldb="$1" + test_tldb "$tldb" + grep ^name "$tldb" | awk '{print$2}' +} + + +### Local Variables: +### perl-indent-level: 4 +### tab-width: 4 +### indent-tabs-mode: t +### End: +# vim:set tabstop=4: # diff --git a/Master/tlpkg/dev/lib/python/TeXLive.py b/Master/tlpkg/dev/lib/python/TeXLive.py new file mode 100644 index 00000000000..fe302acee9b --- /dev/null +++ b/Master/tlpkg/dev/lib/python/TeXLive.py @@ -0,0 +1,1744 @@ +#!/usr/bin/python2.4 -u +# TeXLive.py +# -*- encoding: utf-8 -*- +# Usage: call with argument of --help +# 2007-Aug-05 Jim Hefferon ftpmaint@tug.ctan.org +"""Understand a TeX Live package and the associated dB file. + +TeX Live has a format for metadata located in trunk/Master/tlpkg (for +the 'src' packages and documentation of the format) and +trunk/Master/texlive.tlpdb (see also -withctan ?). This module reads the +two formats, can transform them by adding package documentation from the +ctanWeb database, and can write them back out. + +""" +__version__='1.0.0' +__author__='Jim Hefferon' +__date__='2007-Aug-05' +__notes__=""" +Bugs: +1) Does not expand patterns for the src module, and does not + redo the sizes, etc., for obj files. +2) You can't from the command line change the name of the db files. +3) This version for the TeX Live svn tree has the dB stripped out, so + the option -a doesn't work, and the option -n has no effect. +""" + +import os, os.path, sys +import re +import optparse +import codecs +import tempfile +import time +import pprint +import glob + +## import library +## from util import * +## import dBUtils +## from defaults import DEFAULT_ENCODING, DEFAULT_DATABASE_ENCODING, DEBUG, LOGGING +DEFAULT_ENCODING='UTF-8' + +TLPDB_FILENAME='/home/svn/texlive/trunk/Master/texlive.tlpdb' + +THIS_SCRIPT=sys.argv[0] +DEBUG=True +LOGGING=True +LOGFILE_NAME=os.path.splitext(os.path.basename(THIS_SCRIPT))[0]+'.log' +VERBOSE=True + +# What encoding for the terminal? +import locale +locale_language, locale_output_encoding = locale.getdefaultlocale() +if locale_output_encoding is None: + locale_output_encoding='UTF-8' + + +#---------------------- stuff from util.py +import StringIO # for msg +import traceback # for msg +import logging # for openLog, msg +import locale # for warn messages +import types + +import grp, pwd # get user name and group name + +import pprint # to make nice debugging structures + +termEncoding='UTF-8' + +class utilError(StandardError): + pass + +# Getting the string from the exception is a problem if you want unicode, +# since str() is no good for that, and I can't get err.message to work. +# I need the same functionality for my exceptions as for Python's so +# I wrap a call to err[0] +def errorValue(err): + """Return the string error message from an exception. + err exception instance + Note: I cannot get err.message to work. I sent a note to clp on + Jan 29 2007 with a related query and this is the best that I figured + out. + """ + try: + return str(err) + except: + return err[0] # one of mine, in unicode + +class jhError(StandardError): + """Subclass this to get exceptions that behave correctly when + you do this. + try: + raise subclassOfJhError, 'some error message with unicode chars' + except subclassOfJhError, err + mesg='the message is '+unicode(err) + I don't believe that the built-in exceptions ever pass unicode so you can + use unicode(err) on those also, I think, provided that you don't + raise them yourself. + """ + def __unicode__(self): + return errorValue(self) + +# You can use a string to set the level, or a constant from the logging +# module +_logLevels={'debug':logging.DEBUG, + 'info':logging.INFO, + 'warn':logging.WARN, + 'error':logging.ERROR, + 'critical':logging.CRITICAL, + logging.DEBUG:logging.DEBUG, + logging.INFO:logging.INFO, + logging.WARN:logging.WARN, + logging.WARN:logging.ERROR, + logging.CRITICAL:logging.CRITICAL} + + +# openLog Open a logging instance +def openLog(fn,name=None,purpose=None,format="%(levelname)s\t%(asctime)s: %(message)s",level=logging.DEBUG,announce=False): + """Open an instance of the logging module. Does not append to an old file; + instead it makes a new one. + fn Name of the file. + name=None Name of the logging instance; if None then fn is used + purpose=None Name of calling program; if None then no head line on log + file is written + format='%(levelname)s %(asctime)s: %(message)s' Format for log file + entries + announce=False Announce in log file that logging has started + These are available for the format: + %(name)s Name of the logger (logging channel) + %(levelno)s Numeric logging level for the message (DEBUG, INFO, + WARN, ERROR, CRITICAL) + %(levelname)s Text logging level for the message ("DEBUG", "INFO", + "WARN", "ERROR", "CRITICAL") + %(pathname)s Full pathname of the source file where the logging + call was issued (if available) + %(filename)s Filename portion of pathname + %(module)s Module (name portion of filename) + %(lineno)d Source line number where the logging call was issued + (if available) + %(created)f Time when the LogRecord was created (time.time() + return value) + %(asctime)s Textual time when the LogRecord was created + %(msecs)d Millisecond portion of the creation time + %(relativeCreated)d Time in milliseconds when the LogRecord was created, + relative to the time the logging module was loaded + (typically at application startup time) + %(thread)d Thread ID (if available) + %(message)s The result of record.getMessage(), computed just as + the record is emitted + May raise a utilError. + """ + if not(purpose is None): # write a header on the file, if it is new + if not(os.path.isfile(fn)): + try: + f=open(fn,'w') + f.write("# log file for %s\n" % (purpose,)) + f.close() + except IOError, err: + raise utilError, "Log file %s not present and unable to open and write to a new log file: %s" % (fn,errorValue(err)) + if name is None: + log=logging.getLogger(fn) + else: + log=logging.getLogger(name) + logger_formatter=logging.Formatter(format) + try: + logger_handler=logging.FileHandler(fn) + except Exception, err: + raise utilError, "Unable to associate a log with %s: %s" % (fn,errorValue(err)) + logger_handler.setFormatter(logger_formatter) + log.addHandler(logger_handler) + try: + log.setLevel(_logLevels[level]) + except: + raise utilError, "Unable to set level of the log" + if announce: + try: + log.info("Logging started") + except Exception, err: + raise utilError, "Unable to initially write to the log with file name %s: %s" % (fn,errorValue(err)) + return log + +# msg return a message, for debugging, feedback to the user, etc., and +# optionally log +def msg(m,devel=None,log=None,logLevel='debug',debug=False,**mDct): + """Return a message. Options allow it to be logged, or for a special + debugging flag to be switched to give additional information + m The message returned. Substitutions from the keyword arguments at end + devel=None String that will be used if the DEBUG flag is set for + developer (and used for writing to the log). If devel=None, then m + is used. + log A logging object + logLevel='debug' One of 'debug', 'info', 'warn', 'error', 'critical', + or logging.DEBUG, .. logging.CRITICAL + debug=False Boolean select which message m or mDevel is shown. + **mDct Keyword argument that are substituted into m and mDevel + Note that if an exception is pending then a traceback gets printed to the + log file. + """ + # Indicate log level + try: + level=_logLevels[logLevel] + except: + raise utilError, "Unable to set level of the log to %s" % (repr(logLevel),) + # The main part + if devel is None: + devel_str=m + else: + devel_str=devel + #if log: + # log.debug("in msg: m=<%s>, devel_str=<%s>" % (m,devel_str)) + if log: + (excClass,excObj,excTb)=sys.exc_info() # is there a pending exception? + if excClass: + tbStr=StringIO.StringIO() + traceback.print_exc(None,tbStr) + mDct['tB']=tbStr.getvalue().rstrip() + log.log(level,(devel_str+"\n %(tB)s") % mDct) + else: + log.log(level,devel_str % mDct) + if debug: + m=devel_str + # expect that everybody needs to be encoded; print can't do characters numbered greater than 128 + for (k,v) in mDct.items(): + try: + if not(isinstance(v,UnicodeType)): + mDct[k]=unicode(v,termEncoding,'replace') + except: + try: + mDct[k]=unicode(str(v),termEncoding,'replace') #? has no unicode method, but has a str method? Like StandardError? + except: + mDct[k]="Error in util.msg() -- string conversion to unicode impossible: %s" % (repr(v),) # give a message with some hint of what's gone wrong + return m % mDct + + +DEFAULT_EXCEPTION=utilError +WARNINGS_WANTED=False # sometimes, as for unit testing, nice to turn off +def noteException(m,devel=None,log=None,logLevel='error',exception=DEFAULT_EXCEPTION,debug=None,**mDct): + """ + Raise an exception, and also, optionally, note it in a log file + m string Error message for users; use '%(id)s'-style substitution + devel=None string String for development; sub as in m. + log Instance of logging module + exception An exception + debug Print the error to the stderr? + **mDct Additional keyword arguments; like 'id=7' will be subbed into + m, devel + Uses the msg function; will raise exception. + """ + # print "util.py.noteException: m is: ",m," mDct is",pprint.pformat(mDct) + if sys.exc_info()[0]: # if there is an active exception + extraStr=" (exception is %s)" % (exceptionName(),) + if devel is None: + m+=extraStr + else: + devel+=extraStr + r=msg(m,devel=devel,log=log,logLevel=logLevel,debug=debug,**mDct) + if (debug + and not(log) + and WARNINGS_WANTED): + warn(r,log=None,debug=debug) # print to stderr + raise exception, r + +def warn(s,leader='WARNING: ',log=None,debug=False,**mDct): + """Send a message to stderr and possibly log it + s Message to report + log=None A logging object + debug=False Whether to report debugging information + Warning! You can't use leader, log, or debug as a key + """ + # print >>sys.stderr, leader, msg(s,log=log,logLevel='error',debug=debug,**mDct).encode(locale.getdefaultlocale()[1]) + if not(isinstance(s,types.UnicodeType)): + s=unicode(s,termEncoding,'replace') + # print "in warn(): s=",s," and mDct.keys() is ",repr(mDct.keys()),"<<<<<===" + print >>sys.stderr, leader, msg(s,log=log,logLevel='error',debug=debug,**mDct).encode(termEncoding) + return None + +def ann(s,log=None,debug=False,**mDct): + """Issue a warning-like message without the 'WARNING' message. + s Message to report; may contain %(var)s as long as they are matched + by var=var in the tailing arguments + log=None,debug=False debugging stuff + **mDct variables to substitute in s + """ + return warn(s,leader='',log=log,debug=debug,**mDct) + +def note(s,log,flag=os.environ.has_key('GATEWAY_INTERFACE'),leader="NOTE: "): + """Take the message s and either log it or print it, depending + on the flag. The idea is to debug with note('informational message',log) + and have it do the right thing, in a cgi context or not. + s message to use + log logging instance + flag=os.environ.has_key('GATEWAY_INTERFACE') if True, use log. If + False, use stdout (default is True iff running as a CGI script) + """ + # programming note: + # I've avoided too many options, such as potentially outputting + # to stderr or using another log level; we'll see if simple works. + if flag and log: + log.info(s) + else: + warn(s,leader=leader,log=log) # no debug because no devel string + + +def fail(s,returnCode=1,log=None,debug=False,**mDct): + """Drop out, reporting a return code, and possibly logging a message + s Message to report + returnCode=1 return code + log=None A logging object + debug=False Whether to report debugging information + Warning! You can't use returnCode, leader, log, or debug as a key + """ + warn(s,leader='ERROR: ',log=log,debug=debug,**mDct) + sys.exit(returnCode) + +# exceptionName: get the name of the raised exception +# for use as: +# try: +# .. +# except specificError, err: +# .. +# except Exception, err: +# eN=exceptionName() +# print "exception was",eN +# +def exceptionName(): + """Get the name of the currently raised exception. + """ + fullName=sys.exc_info()[0] # looks like "'exceptions.AttributeError'" + if fullName is None: + return 'No exception' # return rather than None, as I don't expect it to happen, and I don't want the failure if it is None + else: + return str(fullName).split('.')[-1] +#---------------------------------------- + +#-------------------------------stuff from dButils.py +## import psycopg2, psycopg2.extensions + +## DEFAULT_DBCONNECTION_STRING="user=hefferon dbname=ctan password=Gd6eBitK55y" +## DEFAULT_DATABASE_ENCODING='UTF-8' + +## dBConnectionString=DEFAULT_DBCONNECTION_STRING # can be force-changed for debugging + +## class dBUtilsError(StandardError): +## pass + +## def opendB(connectionstring=dBConnectionString,log=None,debug=DEBUG,encoding=DEFAULT_DATABASE_ENCODING,utc=True): +## """ +## Make a connection to the database; return the pair (connection, cursor). +## connectionstring=dBConnectionstring string See doc for psycopg +## log=None logging object +## debug=DEBUG Whether to output extra information +## encoding='UNICODE' What to set the client encoding to (default is utf-8) +## utc=True Set time zone to utc (alternative is local time) +## May raise a dBUtilsError. +## """ +## if encoding.upper()=='UTF-8': +## encoding='UNICODE' # postgres's name for UTF-8 +## if not(encoding in psycopg2.extensions.encodings.keys()): +## mesg=u'Unable to make a database connection' +## noteException(mesg,devel=mesg+" using connection string %(connectionstring)s because the called-for encoding %(encoding)s is not one known to psycopg2",log=log,exception=dBUtilsError,debug=debug,connectionstring=connectionstring,encoding=encoding) +## try: +## dBcnx = psycopg2.connect(connectionstring) +## # dBcnx.set_client_encoding(encoding) # causes a failure JH 05-10-12 +## dBcsr = dBcnx.cursor() +## if utc: +## dBcsr.execute("SET TIME ZONE 'UTC'") +## dBcsr.execute("SET client_encoding TO "+encoding) +## if encoding=='UNICODE': # any way to systematize this code? +## psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) +## elif encoding=='LATIN1': +## psycopg2.extensions.register_type(psycopg2.extensions.LATIN1) +## elif encoding=='SQL_ASCII': +## psycopg2.extensions.register_type(psycopg2.extensions.SQL_ASCII) +## elif encoding=='latin-1': +## psycopg2.extensions.register_type(psycopg2.extensions.LATIN1) +## except psycopg2.DatabaseError, err: +## mesg=u'Unable to connect to the database' +## noteException(mesg,devel=mesg+" using connection string %(connectionstring)s: %(err)s",log=log,exception=dBUtilsError,debug=debug,connectionstring=connectionstring,err=err) +## except Exception, err: +## eN=exceptionName() +## mesg=u'Unable to connect to the database' +## noteException(mesg,devel=mesg+" (exception: %(eN)s) using connection string %(connectionstring)s: %(err)s",log=log,exception=dBUtilsError,debug=debug,eN=eN,connectionstring=connectionstring,err=err) +## return (dBcnx,dBcsr) + +## def getData(sql,dct={},dBcsr=None,selectOne=False,log=None,debug=DEBUG,listtype='list from the database'): +## """ +## Get data out of the database, returning a list of lists +## sql SQL statement; typically a SELECT statement +## dct={} Dictionary of substitutions into SQL statement (unicode strings +## are encoded according to the encoding) +## dBcsr=None database cursor. If None, one will be generated +## log=None Instance of logging object +## selectOne=False With a dB result, issue a fetchone() or a fetchall()? +## debug=DEBUG Whether to include debugging information +## listtype Phrase for use in error messages +## Psycopg2 will handle conversion of unicode strings. +## """ +## if not(dBcsr): # sanity check +## mesg=u'Error getting access to the database' +## noteException(mesg,devel=mesg+": no database cursor, while getting a %(listtype)s",log=log,exception=dBUtilsError,debug=debug,listtype=listtype) +## try: +## dBcsr.execute(sql,dct) +## if selectOne: +## dBres=dBcsr.fetchone() +## if dBres is None: +## lst=[] # an empty list so always yield a sequence +## else: +## lst=dBres # one tuple +## else: +## lst=dBcsr.fetchall() # a list with possibly many tuples +## except psycopg2.DatabaseError, err: +## mesg=u'Database operation error fetching a %(listtype)s' +## noteException(mesg,devel=mesg+" with query "+dBcsr.query+": %(err)s -- "+dBcsr.statusmessage,log=log,exception=dBUtilsError,debug=debug,listtype=listtype,sql=sql,dct=repr(dct),err=err) +## except Exception, err: +## eN=exceptionName() +## noteException("Database error (unknown kind) fetching a %(listtype)s",devel="Database error (exception %(eN)s) fetching a %(listtype)s with sql='%(sql)s' and dct=%(dct)s: %(err)s",log=log,exception=dBUtilsError,debug=debug,listtype=listtype,eN=eN,err=err) +## return lst + +## def putData(sql,dct={},dBcsr=None,log=None,encoding=DEFAULT_DATABASE_ENCODING,debug=DEBUG,listtype='list to the database'): +## """ +## Put data into the database, encoding unicode strings on their way in +## sql SQL statement; should be an INSERT or an UPDATE +## dct={} Dictionary of substitutions into SQL statement (unicode strings +## are encoded according to the encoding) +## dBcsr=None database cursor. If None, one will be generated +## log=None Instance of logging object +## encoding=DEFAULT_DATABASE_ENCODING Unicode encoding to use for the +## database +## debug=DEBUG Whether to include debugging information +## listtype Phrase for use in error messages +## Does *not* do a dBcsr.commit(). +## """ +## if not(dBcsr): # sanity check +## mesg=u'Error accessing the database' +## noteException(mesg,devel=mesg+" while putting a %(listtype)s: no database cursor",log=log,exception=dBUtilsError,debug=debug,listtype=listtype) +## try: +## dBcsr.execute(sql,dct) +## except (psycopg2.DatabaseError,psycopg2.ProgrammingError), err: +## eN=exceptionName() +## mesg=u'Database operation error' +## noteException(mesg,devel=mesg+" (exception %(eN)s) %(err)s while putting a %(listtype)s with query="+dBcsr.query+": %(err)s -- "+dBcsr.statusmessage,log=log,exception=dBUtilsError,debug=debug,listtype=listtype,eN=eN,err=err) +## except Exception, err: +## eN=exceptionName() +## mesg=u'Database operation error' +## noteException(mesg,devel=mesg+" (exception %(eN)s) %(err)s while putting a %(listtype)s",log=log,exception=dBUtilsError,debug=debug,eN=eN,err=str(err),listtype=listtype) +## return None + +#------------------------------------------------- + +class tlError(jhError): + pass + +tlobjKeys=set(['name','category','catalogue','shortdesc','longdesc','depend','execute','revision','srcsize','srcfiles','docsize','docfiles','runsize','runfiles','binsize','binfiles','cataloguedata','srcpattern','runpattern','docpattern','binpattern']) + +class tlp(object): + """Give information based on a TeXLive object file + """ + def __init__(self,verbose=False,log=None,debug=False): + """Initialize an object. + """ + self.verbose=verbose + self.log=log + self.debug=debug + self.name=None # string id of package + self.category=None # string category into which package falls + self.catalogue=None # string id of associated Catalogue package + self.shortdesc=None # string one-liner + self.longdesc=None # string may have newlines + self.depend=None # list of the form Category/Name + self.execute=None # list free-form strings + return None + + def __unicode__(self): + r=[] + r.append("name: %s" % (pprint.pformat(self.name),)) + r.append(" category: %s" % (pprint.pformat(self.category),)) + r.append(" catalogue: %s" % (pprint.pformat(self.catalogue),)) + r.append(" shortdesc: %s" % (pprint.pformat(self.shortdesc),)) + r.append(" longdesc: %s" % (pprint.pformat(self.longdesc),)) + r.append(" depend: %s" % (pprint.pformat(self.depend),)) + r.append(" execute: %s" % (pprint.pformat(self.execute),)) + return "\n".join(r) + + def writeout(self,fn=None): + """Write a textual representation + fn=None file name; if None use sys.stdout + """ + if fn is None: + f=sys.stdout + if f.encoding!=DEFAULT_ENCODING: + warn('using STDOUT but the encoding is %(fEncoding)s and not the expected %(defaultEncoding)s',log=self.log,debug=self.debug,fEncoding=repr(f.encoding),defaultEncoding=repr(DEFAULT_ENCODING)) + else: + if self.debug: + errors='strict' + else: + errors='replace' + try: + f=codecs.open(fn,'w',DEFAULT_ENCODING,errors) + except Exception, err: + mesg='unable to open the file for writing' + noteException(mesg,devel=mesg+' %(fn)s: %(err)s',exception=tlError,log=log,debug=self.debug,fn=repr(fn),err=unicode(err)) + self.writeout_fh(f) + f.close() + return None + + def _stringToWriteout(self): + """String that will be written out during writeout_fh + """ + r=[] + r.append("name %s" % (self.name,)) + if self.category: + r.append("category %s" % (self.category,)) + if self.shortdesc: + r.append("shortdesc %s" % (self.shortdesc,)) + if self.longdesc: + for line in self.longdesc.split("\n"): + r.append("longdesc %s" % (line,)) + if self.depend: + for line in self.depend: + r.append("depend %s" % (line,)) + if self.execute: + for line in self.execute: + r.append("execute %s" % (line,)) + return "\n".join(r) + + def writeout_fh(self,f): + """Write a string representation of the user variables to the + filehandle. + f filehandle + """ + s=self._stringToWriteout() + f.write(s) + return None + + def get_associated_cat_ids(self,dBcsr,log=None,debug=False): + """Return the matching catalogue ids + """ + sql="""SELECT pkg_id FROM tl_cat + WHERE tl_id=%(tlId)s + AND pkg_id IS NOT NULL""" + dct={'tlId':self.name} + try: + dBres=dBUtils.getData(sql,dct=dct,dBcsr=dBcsr,log=log,debug=debug,listtype='get catalogue package ids related to this TeX Live package id') + except dBUtils.dBUtilsError, err: + mesg=u'unable to get texlive-catalogue packages record' + noteException(mesg,devel=mesg+' for TeX Live package %(tlId)s: %(err)s',exception=tlError,log=log,debug=debug,tlId=repr(tlId),err=errorValue(err)) + return [catId for (catId,) in dBres] + + def add_cat_desc(self,dBcsr,catId=None,log=None,debug=False): + """If there is not now a description, and there is a matching + Catalogue package, add its descriptions. (Also sets the catalogue + variable) + dBcsr database cursor + catId=None string or None if present, the name of the Catalogue + package whose descriptions will be added. + log=None,debug=False debugging + """ + if not(catId): + catIds=self.get_associated_cat_ids(dBcsr,log=log,debug=debug) + if len(catIds)==1: + catId=catIds[0] + if not(catId): + return False + sql="""SELECT caption, description FROM pkg_text + WHERE id=%(catId)s + AND iso_code='en'""" + dct={'catId':catId} + try: + dBres=dBUtils.getData(sql,dct=dct,dBcsr=dBcsr,log=log,debug=debug,listtype='get catalogue descriptions related to this TeX Live package id') + except dBUtils.dBUtilsError, err: + mesg=u'unable to get catalogue package descriptions for this TeX Live package' + noteException(mesg,devel=mesg+' for TeX Live package %(tlId)s and catalogue id %(catId)s: %(err)s',exception=tlError,log=log,debug=debug,tlId=repr(tlId),catId=repr(catId),err=errorValue(err)) + res=dBres[0] + if res: + (catCaption,catDesc)=dBres[0] + if (not(self.shortdesc) + and not(self.longdesc)): + self.catalogue=catId + self.shortdesc=catCaption + self.longdesc=catDesc + return True + + def from_file(self,fn=None,multi=False): + """Read a tlp object from a file. + fn=None string file name or None, which means sys.stdin + multi=False boolean whether to allow multiple pkgs in a file + """ + if fn is None: + f=sys.stdin + if f.encoding!=DEFAULT_ENCODING: + warn('using STDIN but the encoding is %(fEncoding)s and not the expected %(defaultEncoding)s',log=self.log,debug=self.debug,fEncoding=repr(f.encoding),defaultEncoding=repr(DEFAULT_ENCODING)) + else: + try: + if self.debug: + errors='strict' + else: + errors='replace' + f=codecs.open(fn,'rU',DEFAULT_ENCODING,errors) + except Exception, err: + mesg='unable to open file for reading' + noteException(mesg,devel=mesg+' %(fn)s: %(err)s',exception=tlError,log=log,debug=self.debug,fn=repr(fn),err=unicode(err)) + r=self.from_fh(f,multi=multi,lineNo=0) + return None + + initialState='init' + keyValueStates=tlobjKeys # line of form "key value" + filePathStates=set(['srcfiles_file','runfiles_file','docfiles_file','binfiles_file']) # line contains file path indented by space + nextStates={initialState:tlobjKeys, + 'name':keyValueStates-set(['name']), + 'category':keyValueStates-set(['category']), + 'catalogue':keyValueStates-set(['catalogue']), + 'shortdesc':keyValueStates-set(['shortdesc']), + 'longdesc':keyValueStates, + 'depend':keyValueStates, + 'execute':keyValueStates} + def from_fh(self,f,multi=None,lineNo=0): + """Read tlp information from a file handle. Returns None if EOF is + read before anything is found. Note that files have been opened + with codecs.open() (except for stdin) + f an opened file + multi=None If not None then multiple tplobj's in the file are + treated as an error + lineNo=0 debugging + May raise tlError. + """ + # Implementation note: I am putting the full parsing routine in + # this base class, except for some "handle" routines, to allow + # me to have the handle routines report error messages in the + # tplobj and tplsrc classes. + state=self.initialState + # Look for blank lines that are delimeters between tlp parts + anyNonblankLinesRead=False + while True: + line=f.readline() + if not(line): # EOF? + return False + lineNo+=1 + if self.debug and self.verbose: + note('line is '+repr(line),self.log) + line=line.rstrip() + if not(anyNonblankLinesRead): + if (not(line) + or line[0]=='#'): # toss initial blank lines or comments + continue + else: + anyNonblankLinesRead=True + elif not(line): + if multi is None: + mesg=u'unexpected multiple tpl objects' + noteException(mesg,devel=mesg+'; trailing blank line found at line %(lineNo)s',exception=tlError,log=self.log,debug=self.debug,lineNo=repr(lineNo)) + else: + return self + # Get the next state (the key) and the part of the line after key. + # The "srcfiles", etc., states need special handling as they + # put the reader in a position where the first thing on the line + # is not the next state. + restOfLine="" + if line[0]==' ': + if (state=='srcfiles' + or state=='srcfiles_file'): + newState='srcfiles_file' + restOfLine=line[1:] + elif (state=='runfiles' + or state=='runfiles_file'): + newState='runfiles_file' + restOfLine=line[1:] + elif (state=='docfiles' + or state=='docfiles_file'): + newState='docfiles_file' + restOfLine=line[1:] + elif (state=='binfiles' + or state=='binfiles_file'): + newState='binfiles_file' + restOfLine=line[1:] + else: + try: + fields=line.split() + newState=fields[0].lower() + restOfLine=line[len(newState):] # can't lstrip() if it is longdesc + except: + mesg=u'no key in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; while in state %(state)s unable to get the new state for line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),state=repr(state)) + # Reject illegal newState's + if not(newState=='binfiles_file'): + self.currentArch=None + if not(newState in self.nextStates[state]): + # print"newState",repr(newState),"state",repr(state),'self.nextStates[state]=',repr(self.nextStates[state])," type",repr(type(self.nextStates[state])) + mesg=u'unable to transition to the next state in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; while in state %(state)s the next state %(newState)s is not legal in line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),state=repr(state),newState=repr(newState)) + # Main part of routine: handle the line depending on the newState. + # if self.debug: + # print "newState is ",repr(newState)," line is ",repr(line) + if newState==self.initialState: + mesg=u'unexpected initial state in line=%(lineNo)s' + noteException(mesg,devel=mesg+'; while in state %(state)s now in initial state reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),state=repr(state)) + if newState=='name': + try: + fields=restOfLine.strip().split() + self.name=fields[0] + if self.debug: + note("package name is "+repr(self.name),self.log) + except Exception, err: + mesg=u'no "value" text in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s: %(err)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState),err=errorValue(err)) + elif newState=='category': + try: + fields=restOfLine.strip().split() + self.category=fields[0] + except: + mesg=u'no "value" text in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + elif newState=='catalogue': + try: + fields=restOfLine.strip().split() + self.catalogue=fields[0] + except: + mesg=u'no "value" text in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + elif newState=='shortdesc': + try: + # I'll allow multiline shortdesc's, although I'll regret it + if self.shortdesc is None: + self.shortdesc="" + if self.shortdesc: + self.shortdesc+=' ' + self.shortdesc+=restOfLine + except: + mesg=u'no value in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + elif newState=='longdesc': + try: + if self.longdesc is None: + self.longdesc="" + if self.longdesc: + self.longdesc+="\n" + self.longdesc+=restOfLine + except Exception, err: + mesg=u'no value in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s: %(err)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState),err=errorValuse(err)) + elif newState=='depend': + fields=restOfLine.strip().split() + if len(fields)>0: + if self.depend is None: + self.depend=[] + self.depend.append(restOfLine.strip()) + else: + mesg=u'no value in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + elif newState=='execute': + fields=restOfLine.strip().split() + if len(fields)>0: + if self.execute is None: + self.execute=[] + self.execute.append(restOfLine.strip()) + else: + mesg=u'no value in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + elif newState=='revision': + self.handleRevision(newState,restOfLine,line,lineNo) + elif newState=='srcfiles': + self.handleSrcfiles(newState,restOfLine,line,lineNo) + elif newState=='srcfiles_file': + self.handleSrcfilesFile(newState,restOfLine,line,lineNo) + elif newState=='docfiles': + self.handleDocfiles(newState,restOfLine,line,lineNo) + elif newState=='docfiles_file': + self.handleDocfilesFile(newState,restOfLine,line,lineNo) + elif newState=='runfiles': + self.handleRunfiles(newState,restOfLine,line,lineNo) + elif newState=='runfiles_file': + self.handleRunfilesFile(newState,restOfLine,line,lineNo) + elif newState=='binfiles': + self.handleBinfiles(newState,restOfLine,line,lineNo) + elif newState=='binfiles_file': + self.handleBinfilesFile(newState,restOfLine,line,lineNo) + elif newState=='srcpattern': + self.handleSrcpattern(newState,restOfLine,line,lineNo) + elif newState=='runpattern': + self.handleRunpattern(newState,restOfLine,line,lineNo) + elif newState=='docpattern': + self.handleDocpattern(newState,restOfLine,line,lineNo) + elif newState=='binpattern': + self.handleBinpattern(newState,restOfLine,line,lineNo) + elif newState.startswith('cataloguedata-'): + self.handleCataloguedata(newState,restOfLine,line,lineNo) + else: + mesg=u'unknown key in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; key is %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=repr(lineNo),line=repr(line),newState=repr(newState)) + # Cycle back to read next line + state=newState + return True + + def handleRevision(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'revision' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleSrcfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'srcfiles' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleSrcfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'srcfiles_file' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleDocfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'docfiles' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleDocfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'docfiles_file' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleRunfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'runfiles' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleRunfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'runfiles_file' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleBinfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'binfiles' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleBinfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'binfiles_file' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleSrcpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'srcpattern' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleRunpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'runpattern' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleDocpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'docpattern' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleBinpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'binpattern' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + def handleCataloguedata(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'cataloguedata-xxx' + """ + mesg=u'the new state is not allowed here, line number=%(lineNo)s' + noteException(mesg,devel=mesg+"; this object %(objName) cannot be in the state %(newState)s: line=%(line)s",exception=tlError,log=self.log,debug=self.debug,objName=repr(self.__class__.__name__),newState=repr(newState),lineNo=repr(lineNo),line=repr(line)) + return None + + +class tlp_db(object): + """Give information based on a tl file database. This class exists + for tlpobj_db and tlpsrc_db to inherit from + """ + def __init__(self,verbose=False,log=None,debug=False): + """Initialize an instance. + """ + self.verbose=verbose + self.log=log + self.debug=debug + self.value={} # map name --> tl pkg + return None + + def __unicode__(self): + names=self.value.keys() + names.sort() + return u" ".join(names) + + def get_package(self,name): + try: + return self.value[name] + except: + return None + + def _makeSingle(self): + """Helper fcn to make one of whatever self.value is holding multiple + of. Used in from_file. + """ + return tlp(log=self.log,debug=self.debug) + + def from_file(self,fn=None,multi=True): + """Read a tlp db file. Set self.value. + """ + if fn is None: + f=sys.stdin + if f.encoding!=DEFAULT_ENCODING: + warn('using STDIN but the encoding is %(fEncoding)s and not the expected %(defaultEncoding)s',log=self.log,debug=self.debug,fEncoding=repr(f.encoding),defaultEncoding=repr(DEFAULT_ENCODING)) + else: + if self.debug: + errors='strict' + else: + errors='replace' + try: + f=codecs.open(fn,'rU',DEFAULT_ENCODING,errors) + except Exception, err: + mesg='unable to open tlpobj file' + noteException(mesg,devel=mesg+' %(fn)s: %(err)s',exception=tlError,log=log,debug=self.debug,fn=repr(fn),err=unicode(err)) + r=self._makeSingle() + retVal=r.from_fh(f,multi=multi,lineNo=0) + self.value[r.name]=r + while retVal: + r=self._makeSingle() + retVal=r.from_fh(f,multi=multi,lineNo=0) + self.value[r.name]=r + return None + + def write_file(self,fn=None): + if fn is None: + f=sys.stdout + if f.encoding!=DEFAULT_ENCODING: + warn('using STDOUT but the encoding is %(fEncoding)s and not the expected %(defaultEncoding)s',log=self.log,debug=self.debug,fEncoding=repr(f.encoding),defaultEncoding=repr(DEFAULT_ENCODING)) + else: + if self.debug: + errors='strict' + else: + errors='replace' + try: + f=codecs.open(fn,'w',DEFAULT_ENCODING,errors) + except Exception, err: + mesg=u'unable to write because unable to open the file' + noteException(mesg,devel=mesg+': %(err)s',exception=tlError,log=self.log,debug=self.debug,err=errorValue(err)) + pkgNames=self.value.keys() + pkgNames.sort() + pkgNo=1 + for k in pkgNames: + v=self.value[k] + v.writeout_fh(f) + f.write("\n") + if pkgNo<len(pkgNames): # keep off extra \n after end + f.write("\n") + pkgNo+=1 + f.close() + return None + + def add_cat_descs(self,dBcsr): + """Add catalogue descriptions to all matching TL packages that do not + already have a description. + """ + pkgNames=self.value.keys() + pkgNames.sort() + for k in pkgNames: + self.value[k].add_cat_desc(dBcsr,log=self.log,debug=self.debug) + return None + + + +class tlpobj(tlp): + """Give information based on a TeXLive object file + """ + def __init__(self,verbose=False,log=None,debug=False): + """Initialize an object. + """ + super(tlpobj,self).__init__(verbose=verbose,log=log,debug=debug) + self.revision=None # integer + self.srcfiles=None # list of files + self.runfiles=None # list of files + self.docfiles=None # dct fileName--> (dct tagkey --> tagval) + self.binfiles=None # arch --> list of files + self.srcsize=None # int (or None) + self.runsize=None # int (or None) + self.docsize=None # int (or None) + self.binsize=None # arch --> size (or None) + self.cataloguedata=None # cataloguekey --> value + return None + + def __unicode__(self): + r=[] + r.append(super(tlpobj,self).__unicode__()) + r.append(" revision: %s" % (pprint.pformat(self.revision),)) + r.append(" srcsize: %s" % (pprint.pformat(self.srcsize),)) + r.append(" srcfiles: %s" % (pprint.pformat(self.srcfiles),)) + r.append(" docsize: %s" % (pprint.pformat(self.docsize),)) + r.append(" docfiles: %s" % (pprint.pformat(self.docfiles),)) + r.append(" runsize: %s" % (pprint.pformat(self.runsize),)) + r.append(" runfiles: %s" % (pprint.pformat(self.runfiles),)) + r.append(" binsize: %s" % (pprint.pformat(self.binsize),)) + r.append(" binfiles: %s" % (pprint.pformat(self.binfiles),)) + r.append(" cataloguedata: %s" % (pprint.pformat(self.cataloguedata),)) + return "\n".join(r) + + def _stringToWriteout(self): + """String that will be written out during writeout_fh + """ + r=[] + r.append(super(tlpobj,self)._stringToWriteout()) + if self.revision: + r.append("revision %s" % (self.revision,)) + if self.docfiles: + if self.docsize is None: + mesg='docsize is not there but there are docfiles' + noteException(mesg,devel=mesg,exception=tlError,log=self.log,debug=self.debug) + r.append("docfiles size=%s" % (self.docsize,)) + dFiles=self.docfiles.keys() + dFiles.sort() + for line in dFiles: + s=[] + for (k,v) in self.docfiles[line].items(): + s.append("%s=%s" % (k,v)) + dLine=" "+line + if s: + dLine+=" "+(" ".join(s)) + r.append(dLine) + if self.srcfiles: + if self.srcsize is None: + mesg='srcsize is not there but there are srcfiles' + noteException(mesg,devel=mesg,exception=tlError,log=self.log,debug=self.debug) + r.append("srcfiles size=%s" % (self.srcsize,)) + self.srcfiles.sort() + for line in self.srcfiles: + r.append(" "+line) + if self.runfiles: + if self.runsize is None: + mesg='runsize is not there but there are runfiles' + noteException(mesg,devel=mesg,exception=tlError,log=self.log,debug=self.debug) + r.append("runfiles size=%s" % (self.runsize,)) + self.runfiles.sort() + for line in self.runfiles: + r.append(" "+line) + if self.binfiles: + arches=self.binfiles.keys() + arches.sort() + for arch in arches: + if self.binsize[arch] is None: + mesg='binsize is not there but there are binfiles' + noteException(mesg,devel=mesg+" for %(arch)s",exception=tlError,log=self.log,debug=self.debug,arch=repr(arch)) + r.append("binfiles arch=%s size=%s" % (arch,self.binsize[arch],)) + sBinfiles=self.binfiles[arch] + sBinfiles.sort() + for line in sBinfiles: + r.append(" "+line) + if self.cataloguedata: + cdKeys=self.cataloguedata.keys() + for k in cdKeys: + r.append("catalogue-%s %s" % (k,self.cataloguedata[k])) + return "\n".join(r) + +## def to_db(self,dBcsr,dBcnx,careful=True,associatedCatPkgs=None,verbose=False): +## """Put the yyy-file information to a database +## dBcsr, dBcnx database cursor and connection +## careful=True raise exception on error? +## associatedCatPkgs=None list of catalogue package id's that either +## are part of this texlive package of of which this texlive package +## is a part (None is the same as using what is now in the dB) +## verbose=False Give warnings +## """ +## tlId=self.name +## # Drop the file records if they are there +## sql="DELETE FROM tds_files WHERE tl_id=%(tlId)s" +## dct={'tlId':tlId} +## try: +## dBUtils.putData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='drop old texlive files record') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to drop existing tds files record' +## noteException(mesg,devel=mesg+' for package %(pkgId)s: %(err)s',log=self.log,debug=self.debug,pkgId=repr(pkgId),err=errorValue(err)) +## # Do the tl_cat records; see which ones to do +## if associatedCatPkgs is None: +## sql="SELECT pkg_id FROM tl_cat WHERE tl_id=%(tlId)s" +## dct['tlId']=tlId +## try: +## dBres=dBUtils.getData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='get list of catalogue packages for this texlive package') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to get list of catalogue packages for this texlive packages ' +## noteException(mesg,devel=mesg+'%(tlId)s: %(err)s',log=self.log,debug=self.debug,tlId=repr(tlId),err=errorValue(err)) +## associatedCatPkgs=[a for (a,) in dBres] +## if not(associatedCatPkgs): # try tlId +## possiblePkgId=tlId.lower() +## sql="SELECT id FROM package WHERE id=%(pkgId)s" +## dct['pkgId']=possiblePkgId +## try: +## dBres=dBUtils.getData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='check for existence of a catalogue id') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to check for existence of a catalogue id' +## noteException(mesg,devel=mesg+'%(pkgId)s: %(err)s',log=self.log,debug=self.debug,pkgId=repr(possiblePkgId),err=errorValue(err)) +## if dBres: +## associatedCatPkgs.append(possiblePkgId) +## # drop any that are there now +## sql="DELETE FROM tl_cat WHERE tl_id=%(tlId)s" +## dct={'tlId':tlId} +## try: +## dBUtils.putData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='drop old texlive package-catalogue package association') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to drop existing texlive package record' +## noteException(mesg,devel=mesg+' for package %(tlId)s: %(err)s',log=self.log,debug=self.debug,tlId=repr(tlId),err=errorValue(err)) +## # Drop the tl records if they are there +## sql="DELETE FROM tl WHERE tl_id=%(tlId)s" +## dct={'tlId':tlId} +## try: +## dBUtils.putData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='drop old texlive package record') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to drop existing texlive package record' +## noteException(mesg,devel=mesg+' for package %(tlId)s: %(err)s',log=self.log,debug=self.debug,tlId=repr(tlId),err=errorValue(err)) +## # Insert new tl record +## sql="INSERT INTO tl (tl_id,shortdesc,longdesc) VALUES (%(tlId)s,%(shortdesc)s,%(longdesc)s)" +## dct['shortdesc']=self.shortdesc +## dct['longdesc']=self.longdesc +## try: +## dBUtils.putData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='insert new texlive package record') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to insert new texlive package record' +## noteException(mesg,devel=mesg+' for package %(tlId)s: %(err)s',log=self.log,debug=self.debug,tlId=repr(tlId),err=errorValue(err)) +## # insert new tl_cat records +## if not(tlId.startswith('bin-') +## or tlId.startswith('collection-') +## or tlId.startswith('hyphen-') +## or tlId.startswith('lib-') +## or tlId.startswith('scheme-') +## or tlId.startswith('texlive-')): +## if (not(associatedCatPkgs) +## and careful +## and verbose): +## mesg=u'there are no catalogue packages associated with the TeX Live package %(tlId)s' +## warn(mesg,log=self.log,debug=self.debug,tlId=repr(tlId)) +## for pkgId in associatedCatPkgs: +## sql="INSERT INTO tl_cat (tl_id,pkg_id) VALUES (%(tlId)s,%(pkgId)s)" +## dct['pkgId']=pkgId +## try: +## dBUtils.putData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='insert new tl_cat package record') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to insert new association between a texlive package and a catalogue package' +## noteException(mesg,devel=mesg+' for texlive package %(tlId)s and catalgoue package %(pkgId)s: %(err)s',log=self.log,debug=self.debug,tlId=repr(tlId),pkgId=repr(pkgId),err=errorValue(err)) +## # Insert the file records +## # First build a list of pairs: (fileName,fileType) +## fileList=[] +## if self.srcfiles: +## for fn in self.srcfiles: +## fileList.append((fn,'src')) +## if self.runfiles: +## for fn in self.runfiles: +## fileList.append((fn,'run')) +## if self.docfiles: +## for fn in self.docfiles.keys(): +## fileList.append((fn,'doc')) +## if self.binfiles: +## for arch in self.binfiles.keys(): +## for fn in self.binfiles[arch]: +## fileList.append((fn,'bin')) +## # .. then put the info in the dB +## dct={'tlId':tlId} +## for (fn,fileType) in fileList: +## pathDir,pathBase=os.path.split(fn) +## sql="INSERT INTO tds_files (tl_id,type,path_dir,path_base) VALUES (%(tlId)s,%(fileType)s,%(pathDir)s,%(pathBase)s)" +## dct['fileType']=fileType +## dct['pathDir']=pathDir +## dct['pathBase']=pathBase +## try: +## dBUtils.putData(sql,dct=dct,dBcsr=dBcsr,log=self.log,debug=self.debug,listtype='insert new texlive files record') +## except dBUtils.dBUtilsError, err: +## mesg=u'unable to insert new tds files record' +## noteException(mesg,devel=mesg+' for package %(tlId)s with type=%(fileType)s, pathDir=%(pathDir)s, pathBase=%(pathBase)s: %(err)s',log=self.log,debug=self.debug,tlId=repr(tlId),fileType=repr(fileType),pathDir=repr(pathDir),pathBase=repr(pathBase),err=errorValue(err)) +## # Commit +## try: +## dBcnx.commit() +## except Exception, err: +## mesg=u'unable to commit the insert of the new tds files record' +## noteException(mesg,devel=mesg+' for package %(pkgId)s: %(err)s',log=self.log,debug=self.debug,tlId=repr(tlId),err=errorValue(err)) +## return None + + initialState=tlp.initialState + nextStates=tlp.nextStates + nextStates['revision']=tlp.keyValueStates-set(['revision']) + nextStates['srcfiles']=tlp.keyValueStates | set(['srcfiles_file'])-set(['srcfiles']) + nextStates['srcfiles_file']=tlp.keyValueStates | set(['srcfiles_file']) + nextStates['runfiles']=tlp.keyValueStates | set(['runfiles_file'])-set(['runfiles']) + nextStates['runfiles_file']=tlp.keyValueStates | set(['runfiles_file']) + nextStates['docfiles']=tlp.keyValueStates | set(['docfiles_file'])-set(['docfiles']) + nextStates['docfiles_file']=tlp.keyValueStates | set(['docfiles_file'])-set(['docfiles']) + nextStates['binfiles']=tlp.keyValueStates | set(['binfiles_file']) + nextStates['binfiles_file']=tlp.keyValueStates | set(['binfiles_file']) + nextStates['cataloguedata']=tlp.keyValueStates + + def handleRevision(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'revision' + """ + try: + fields=restOfLine.strip().split() + self.revision=int(fields[0]) + except: + mesg=u'no "value" integer in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + return None + + def handleSrcfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'srcfiles' + """ + try: + fields=restOfLine.strip().split() + sizeString=fields[0] + except: + mesg=u'no value in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + try: + sizeFields=sizeString.split('=') + if sizeFields[0].lower()!='size': + raise tlError + size=int(sizeFields[1]) + if self.srcsize is None: + self.srcsize=0 + self.srcsize+=size + except: + mesg=u'expected a value of size=NNNNNN in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + if self.srcfiles is None: + self.srcfiles=[] + return None + + def handleSrcfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'srcfiles_file' + """ + try: + fields=restOfLine.strip().split() # recall that restOfLine=line[1:] + self.srcfiles.append(fields[0]) + except: + mesg=u'unable to understand source file name in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + return None + + def handleDocfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'docfiles' + """ + try: + fields=restOfLine.strip().split() + sizeString=fields[0] + except: + mesg=u'no value in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + try: + sizeFields=sizeString.split('=',1) + if sizeFields[0].lower()!='size': + raise tlError + size=int(sizeFields[1]) + if self.docsize is None: + self.docsize=0 + self.docsize+=size + except: + mesg=u'expected a value of size=NNNNNN in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + if self.docfiles is None: + self.docfiles={} + return None + + def handleDocfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'docfiles_file' + """ + fields=restOfLine.strip().split() # recall that restOfLine=line[1:] + kvDct={} + kvString=None + try: + for kvString in fields[1:]: + if kvString: + k,v=kvString.split("=",1) + kvDct[k]=v + except: + mesg=u'unable to understand doc file description in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s; key-value description string=%(kvString)s; reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState),kvString=repr(kvString)) + try: + self.docfiles[fields[0].strip()]=kvDct + except Exception, err: + mesg=u'unable to understand doc file name in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s: %(err)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState),err=errorValue(err)) + return None + + def handleRunfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'runfiles' + """ + try: + fields=restOfLine.strip().split() + sizeString=fields[0] + except: + mesg=u'no value in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + try: + sizeFields=sizeString.split('=',1) + if sizeFields[0].lower()!='size': + raise tlError + size=int(sizeFields[1]) + if self.runsize is None: + self.runsize=0 + self.runsize+=size + except: + mesg=u'expected a value of size=NNNNNN in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + if self.runfiles is None: + self.runfiles=[] + return None + + def handleRunfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'runfiles_file' + """ + try: + fields=restOfLine.strip().split() # recall that restOfLine=line[1:] + self.runfiles.append(fields[0].strip()) + except: + mesg=u'unable to understand run file name in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + return None + + def handleBinfiles(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'binfiles' + """ + try: + fields=restOfLine.strip().split() + firstString,secondString=fields[0],fields[1] + except: + mesg=u'expected an arch=XXXX size=NNNNNN in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + try: + firstStringFields=firstString.split('=',1) + secondStringFields=secondString.split('=',1) + if firstStringFields[0].lower()=='arch': + archFields=firstStringFields + sizeFields=secondStringFields + else: + archFields=secondStringFields + sizeFields=firstStringFields + if (archFields[0].lower()!='arch' + or sizeFields[0].lower()!='size'): + raise tlError + self.currentArch=archFields[1] + except: + mesg=u'expected two values of the form x=y in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + try: + if self.binsize is None: + self.binsize={} + self.binsize[self.currentArch]=int(sizeFields[1]) + except: + mesg=u'expected size to be an integer in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + if self.binfiles is None: + self.binfiles={} + self.binfiles[self.currentArch]=[] + return None + + def handleBinfilesFile(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'binfiles_file' + """ + if self.currentArch is None: + mesg=u'do not know the right architecture in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + try: + fields=restOfLine.strip().split() # recall that restOfLine=line[1:] + self.binfiles[self.currentArch].append(fields[0].strip()) + except: + mesg=u'unable to understand bin file path in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s with architecture %(currentArch)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState),currentArch=repr(currentArch)) + return None + + def is_arch_dependent(self): + """Returns True if there are binfiles. + """ + if self.binfiles: + return True + else: + return False + + def total_size(self,*archs): + """Returns the sum of the sizes of srcfiles, docfiles, runfiles, + and binfiles any architectures given. + """ + if self.srcsize is None: + srcsize=0 + else: + srcsize=self.srcsize + if self.docsize is None: + docsize=0 + else: + docsize=self.docsize + if self.runsize is None: + runsize=0 + else: + runsize=self.runsize + s=srcsize+docsize+runsize + try: + for arch in archs: + s+=self.binsize[arch] + except: + mesg=u'unable to recognize an architecture' + noteException(mesg,devel=mesg+': %(arch)s',exception=tlError,log=self.log,debug=self.debug,arch=repr(arch)) + return s + + def _subtractList(self,l1,l2): + """From l1 remove any elements of l2, as many times as they occur. + """ + for f in l2: + while True: # more than one f in l1? + try: + l1.remove(f) + except: + break + return l1 + def add_srcfiles(self,fileList): + self.srcfiles+=fileList + def remove_srcfiles(self,fileList): + self.srcfiles=self._subtractList(self.srcfiles,fileList) + def add_docfiles(self,fileList): + self.docfiles+=fileList + def remove_docfiles(self,fileList): + self.docfiles=self._subtractList(self.docfiles,fileList) + def add_runfiles(self,fileList): + self.runfiles+=fileList + def remove_runfiles(self,fileList): + self.runfiles=self._subtractList(self.runfiles,fileList) + def add_binfiles(self,arch,fileList): + self.binfiles[arch]+=fileList + def remove_binfiles(self,arch,fileList): + self.binfiles[arch]=self._subtractList(self.binfiles[arch],fileList) + def add_files(self,t,fileList): + if t=='src': + self.add_srcfiles(fileList) + elif t=='doc': + self.add_docfiles(fileList) + elif t=='run': + self.add_runfiles(fileList) + else: + mesg=u'file type not known' + noteException(mesg,devel=mesg+': %(t)s',exception=tlError,log=self.log,debug=self.debug,t=repr(t)) + def remove_files(self,t,fileList): + if t=='src': + self.remove_srcfiles(fileList) + elif t=='doc': + self.remove_docfiles(fileList) + elif t=='run': + self.remove_runfiles(fileList) + else: + mesg=u'file type not known' + noteException(mesg,devel=mesg+': %(t)s',exception=tlError,log=self.log,debug=self.debug,t=repr(t)) + + def list_files(self): + """Return a string of lines with file names for all files + """ + r=[] + if self.srcfiles: + r+=self.srcfiles + if self.runfiles: + r+=self.runfiles + if self.docfiles: + r+=self.docfiles.keys() + if self.binfiles: + for arch in self.binfiles.keys(): + r+=self.binfiles[arch] + r.sort() + return "\n".join(r) + + +class tlpobj_db(tlp_db): + """Give information based on a TeXLive object file database + """ + def _makeSingle(self): + """Helper fcn to make one of whatever self.value is holding multiple + of + f file handle + """ + return tlpobj(log=self.log,debug=self.debug) + +## def to_db(self,dBcsr,dBcnx,verbose=False): +## """Write all records to the database +## dBcsr,dBcnx database cursor and connection +## """ +## pkgNames=self.value.keys() +## pkgNames.sort() +## for k in pkgNames: +## v=self.value[k] +## v.to_db(dBcsr,dBcnx,verbose=verbose) +## return None + + +class tlpsrc(tlp): + """Give information based on a TeXLive source file + """ + def __init__(self,verbose=False,log=None,debug=False): + """Initialize an object. + """ + super(tlpsrc,self).__init__(verbose=verbose,log=log,debug=debug) + self.srcpattern=None # list of strings (or None) + self.runpattern=None # list of strings (or None) + self.docpattern=None # list of strings (or None) + self.binpattern=None # list of strings (or None) + return None + + def __unicode__(self): + r=[] + r.append(super(tlpsrc,self).__unicode__()) + r.append(" srcpattern: %s" % (pprint.pformat(self.srcpattern),)) + r.append(" runpattern: %s" % (pprint.pformat(self.runpattern),)) + r.append(" docpattern: %s" % (pprint.pformat(self.docpattern),)) + r.append(" binpattern: %s" % (pprint.pformat(self.binpattern),)) + return "\n".join(r) + + def _stringToWriteout(self): + """String that will be written out during writeout_fh + """ + r=[] + r.append(super(tlpsrc,self)._stringToWriteout()) + if self.srcpattern: + for line in self.srcpattern: + r.append("srcpattern %s" % (line,)) + if self.runpattern: + for line in self.runpattern: + r.append("runpattern %s" % (line,)) + if self.docpattern: + for line in self.docpattern: + r.append("docpattern %s" % (line,)) + if self.binpattern: + for line in self.binpattern: + r.append("binpattern %s" % (line,)) + return "\n".join(r) + + initialState=tlp.initialState + nextStates=tlp.nextStates + nextStates['srcpattern']=tlp.keyValueStates + nextStates['runpattern']=tlp.keyValueStates + nextStates['docpattern']=tlp.keyValueStates + nextStates['binpattern']=tlp.keyValueStates + + def handleSrcpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'srcpattern' + """ + try: + if self.srcpattern is None: + self.srcpattern=[] + self.srcpattern.append(restOfLine.rstrip()) + except: + mesg=u'no "value" text in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + return None + + def handleRunpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'runpattern' + """ + try: + if self.runpattern is None: + self.runpattern=[] + self.runpattern.append(restOfLine.rstrip()) + except: + mesg=u'no "value" text in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + return None + + def handleDocpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'docpattern' + """ + try: + if self.docpattern is None: + self.docpattern=[] + self.docpattern.append(restOfLine.rstrip()) + except: + mesg=u'no "value" text in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + return None + + def handleBinpattern(self,newState,restOfLine,line,lineNo): + """What to do if the newState is 'binpattern' + """ + try: + if self.binpattern is None: + self.binpattern=[] + self.binpattern.append(restOfLine.rstrip()) + except: + mesg=u'no "value" text in line number=%(lineNo)s' + noteException(mesg,devel=mesg+'; now in state %(newState)s reading line=%(line)s',exception=tlError,log=self.log,debug=self.debug,lineNo=lineNo,line=repr(line),newState=repr(newState)) + return None + + +class tlpsrc_db(tlp_db): + """Give information based on a TeXLive src file list + """ + def from_dir(self,dn=None): + """Read a set of tlpsrc files. Set self.value. + dn=None directory name. If None, use the canonical name. + """ + if dn is None: + dn=os.path.join(os.path.dirname(TLPDB_FILENAME),'tlpkg/tlpsrc') + globPattern=os.path.join(dn,'*.tlpsrc') + for fn in glob.glob(globPattern): + self.from_file(fn=fn) + return None + + def _makeSingle(self): + """Helper fcn to make one of whatever self.value is holding multiple + of. + """ + return tlpsrc(log=self.log,debug=self.debug) + + def to_dir(self,dn=None): + """Write a set of tlpsrc files. + dn=None directory name. If None, use the canonical name. + """ + if dn is None: + dn=os.path.join(os.path.basename(TLPDB_FILENAME),'tlpsrc') + if not(os.path.exists(dn)): + os.makedirs(dn) + pkgNames=self.value.keys() + for k in pkgNames: + v=self.value[k] + fn=os.path.join(dn,v.name+'.tlpsrc') + v.writeout(fn=fn) + return None + + +def getRelatedCatPkg(tlId,dBcsr,log=None,debug=False): + """Get the list of catalogue packages that are related to the given + TeX Live package (does not return None values). + tlId string + dBcsr database cursor + log=None,debug=False debugging + """ + sql="""SELECT pkg_id FROM tl_cat + WHERE tl_id=%(tlId)s + AND pkg_id IS NOT NULL""" + dct={'tlId':tlId} + try: + dBres=dBUtils.getData(sql,dct=dct,dBcsr=dBcsr,log=log,debug=debug,listtype='get catalogue package ids related to this TeX Live package id') + except dBUtils.dBUtilsError, err: + mesg=u'unable to get texlive-catalogue packages record' + noteException(mesg,devel=mesg+' for TeX Live package %(tlId)s: %(err)s',log=log,debug=debug,tlId=repr(tlId),err=errorValue(err)) + return set([catId for (catId,) in dBres]) + +def getRelatedTlPkg(pkgId,dBcsr,log=None,debug=False): + """Get the list of TeX Live packages that are related to the given + Catalogue package. + pkgId string + dBcsr database cursor + log=None,debug=False debugging + """ + sql="""SELECT tl_id FROM tl_cat + WHERE pkg_id=%(pkgId)s""" + dct={'pkgId':pkgId} + try: + dBres=dBUtils.getData(sql,dct=dct,dBcsr=dBcsr,log=log,debug=debug,listtype='get TeX Live package ids related to this catalogue package id') + except dBUtils.dBUtilsError, err: + mesg=u'unable to get catalogue-texlive packages record' + noteException(mesg,devel=mesg+' for catalogue package %(pkgId)s: %(err)s',log=log,debug=debug,pkgId=repr(pkgId),err=errorValue(err)) + return set([tlId for (tlId,) in dBres]) + + +#...................................................................... +def main(argv=None,log=None,debug=DEBUG): + """The main logic if called from the command line + argv The arguments to the routine + log=None, debug=DEBUG Debugging stuff + """ + if argv is None: + argv=sys.argv + # Parse the arguments + usage="""%prog: read a TeX Live tlp src or obj file; typically write the obj filelists to the dB + %prog [options]""" + oP=optparse.OptionParser(usage=usage,version=__version__) + oP.add_option('--output','-o',action='store_true',default=False,dest='output',help='show all package records') + oP.add_option('--no-database','-n',action='store_true',default=False,dest='noDb',help='do not put all package records to the database') + oP.add_option('--source-read','-s',action='store_true',default=False,dest='srcDir',help='read the source files') + oP.add_option('--add-catalogue-information','-a',action='store_true',default=False,dest='catInfo',help='add catalogue information to the source or object information') + oP.add_option('--debug','-D',action='store_true',default=DEBUG,dest='debug',help='output debugging information') + oP.add_option('--verbose','-V',action='store_true',default=VERBOSE,dest='verbose',help='talk a lot') + opts, args=oP.parse_args(argv[1:]) + # Handle the options + # Handle positional arguments + if args[1:]: + tlpdbFilename=args[1] + else: + tlpdbFilename=TLPDB_FILENAME + # Handle the various command line switches +## try: +## (dBcnx,dBcsr)=dBUtils.opendB() +## except dBUtils.dBUtilsError, err: +## fail("Unable to connect to the database: %(err)s",returnCode=10,log=log,debug=opts.debug,err=errorValue(err)) + if opts.srcDir: + try: + t=tlpsrc_db(log=log,debug=opts.debug) + t.from_dir(dn=None) + if opts.catInfo: + t.add_cat_descs(dBcsr) + t.to_dir(dn='tmpTexlive') + except Exception, err: + mesg="trouble reading the object file and writing: "+errorValue(err) + fail(mesg,returnCode=10,log=log,debug=opts.debug) + return None + if opts.output: + try: + t=tlpobj_db(log=log,debug=opts.debug) + t.from_file(tlpdbFilename) + if opts.catInfo: + t.add_cat_descs(dBcsr) + t.write_file() + except Exception, err: + mesg="trouble reading the object file and writing: "+errorValue(err) + fail(mesg,returnCode=10,log=log,debug=opts.debug) + return None +## if not(opts.noDb): +## try: +## t=tlpobj_db(log=log,debug=opts.debug) +## t.from_file(tlpdbFilename) +## t.to_db(dBcsr,dBcnx,verbose=opts.verbose) +## except Exception, err: +## mesg="trouble reading the object file and sending the results to the database: "+errorValue(err) +## fail(mesg,returnCode=10,log=log,debug=opts.debug) + return None + + +# ............... script start ....................... +if __name__=='__main__': + log=None + if LOGGING: + log=openLog(LOGFILE_NAME,purpose=THIS_SCRIPT) + if DEBUG and __notes__.strip(): + note(__notes__,log,leader="NOTES FOR %s:" % (THIS_SCRIPT,),) + try: + main(argv=sys.argv,log=log,debug=DEBUG) + except KeyboardInterrupt: + mesg=u"Keyboard interrupt" + fail(mesg,returnCode=1,log=log,debug=DEBUG) + except StandardError, err: + mesg=u"General programming error: "+errorValue(err) + fail(mesg,returnCode=2,log=log,debug=DEBUG) + except SystemExit, err: # fail() inside a subroutine + pass + sys.exit(0) |