X-Git-Url: http://nitlanguage.org diff --git a/contrib/neo_doxygen/src/neo_doxygen.nit b/contrib/neo_doxygen/src/neo_doxygen.nit index 3952d28..431809c 100644 --- a/contrib/neo_doxygen/src/neo_doxygen.nit +++ b/contrib/neo_doxygen/src/neo_doxygen.nit @@ -20,16 +20,24 @@ module neo_doxygen import model import doxml +import graph_store import console import opts # An importation task. class NeoDoxygenJob - var client: Neo4jClient + + # The storage medium to use. + var store: GraphStore + + # The loaded project graph. var model: ProjectGraph is noinit - # How many operation can be executed in one batch? - private var batch_max_size = 1000 + # Escape control sequence to save the cursor position. + private var term_save_cursor: String = (new TermSaveCursor).to_s + + # Escape control sequence to rewind to the last saved cursor position. + private var term_rewind: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}" # Generate a graph from the specified project model. # @@ -39,72 +47,71 @@ class NeoDoxygenJob # * `dir`: Doxygen XML output directory path. # * `source`: The language-specific logics to use. fun load_project(name: String, dir: String, source: SourceLanguage) do + check_name name model = new ProjectGraph(name) - # TODO Let the user select the language. var reader = new CompoundFileReader(model, source) # Queue for sub-directories. var directories = new Array[String] + var file_count = 0 - if dir.length > 1 and dir.chars.last == "/" then - dir = dir.substring(0, dir.length - 1) + if dir == "" then + printn "Reading the current directory... " + else + printn "Reading {dir}... " end loop - for f in dir.files do + for f in list_files(dir) do var path = dir/f if path.file_stat.is_dir then directories.push(path) else if f.has_suffix(".xml") and f != "index.xml" then - print "Processing {path}..." reader.read(path) + file_count += 1 end end if directories.length <= 0 then break dir = directories.pop end + model.add_global_modules + print "Done." + if file_count < 2 then + print "{file_count} file read." + else + print "{file_count} files read." + end end - # Save the graph. - fun save do - model.put_edges - var nodes = model.all_nodes - print("Saving {nodes.length} nodes...") - push_all(nodes) - var edges = model.all_edges - print("Saving {edges.length} edges...") - push_all(edges) + # List files in a directory. + # + # This method may be redefined to force the order in which the files + # are read by `load_project`. + protected fun list_files(dir: String): Collection[String] do + return dir.files end - # Save `neo_entities` in the database using batch mode. - private fun push_all(neo_entities: Collection[NeoEntity]) do - var batch = new NeoBatch(client) - var len = neo_entities.length - var sum = 0 - var i = 1 - - for nentity in neo_entities do - batch.save_entity(nentity) - if i == batch_max_size then - do_batch(batch) - sum += batch_max_size - print("\t{sum * 100 / len}% done.") - batch = new NeoBatch(client) - i = 1 - else - i += 1 - end + # Check the project’s name. + private fun check_name(name: String) do + assert name_valid: not name.chars.first.is_upper else + sys.stderr.write("{sys.program_name}: The project’s name must not" + + " begin with an upper case letter. Got `{name}`.\n") + end + assert name_unused: not store.has_node_label(name) else + sys.stderr.write("{sys.program_name}: The label `{name}` is already" + + " used in the specified graph.\n") end - do_batch(batch) end - # Execute `batch` and check for errors. - # - # Abort if `batch.execute` returns errors. - private fun do_batch(batch: NeoBatch) do - var errors = batch.execute - if not errors.is_empty then - for e in errors do sys.stderr.write("{sys.program_name}: {e}\n") - exit(1) - end + # Save the graph. + fun save do + sys.stdout.write "Linking nodes...{term_save_cursor} " + model.put_edges + print "{term_rewind} Done." + var nodes = model.all_nodes + sys.stdout.write "Saving {nodes.length} nodes..." + store.save_all(nodes) + var edges = model.all_edges + sys.stdout.write "Saving {edges.length} edges..." + store.save_all(edges) end end @@ -142,6 +149,7 @@ class NeoDoxygenCommand init do sources["any"] = new DefaultSource sources["java"] = new JavaSource + sources["python"] = new PythonSource var prefix = new OptionText(""" {{{"NAME".bold}}} @@ -172,15 +180,15 @@ class NeoDoxygenCommand opt_dest.default_value = default_dest option_context.add_option(opt_dest) + opt_help = new OptionBool("Show the help (this page).", + "-h", "--help") + option_context.add_option(opt_help) + var keys = new Array[String].from(sources.keys) opt_src_lang = new OptionEnum(keys, - "The programming language to assume when processing chunk in the declarations left as-is by Doxygen. Use `any` (the default) to disable any language-specific processing.", + "The programming language to assume when processing chunks in the declarations left as-is by Doxygen. Use `any` (the default) to disable any language-specific processing.", keys.index_of("any"), "--src-lang") option_context.add_option(opt_src_lang) - - opt_help = new OptionBool("Show the help (this page).", - "-h", "--help") - option_context.add_option(opt_help) end # Start the application. @@ -211,13 +219,18 @@ class NeoDoxygenCommand var dest = opt_dest.value var project_name = rest[0] var dir = rest[1] - var neo = new NeoDoxygenJob(new Neo4jClient(dest or else default_dest)) + var neo = new NeoDoxygenJob(create_store(dest or else default_dest)) neo.load_project(project_name, dir, source) neo.save return 0 end + # Create an instance of `GraphStore` for the specified destination. + protected fun create_store(dest: String): GraphStore do + return new Neo4jStore(new Neo4jClient(dest)) + end + # Show the help. fun show_help do option_context.usage @@ -237,8 +250,8 @@ end # Add handling of multi-line descriptions. # -# Note: The algorithm is naive and do not handle internationalisation and -# escape sequences. +# Note: The algorithm is naive and do not handle internationalisation, +# multi-byte characters and control characters. redef class Option redef fun pretty(off) do