def _print_symbol_index_page(self): debug_message('print symbols index page') text = [] text.append(self.html.page_header("Schema Objects Index")) local_nav_bar = [] keys = self.index.keys() keys.sort() letter = "" for key in keys: if (key[:1] != letter): letter = key[:1] local_nav_bar.append((letter,letter)) text.append(self.html.context_bar(local_nav_bar)) letter = "" for key in keys: if (key[:1] != letter): letter = key[:1] text.append(self.html.heading(letter, 3) + self.html.anchor(letter)) for entry in self.index[key]: text.append('%s %s<br/>' % entry) text.append(self.html.page_footer()) file_name = path.join(self.cfg.output_dir, "symbol-index.html") self._write(''.join(text), file_name)
def _copy_css(self): """copy the css file to the output_dir""" debug_message('copying CSS stylesheet to output_dir') css = self.cfg.css output_dir = self.cfg.output_dir csspath = self.cfg.csspath try: copy(path.join(csspath, css), output_dir) debug_message('css: done') except IOError, (errno, errmsg): msg = path.join(csspath, css) + ' not fround. ' \ 'Trying to find another. Error copying CSS style. ' \ 'You are running precompiled version propably.\n' \ 'Related info: (%s) %s' % (errno, errmsg) debug_message(msg) try: debug_message('Trying: ' + path.join(path.dirname( sys.executable), 'css', css)) copy(path.join(path.dirname(sys.executable), 'css', css), output_dir) debug_message('css: done') except IOError: print 'Error: (%s) %s' % (errno, errmsg) print 'Please copy some css style into output directory manually.'
def write(self): """write out the xml files to the file system""" xml_file = file_name = os.path.join(self.cfg.output_dir, self.cfg.xml_file) debug_message('Creating XML file: %s' % xml_file) f = open(xml_file, 'w') f.write(self.cfg.schema.getXML()) f.close()
def _print_list_page(self, title, ht_table, file_name): # print list pages debug_message('print %s list page' % title) text = self.html.page_header(title) text = text + self.html.context_bar( None) text = text + ht_table text = text + self.html.page_footer() file_name = path.join(self.cfg.output_dir, file_name.replace("/", "-")) self._write(text, file_name)
def _print_index_frame(self, header, item_list, file_name): # generic procedure to print index frame on left side # excpects: # header - title string, i.e "Tables" # item_list - list of names with html links # file_name - relative file name debug_message('index frame for %s' % header) text = [] text.append(self.html.frame_header(header)) text.append(self.html.href('nav.html', 'Categories')) for row in item_list: text.append(row) text.append(self.html.frame_footer()) #java sources contain simbol / inside name, in file_names should be replaced with "-" f_name = path.join(self.cfg.output_dir, file_name.replace("/","-")) self._write(''.join(text), f_name)
def main(): """parse the command line args and run the formatting/writing of the documentation """ parser = argparse.ArgumentParser(description='Parse command line args.') # add all the possible arguments we expect to handle via the cli parser.add_argument('-u', dest='username', action='store', required=True, help='db schema') parser.add_argument('-p', dest='password', action='store', required=True, help='Password for the db schema') parser.add_argument('-t', dest='tsn', action='store', required=True, help='Network TSN alias') parser.add_argument('-o', dest='output_dir', action='store', required=True, help='Output directory for doc generation, for sphinx '\ 'documentation this is the same name as the schema '\ 'name so that links can be made between schemas.') parser.add_argument('-n', dest='name', action='store', required=False, default=False, help='DB Project name') parser.add_argument('-v', dest='verbose', action='store_true', default=False, help='Display verbose "build" text when running.') parser.add_argument('-s', dest='syntax_highlighting', action='store_true', default=False, help='When formatting as html, turn on syntax highlighting.') parser.add_argument('--css', dest='css', action='store', help='When formatting as html, path to custom css file') parser.add_argument('--noddl', dest='noddl', action='store_true', default=False, help='Diasble ddl generation') parser.add_argument('--dia', dest='dia', action='store_true', default=False, help='Enable dia uml output') parser.add_argument('--dia_conf_file', dest='dia_conf_file', action='store', help='Path to the dia conf table file. Only '\ 'create dia diagrams of tables in conf file') parser.add_argument('--desc', dest='description', action='store', help='Project description added to the documentation index') parser.add_argument('--dia-table-list', dest='dia-table-list', action='append', help='Filename for dia table lists') parser.add_argument('--not-nulls', dest='notnulls', action='store_true', default=False, help='Do not Write out the not null contraints') parser.add_argument('--pb', dest='pb', action='store_true', default=False, help='Do not write out the package bodies') group = parser.add_mutually_exclusive_group() group.add_argument('--html', dest='html', action='store_true', default=False, help='Format output as javadoc html files') group.add_argument('--rest', dest='rest', action='store_true', default=False, help='Format output as reST files') group.add_argument('--xml-file', dest='xml', action='store', help='Generate output into xml file') # create global config file - hanger passed around to various apps... # bleagh - but how it is in first fork.... cfg = OSDConfig() pargs = parser.parse_args() # username/schema username = pargs.username # do we want to generate ddl? cfg.allowDDL = not pargs.noddl # Just stick these as they are.... cfg.dia_conf_file = cfg.dia_conf_file name = pargs.name cfg.name = name and name or upper(username) cfg.notNulls = pargs.notnulls cfg.pb = pargs.pb cfg.xml_file = pargs.xml verbose = cfg.verbose = pargs.verbose set_verbose_mode(verbose) # make sure the dia conf file exists if set. if cfg.dia_conf_file: if not os.path.exists(cfg.cfg.dia_conf_file): cfg.dia_conf_file = None css = pargs.css if css: if not os.path.exists(os.path.join(cfg.csspath, css)): msg = '\nWARNING: %s doesn\'t exists. Using default instead.\n' % \ value debug_message(msg) else: cfg.css = css #if opt == '--schema': # cfg.useOwners = True # if len(value) > 0: # cfg.owners = value.split(',') # output dir is the dir the directory is created - based on:: # db.schema_name format - so /tmp/foo.username output_dir = os.path.join(os.path.abspath(pargs.output_dir), '%s.%s' % (pargs.tsn, username)) cfg.output_dir = output_dir # check if output_dir exsits, if not try to create one. if os.access(cfg.output_dir, os.F_OK) != 1: try: os.makedirs(cfg.output_dir) except os.error, e: print 'ERROR: Cannot create directory ', cfg.output_dir exit(2)
exit(2) # XXX effectively also the schema cfg.currentUser = connect_string[:connect_string.find('/')].upper() # know encoding we will use oraenc = OracleNLSCharset() encoding = oraenc.getClientNLSCharset() cfg.ora_encoding = oraenc.getOracleNLSCharacterset(cfg.connection) if encoding == None: encoding = oraenc.getPythonEncoding(cfg.ora_encoding) else: encoding = oraenc.getPythonEncoding(encoding) cfg.encoding = encoding debug_message('Using codec: %s' % cfg.encoding) debug_message('HTML encoding: %s\n' % cfg.webEncoding) # make sure that the name and desc. are encoded if cfg.desc != None: cfg.desc = cfg.desc.encode(encoding) cfg.name = cfg.name.encode(encoding) cfg.dictionary = OraSchemaDataDictionary(cfg) cfg.schema = OracleSchema(cfg) if pargs.html: cfg.syntaxHighlighting = pargs.syntax # all the magic is in this formatter's __init__ for now HTMLFormatter(cfg)
def _write(self, text, file_name): # write file to fs debug_message("debug: writing file %s" % file_name) f = open(file_name, 'w') f.write(text) f.close()
def _sanity_check(self): debug_message('print sanity check page') problems = False text = [] text.append(self.html.page_header("Sanity Check")) local_nav_bar = [] local_nav_bar.append(("FK indexes", "fk-ix")) local_nav_bar.append(("Invalid objects", "inv")) text.append(self.html.context_bar(local_nav_bar)) text.append(self.html.heading("Sanity Check", 1)) scheck = SchemaAnalyzer(self.cfg.connection, self.cfg.schema) if scheck.fk_no_indexes: text.append(self.html.anchor("fk-ix")) text.append(self.html.heading("No indexes on columns involved in foreign key constraints",2)) text.append('''<p>You should almost always index foreign keys. The only exception is when the matching unique or primary key is never updated or deleted. For more information take a look on <a href="http://oradoc.photo.net/ora817/DOC/server.817/a76965/c24integ.htm#2299"> Concurrency Control, Indexes, and Foreign Keys</a>.</p> <p>The sql file which will generate these indexes is <a href="fk-indexes.sql">created for you</a></p>''') title = '"Unindexed" foreign keys' headers = "Table Name", "Constraint name", "Columns" rows = [] for constraint in scheck.fk_no_indexes: row=[] row.append( self.html.href_to_table(constraint.table_name)) row.append( self.html.href_to_constraint(constraint.name, constraint.table_name, constraint.name)) columns = '' columns_count = len(constraint.columns) i=0 for j in constraint.columns.keys(): columns += constraint.columns[j] i +=1 if i != columns_count: columns += ', ' row.append(columns) rows.append(row) #write sql file_name = path.join(self.cfg.output_dir, "fk-indexes.sql") self._write(scheck.fk_no_indexes_sql,file_name) text.append(self.html.table(title,headers,rows)) problems = True if len(scheck.invalids) != 0: problems = True text.append(self.html.anchor("inv")) text.append(self.html.heading('Invalid objects', 2)) text.append('''<p>Invalid object does not mean a problem sometimes. Sometimes will fix itself as is is executed or accessed. But if there is an error in USER_ERRORS table, you are in trouble then...</p> <p>The sql file which will compile these objects is <a href="compile-objects.sql">created for you</a>.</p>''') self._write(scheck.invalids_sql, path.join(self.cfg.output_dir, 'compile-objects.sql')) invalids = scheck.invalids for i in invalids: if i[1] == 'PACKAGE' or i[1] == 'PACKAGE BODY': i[0] = self.html.href_to_package(i[0]) if i[1] == 'PROCEDURE': i[0] = self.html.href_to_procedure(i[0]) if i[1] == 'FUNCTION': i[0] = self.html.href_to_function(i[0]) if i[1] == 'VIEW': i[0] = self.html.href_to_view(i[0]) if i[1] == 'TRIGGER': for j in self.cfg.schema.triggers: if j.name == i[0]: i[0] = self.html.href_to_trigger(i[0], j.table_name, i[0], self.triggerAnchorType(j)) break i[2] = self.html._quotehtml(i[2]) text.append(self.html.table('Invalids', ['Object name', 'Type', 'Error', 'At line'], invalids)) if problems == False: # no checks text.append(self.html.p('No known problems.')) text.append(self.html.page_footer()) file_name = path.join(self.cfg.output_dir, "sanity-check.html") self._write(''.join(text), file_name)
def __init__(self, cfg): set_verbose_mode(cfg.verbose_mode) self.syntaxHighlighter = SqlHighlighter( highlight=cfg.syntaxHighlighting) self.dotEngine = Dot(cfg.output_dir) self.cfg = cfg self.html = HtmlWidgets(cfg.name, cfg.css, cfg.webEncoding, cfg.notNulls) self.index = {} # print html files debug_message('\nCreating HTML output') self._print_index_frames() self._print_list_pages() self._sanity_check() self._print_common_pages() debug_message('print tables') for table in cfg.schema.tables: self._print_table(table) debug_message('print views') for view in cfg.schema.views: self._print_view(view) debug_message('print materialized views') for mview in cfg.schema.mviews: self._print_mview(mview) debug_message('print functions') for function in cfg.schema.functions: self._print_function(function) debug_message('print procedures') for procedure in cfg.schema.procedures: self._print_procedure(procedure) debug_message('print packages') for package in cfg.schema.packages: self._print_package(package) debug_message('print java sources') for jsource in cfg.schema.java_sources: self._print_java_source(jsource) self._print_symbol_index_page()