From: Thomas Walker Lynch
Date: Sun, 13 Oct 2024 05:18:13 +0000 (+0000)
Subject: refactoring class Graph, updating project structure
X-Git-Url: https://git.reasoningtechnology.com/style/static/%7Bstyle.link%7D?a=commitdiff_plain;h=61c58d534188e822f23b9bc643b9424e8f4f4482;p=Ariadne
refactoring class Graph, updating project structure
---
diff --git a/developer/deprecated/#Ariandne.groovy# b/developer/deprecated/#Ariandne.groovy#
deleted file mode 100644
index 6c0cf17..0000000
--- a/developer/deprecated/#Ariandne.groovy#
+++ /dev/null
@@ -1,635 +0,0 @@
-class AriadneGraph {
-
- // Instance variables for graph data if needed
- Map node_map = [:]
- List node_f_list = []
-
- // Constructor to accept a graph definition (node_map and node_f_list)
- AriadneGraph( Map node_map ,List node_f_list ){
- this.node_map = node_map ?: [:]
- this.node_f_list = node_f_list ?: []
- }
-
- /*--------------------------------------------------------------------------------
- File utility functions
- */
-
- static Map unpack_file_path( String file_fp ){
- def file = new File( file_fp )
-
- def parent_dp = file.getParent()
- def file_fn = file.getName()
- def file_fn_base = file_fn.lastIndexOf('.') > 0 ? file_fn[ 0..file_fn.lastIndexOf('.') - 1 ] : file_fn
- def file_fn_ext = file_fn.lastIndexOf('.') > 0 ? file_fn[ file_fn.lastIndexOf('.') + 1..-1 ] : ''
-
- return [
- parent_dp: parent_dp
- ,file_fn: file_fn
- ,file_fn_base: file_fn_base
- ,file_fn_ext: file_fn_ext
- ]
- }
-
- static boolean file_exists_q( String node_label ){
- def node_path = Paths.get( node_label )
- return Files.exists( node_path )
- }
-
- /*--------------------------------------------------------------------------------
- Node type checks and marking
- */
-
- static Set all_node_type_set = ['symbol' ,'path' ,'leaf' ,'generator'] as Set
- static Set persistent_node_mark_set = ['cycle_member' ,'wellformed' ,'build_failed'] as Set
-
- static boolean leaf_q( Map node ){
- return node && node.type == 'leaf'
- }
-
- static boolean has_mark( Map node ){
- return node?.mark?.isNotEmpty()
- }
-
- static void set_mark( Map node ,String mark ){
- node.mark = node.mark ?: [] as Set
- node.mark << mark
- }
-
- static void clear_mark( Map node ,String mark ){
- node?.mark?.remove( mark )
- }
-
- static boolean marked_good_q( Map node ){
- return node && node.mark && ( 'wellformed' in node.mark ) && !( 'cycle_member' in node.mark ) && !( 'build_failed' in node.mark )
- }
-
- /*--------------------------------------------------------------------------------
- Well-formed Node Check
- */
-
- static Set all_form_error_set = [
- 'no_node'
- ,'node_must_have_label'
- ,'label_must_be_string'
- ,'node_must_have_type'
- ,'bad_node_type'
- ,'neighbor_value_must_be_list'
- ,'neighbor_reference_must_be_string'
- ,'mark_property_value_must_be_set'
- ,'unregistered_mark'
- ,'missing_required_build_code'
- ,'leaf_given_neighbor_property'
- ,'leaf_given_build_property'
- ] as Set
-
- static Set wellformed_q( Map node ){
- def form_error_set = [] as Set
-
- if( !node ){
- form_error_set << 'no_node'
- return form_error_set
- }
-
- if( !node.label )
- form_error_set << 'node_must_have_label'
- else if( !( node.label instanceof String ) )
- form_error_set << 'label_must_be_string'
-
- if( !node.type )
- form_error_set << 'node_must_have_type'
- else if( !( node.type instanceof String ) || !( node.type in all_node_type_set ) )
- form_error_set << 'bad_node_type'
-
- if( node.neighbor ){
- if( !( node.neighbor instanceof List ) )
- form_error_set << 'neighbor_value_must_be_list'
- else if( !( node.neighbor.every { it instanceof String } ) )
- form_error_set << 'neighbor_reference_must_be_string'
- }
-
- if( node.mark ){
- if( !( node.mark instanceof Set ) )
- form_error_set << 'mark_property_value_must_be_set'
- else if( !( node.mark.every { it in persistent_node_mark_set } ) )
- form_error_set << 'unregistered_mark'
- }
-
- if( node.type == 'path' && ( !node.build || !( node.build instanceof Closure ) ) )
- form_error_set << 'missing_required_build_code'
-
- if( node.type == 'leaf' ){
- if( node.neighbor ) form_error_set << 'leaf_given_neighbor_property'
- if( node.build ) form_error_set << 'leaf_given_build_property'
- }
-
- return form_error_set
- }
-
- /*--------------------------------------------------------------------------------
- Graph traversal and build functions
- */
-
- def lookup( String node_label ,boolean verbose = false ){
- def lookup_node = node_map[ node_label ]
- if( !lookup_node ){
- def match_result
- for( func in node_f_list ){
- match_result = func( node_label )
- if( match_result.status == "matched" ){
- lookup_node = match_result
- break
- }
- }
- }
-
- if( !lookup_node && verbose ) println "lookup:: Node ${node_label} could not be found."
- return lookup_node
- }
-
- def run_build_scripts_f( List root_node_labels ,boolean verbose = true ){
- if( root_node_labels.isEmpty() ) return
-
- def node_function = { node ,error_token_set ->
-
- if( !can_be_built_q( node ) ){
- println( "Skipping build for ${node.label} due to dependency problems" )
- return
- }
- if( !should_be_built_q( node ) ){
- if( verbose ) println( "${node.label} already up to date" )
- return
- }
-
- println( "Running build script for ${node.label}" )
- node.build( node ,node.neighbor )
-
- if( should_be_built_q( node ) ){
- println( "Build failed for ${node.label}" )
- set_mark( node ,'build_failed' )
- }
- }
-
- println( "run_build_scripts_f:: running ..." )
- all_DAG_DF( root_node_labels ,node_function ,verbose )
- }
-
- // Add the rest of your methods here as instance/static methods based on whether they depend on the graph instance
-
-}
-/*
- Some terms:
-
- a node is either malformed or 'wellformed'. A wellformed node meets
- the criteria set forth by `well_formed_node_q`.
-
- 'node': a dictionary, hopefully a wellformed one
- 'file node': a 'path' or 'leaf' type node.
- 'node file': for 'path' or 'leaf' nodes, path relative to the developer's directory.
-
- This code makes use of the following node properties:
- - label: Unique label string. Used to reference nodes.
- - type: The type of the node: 'leaf' ,'symbol' ,or 'path'.
- - neighbor: list of the neighbor nodes labels
- - must_have: list of node labels
- - build: Code that builds the node.
- - mark: a set of 'mark' tokens optionally placed on a node
-
- For 'path' and 'leaf' type nodes, the node label is a file path. Relative paths
- are relative to the developer's directory.
-
- The dependency graph is defined by the `lookup` function. `lookup` when given
- a node label returns the node, if found, or null.
-
-*/
-
-/*--------------------------------------------------------------------------------
- file utility functions
-*/
-
-def unpack_file_path = { file_fp ->
- def file = new File(file_fp)
-
- // Get the parent directory path
- def parent_dp = file_fn.getParent()
-
- // Get the file name (with extension)
- def file_fn = file_fn.getName()
-
- // Split the file name into base and extension
- def file_fn_base = file_fn.lastIndexOf('.') > 0 ? file_fn[0..file_fn.lastIndexOf('.') - 1] : file_fn
- def file_fn_ext = file_fn.lastIndexOf('.') > 0 ? file_fn[file_fn.lastIndexOf('.') + 1..-1] : ''
-
- // Return the components as a map for easier use
- return [
- parent_dp: parent_dp
- ,file_fn: file_fn
- ,file_fn_base: file_fn_base
- ,file_fn_ext: file_fn_ext
- ]
-}
-
-def file_exists_q(node_label) {
- def node_path = Paths.get(node_label)
- return Files.exists(node_path)
-}
-
-
-/*-------------------------------------------------------------------------------
- DAG adjectives
-
- node undefined for undefined node?
-*/
-
-// A node is type 'leaf' when the node file can not be deleted or replaced.
-// This type used to be called 'primary', which might be a better term.
-
-def all_node_type_set = ['symbol' ,'path' ,'leaf' ,'generator'] as Set
-
-def persistent_node_mark_set = ['cycle_member' ,'wellformed' ,'build_failed'] as Set
-def leaf_q = { node -> node && node.type && node.type == 'leaf' }
-
-// mark
-def has_mark = { node -> node.mark && !node.mark.isEmpty() }
-def set_mark(node ,mark){
- node.mark = node.mark ?: [] as Set
- node.mark << mark
-}
-def clear_mark(node ,mark){
- if( node.mark ) node.mark.remove(mark)
-}
-def marked_good_q(node){
- return (
- node
- && node.mark
- && ('wellformed' in node.mark)
- && !('cycle_member' in node.mark)
- && !('build_failed' in node.mark)
- )
-}
-
-
-
-/*--------------------------------------------------------------------------------
- Wellformed Node Check
-
- The developer defines the nodes, so their form needs to be checked.
-
- early bail on node not defined
- legal path in the build directory makedir -p ... not really a acquirement
-
-*/
-def all_form_error_set = [
- 'no_node'
- ,'node_must_have_label'
- ,'label_must_be_string'
- ,'node_must_have_type'
- ,'bad_node_type'
- ,'neighbor_value_must_be_list'
- ,'neighbor_reference_must_be_string'
- ,'mark_property_value_must_be_set'
- ,'unregistered_mark'
- ,'missing_required_build_code'
- ,'leaf_given_neighbor_property'
- ,'leaf_given_build_property'
-]
-def wellformed_q = { node ->
- def form_error_set = [] as Set
-
- if( !node ){
- form_error_set << 'no_node'
- return form_error_set
- }
-
- if( !node.label )
- form_error_set << 'node_must_have_label'
- else if( !(node.label instanceof String) )
- form_error_set << 'label_must_be_string'
-
- if( !node.type )
- form_error_set << 'node_must_have_type'
- else if( !(node.type instanceof String) || !(node.type in all_node_type_set) )
- form_error_set << 'bad_node_type'
-
- if( node.neighbor ){
- if( !(node.neighbor instanceof List) )
- form_error_set << 'neighbor_value_must_be_list'
- else if( !(node.neighbor.every { it instanceof String }) )
- form_error_set << 'neighbor_reference_must_be_string'
- }
-
- if( node.mark ){
- if( !(node.mark instanceof Set) )
- form_error_set << 'mark_property_value_must_be_set'
- else if( !(node.mark.every { it in persistent_node_mark_set }) )
- form_error_set << 'unregistered_mark'
- }
-
- // Removed test about symbol build needing neighbors
-
- if(
- node.type == "path"
- && (!node.build || !(node.build instanceof Closure))
- )
- form_error_set << 'missing_required_build_code'
-
- // Removed test about path needing neighbors
-
- // Can a primary file have neighbors or a build script? Our build model
- // has the node file as a target, the build script as a means of building
- // the target (hence its name), and the dependencies as inputs to the build
- // script. So in the spirit of this model, we will say "no".
- if( node.type == "leaf" ){
- if( node.neighbor ) form_error_set << 'leaf_given_neighbor_property'
- if( node.build ) form_error_set << 'leaf_given_build_property'
- }
-
- return form_error_set
-}
-
-
-
-/*--------------------------------------------------------------------------------
- A well formed graph checker. Traverses entire graph and marks nodes
- that are not well formed or that are part of a cycle.
-
-*/
-
-// given a node label list, adds the 'wellformed' mark to wellformed nodes.
-def mark_the_wellformed_f(node_label_list ,boolean verbose = true){
- def all_wellformed = true
-
- def neighbors = node_label_list.collect{ neighbor_label ->
- def neighbor_node = lookup(neighbor_label)
- def form_errors = wellformed_q(neighbor_node)
- if(form_errors.isEmpty()){
- neighbor_node.mark = neighbor_node.mark ?: [] as Set
- neighbor_node.mark << 'wellformed'
- } else {
- all_wellformed = false
- if(verbose){
- if(neighbor_node.label && neighbor_node.label.length() > 0){
- print("node ${neighbor_node.label} is malformed due to:")
- } else {
- print("anonymous node is malformed due to:")
- }
- form_errors.each { error -> print(" ${error}") }
- println("")
- }
- }
- neighbor_label
- }
-
- return all_wellformed ? 'all_wellformed' : 'exists_malformed'
-}
-
-// descends un-visited leftmost path, while marking nodes as wellformed and if
-// they are part of a cycle.
-def markup_graph_f_descend(path_stack ,boolean verbose = true){
- def ret_value = [] as Set
- def local_path = path_stack.collect{ it[0] }
- def local_node_label = local_path[-1]
- def cycle_start_index
-
- do{
- // Check for a cycle in the local path
- cycle_start_index = local_path[0..-2].findIndexOf{ it == local_node_label }
- if(cycle_start_index != -1){ // Cycle detected
- ret_value << 'cycle_found'
- if(verbose) print "markup_graph_f_descend:: dependency cycle found:"
- local_path[cycle_start_index..-1].each{ cycle_node_label ->
- def cycle_node = lookup(cycle_node_label)
- if(verbose) print " ${cycle_node.label}"
- cycle_node.mark = cycle_node.mark ?: [] as Set // Initialize mark set if needed
- cycle_node.mark << 'cycle_member'
- }
- if(verbose) println ""
- // we can not continue searching after the loop so ,we pop back to treat
- // the first node in the loop as though a leaf node.
- path_stack = path_stack[0..cycle_start_index]
- return ret_value
- }
-
- // a 'de-facto' leaf node test subtleties here because we have not yet
- // determined if the nodes we are wellformed. This is purposeful ,as
- // this function does not know about the relationships between the
- // possible error marks.
- def local_node = lookup(local_node_label)
- if(local_node.neighbor.isEmpty()){
- ret_value << 'defacto_leaf_node'
- return ret_value
- }
-
- // Mark the wellformed nodes and get the result
- def result = mark_the_wellformed_f(local_node.neighbor ,verbose)
- if(result == 'exists_malformed'){
- ret_value << 'exists_malformed'
- }
-
- // Descend further into the tree.
- path_stack << local_node.neighbor.clone()
- local_node_label = local_node.neighbor[0]
- local_path << local_node_label
- }while(true)
-}
-
-
-
-/*--------------------------------------------------------------------------------
- This function defines the graph.
-
- Lookup attempts to lookup a node label in the node_map, and failing that, it
- tries each label pattern recognition function in order.
-
- lookup_marked_good can be run after `wellformed_graph_f` has marked up the
- graph. It will only return a node if a) found b) that is 'good'.
- Note the `marked_good_q` adjective above.
-
-*/
-def lookup(node_label ,verbose = false){
- def lookup_node = node_map[node_label]
- if( lookup_node ){
- lookup_node.label = node_label
- } else {
- def match_result
- for(func in node_f_list){
- match_result = func(node_label)
- if(match_result.status == "matched"){
- lookup_node = match_result
- break
- }
- }
- }
- if( !lookup_node ){
- if( verbose ) println "lookup:: Node ${node_label} could not be found."
- return null
- }
- return lookup_node
-}
-
-// mark aware lookup function
-def lookup_marked_good(node_label ,verbose = false){
- def node = lookup(node_label ,verbose)
- if( node && marked_good_q(node) ) return node;
- return null;
-}
-
-
-/*
- Given `root_node_labels` of a DAG. Applies `node_function` to each node in a
- depth-first traversal order. Returns a set of error tokens encountered
- during traversal.
-
- `wellformed_graph_q` must be run on the DAG before this function is called ,or
- `lookup_marked_good` will not function correctly.
-*/
-def all_DAG_DF(root_node_labels ,node_function ,boolean verbose = true) {
- def error_token_set = [] as Set
-
- if (root_node_labels.isEmpty()) return error_token_set
-
- def visited = [] as Set
- def in_traversal_order = []
- def stack = []
-
- root_node_labels.each { root_label ->
- stack << root_label
- }
-
- do {
- def node_label = stack.pop()
-
- def node = lookup_marked_good(node_label ,verbose)
- if (!node) {
- error_token_set << 'lookup_fail'
- continue
- }
-
- if (node.label in visited) continue
- visited << node.label
-
- in_traversal_order << node
-
- node.neighbor.each { neighbor_label ->
- stack << neighbor_label
- }
- } while (!stack.isEmpty())
-
- in_traversal_order.reverse().each { node ->
- node_function(node ,error_token_set ,verbose)
- }
-
- return error_token_set
-}
-
-
-/*--------------------------------------------------------------------------------
- run the build scripts
- depends upon is_acyclic having already marked up the graph.
-*/
-
-import java.nio.file.Files
-import java.nio.file.Paths
-
-// a symbol dependency is good ,as long as it is built before the node in question
-def good_dependency_q(node_labels) {
- return node_labels.every { node_label ->
- def node = lookup_marked_good(node_label)
- if (!node) return false
- if (node.type in ['path' ,'leaf'] && !file_exists_q(node.label)) return false
- return true
- }
-}
-
-/*
- Given a node label and a list of node labels ,returns true if the file at the
- node label in the first argument is newer than all the files at the
- corresponding node labels in the second list.
-*/
-def newer_than_all(node_label ,node_label_list) {
- def node_path = Paths.get(node_label)
- if (!Files.exists(node_path)) return false
-
- def node_last_modified = Files.getLastModifiedTime(node_path).toMillis()
-
- return node_label_list.every { label ->
- def path = Paths.get(label)
- if (!Files.exists(path)) return false
- def last_modified = Files.getLastModifiedTime(path).toMillis()
- return node_last_modified > last_modified
- }
-}
-
-def can_be_built_q(node){
- if( !marked_good_q(node) ) return false;
- if(
- (node.type == 'symbol' || type == 'path')
- && !good_dependency_q( node.neighbor )
- ){
- return false
- }
- if(
- node.type == 'leaf'
- && !file_exists_q(node.label)
- ){
- return false;
- }
- return true
-}
-
-// `can_be_build_q` must be true for this to be meaningful:
-def should_be_built_q(node ,verbose = true) {
- if(node.type == 'leaf') return false
- if(node.type == 'symbol') return true
- if( node.type == 'path') return !newer_than_all(node.label ,node.neighbor)
- println("should_be_build_q:: unrecognized node type ,so assuming it should not be built.")
- return false
-}
-
-/*
- Runs build scripts for the given root_node_labels in a depth-first traversal order.
- Uses `all_DAG_DF` to traverse the graph and applies the build function to each node.
-
- Be sure that `wellformed_graph_q` has been run on DAG.
-
- Be sure that the 'build_failed' marks have been cleared if this is not the
- first build attempt.
-
-*/
-def run_build_scripts_f(root_node_labels ,boolean verbose = true){
- if( root_node_labels.isEmpty() ) return
-
- // Define the function to be applied to each node
- def node_function = { node ,error_token_set ->
-
- if( !can_be_built_q(node) ){
- println("Skipping build for ${node.label} due to dependency problems or found leaf is missing")
- return
- }
-
- if( !should_be_built_q(node) ){
- if(verbose) println("${node.label} already up to date")
- return
- }
-
- // if we get here, node can and should be built
-
- println("Running build script for ${node.label}")
- node.build(node ,node.neighbor)
-
- // Check if the build updated the target file
- if( should_be_built_q(node) ){
- println("Build failed for ${node.label}")
- set_mark(node ,'build_failed')
- }
-
- }
-
- println("run_build_scripts_f:: running ...")
- // Apply the function to all nodes in a depth-first manner
- all_DAG_DF(root_node_labels ,node_function ,verbose)
-}
-
-
-// LocalWords: FN FPL DN DNL RuleNameListRegx RuleNameList PrintVisitorMethod
-// LocalWords: PrintVisitor SyntaxAnnotate wellformed defacto acyclic
-// LocalWords: wellformed unvisited
diff --git a/developer/deprecated/Ariandne2.groovy b/developer/deprecated/Ariandne2.groovy
new file mode 100644
index 0000000..6c0cf17
--- /dev/null
+++ b/developer/deprecated/Ariandne2.groovy
@@ -0,0 +1,635 @@
+class AriadneGraph {
+
+ // Instance variables for graph data if needed
+ Map node_map = [:]
+ List node_f_list = []
+
+ // Constructor to accept a graph definition (node_map and node_f_list)
+ AriadneGraph( Map node_map ,List node_f_list ){
+ this.node_map = node_map ?: [:]
+ this.node_f_list = node_f_list ?: []
+ }
+
+ /*--------------------------------------------------------------------------------
+ File utility functions
+ */
+
+ static Map unpack_file_path( String file_fp ){
+ def file = new File( file_fp )
+
+ def parent_dp = file.getParent()
+ def file_fn = file.getName()
+ def file_fn_base = file_fn.lastIndexOf('.') > 0 ? file_fn[ 0..file_fn.lastIndexOf('.') - 1 ] : file_fn
+ def file_fn_ext = file_fn.lastIndexOf('.') > 0 ? file_fn[ file_fn.lastIndexOf('.') + 1..-1 ] : ''
+
+ return [
+ parent_dp: parent_dp
+ ,file_fn: file_fn
+ ,file_fn_base: file_fn_base
+ ,file_fn_ext: file_fn_ext
+ ]
+ }
+
+ static boolean file_exists_q( String node_label ){
+ def node_path = Paths.get( node_label )
+ return Files.exists( node_path )
+ }
+
+ /*--------------------------------------------------------------------------------
+ Node type checks and marking
+ */
+
+ static Set all_node_type_set = ['symbol' ,'path' ,'leaf' ,'generator'] as Set
+ static Set persistent_node_mark_set = ['cycle_member' ,'wellformed' ,'build_failed'] as Set
+
+ static boolean leaf_q( Map node ){
+ return node && node.type == 'leaf'
+ }
+
+ static boolean has_mark( Map node ){
+ return node?.mark?.isNotEmpty()
+ }
+
+ static void set_mark( Map node ,String mark ){
+ node.mark = node.mark ?: [] as Set
+ node.mark << mark
+ }
+
+ static void clear_mark( Map node ,String mark ){
+ node?.mark?.remove( mark )
+ }
+
+ static boolean marked_good_q( Map node ){
+ return node && node.mark && ( 'wellformed' in node.mark ) && !( 'cycle_member' in node.mark ) && !( 'build_failed' in node.mark )
+ }
+
+ /*--------------------------------------------------------------------------------
+ Well-formed Node Check
+ */
+
+ static Set all_form_error_set = [
+ 'no_node'
+ ,'node_must_have_label'
+ ,'label_must_be_string'
+ ,'node_must_have_type'
+ ,'bad_node_type'
+ ,'neighbor_value_must_be_list'
+ ,'neighbor_reference_must_be_string'
+ ,'mark_property_value_must_be_set'
+ ,'unregistered_mark'
+ ,'missing_required_build_code'
+ ,'leaf_given_neighbor_property'
+ ,'leaf_given_build_property'
+ ] as Set
+
+ static Set wellformed_q( Map node ){
+ def form_error_set = [] as Set
+
+ if( !node ){
+ form_error_set << 'no_node'
+ return form_error_set
+ }
+
+ if( !node.label )
+ form_error_set << 'node_must_have_label'
+ else if( !( node.label instanceof String ) )
+ form_error_set << 'label_must_be_string'
+
+ if( !node.type )
+ form_error_set << 'node_must_have_type'
+ else if( !( node.type instanceof String ) || !( node.type in all_node_type_set ) )
+ form_error_set << 'bad_node_type'
+
+ if( node.neighbor ){
+ if( !( node.neighbor instanceof List ) )
+ form_error_set << 'neighbor_value_must_be_list'
+ else if( !( node.neighbor.every { it instanceof String } ) )
+ form_error_set << 'neighbor_reference_must_be_string'
+ }
+
+ if( node.mark ){
+ if( !( node.mark instanceof Set ) )
+ form_error_set << 'mark_property_value_must_be_set'
+ else if( !( node.mark.every { it in persistent_node_mark_set } ) )
+ form_error_set << 'unregistered_mark'
+ }
+
+ if( node.type == 'path' && ( !node.build || !( node.build instanceof Closure ) ) )
+ form_error_set << 'missing_required_build_code'
+
+ if( node.type == 'leaf' ){
+ if( node.neighbor ) form_error_set << 'leaf_given_neighbor_property'
+ if( node.build ) form_error_set << 'leaf_given_build_property'
+ }
+
+ return form_error_set
+ }
+
+ /*--------------------------------------------------------------------------------
+ Graph traversal and build functions
+ */
+
+ def lookup( String node_label ,boolean verbose = false ){
+ def lookup_node = node_map[ node_label ]
+ if( !lookup_node ){
+ def match_result
+ for( func in node_f_list ){
+ match_result = func( node_label )
+ if( match_result.status == "matched" ){
+ lookup_node = match_result
+ break
+ }
+ }
+ }
+
+ if( !lookup_node && verbose ) println "lookup:: Node ${node_label} could not be found."
+ return lookup_node
+ }
+
+ def run_build_scripts_f( List root_node_labels ,boolean verbose = true ){
+ if( root_node_labels.isEmpty() ) return
+
+ def node_function = { node ,error_token_set ->
+
+ if( !can_be_built_q( node ) ){
+ println( "Skipping build for ${node.label} due to dependency problems" )
+ return
+ }
+ if( !should_be_built_q( node ) ){
+ if( verbose ) println( "${node.label} already up to date" )
+ return
+ }
+
+ println( "Running build script for ${node.label}" )
+ node.build( node ,node.neighbor )
+
+ if( should_be_built_q( node ) ){
+ println( "Build failed for ${node.label}" )
+ set_mark( node ,'build_failed' )
+ }
+ }
+
+ println( "run_build_scripts_f:: running ..." )
+ all_DAG_DF( root_node_labels ,node_function ,verbose )
+ }
+
+ // Add the rest of your methods here as instance/static methods based on whether they depend on the graph instance
+
+}
+/*
+ Some terms:
+
+ a node is either malformed or 'wellformed'. A wellformed node meets
+ the criteria set forth by `well_formed_node_q`.
+
+ 'node': a dictionary, hopefully a wellformed one
+ 'file node': a 'path' or 'leaf' type node.
+ 'node file': for 'path' or 'leaf' nodes, path relative to the developer's directory.
+
+ This code makes use of the following node properties:
+ - label: Unique label string. Used to reference nodes.
+ - type: The type of the node: 'leaf' ,'symbol' ,or 'path'.
+ - neighbor: list of the neighbor nodes labels
+ - must_have: list of node labels
+ - build: Code that builds the node.
+ - mark: a set of 'mark' tokens optionally placed on a node
+
+ For 'path' and 'leaf' type nodes, the node label is a file path. Relative paths
+ are relative to the developer's directory.
+
+ The dependency graph is defined by the `lookup` function. `lookup` when given
+ a node label returns the node, if found, or null.
+
+*/
+
+/*--------------------------------------------------------------------------------
+ file utility functions
+*/
+
+def unpack_file_path = { file_fp ->
+ def file = new File(file_fp)
+
+ // Get the parent directory path
+ def parent_dp = file_fn.getParent()
+
+ // Get the file name (with extension)
+ def file_fn = file_fn.getName()
+
+ // Split the file name into base and extension
+ def file_fn_base = file_fn.lastIndexOf('.') > 0 ? file_fn[0..file_fn.lastIndexOf('.') - 1] : file_fn
+ def file_fn_ext = file_fn.lastIndexOf('.') > 0 ? file_fn[file_fn.lastIndexOf('.') + 1..-1] : ''
+
+ // Return the components as a map for easier use
+ return [
+ parent_dp: parent_dp
+ ,file_fn: file_fn
+ ,file_fn_base: file_fn_base
+ ,file_fn_ext: file_fn_ext
+ ]
+}
+
+def file_exists_q(node_label) {
+ def node_path = Paths.get(node_label)
+ return Files.exists(node_path)
+}
+
+
+/*-------------------------------------------------------------------------------
+ DAG adjectives
+
+ node undefined for undefined node?
+*/
+
+// A node is type 'leaf' when the node file can not be deleted or replaced.
+// This type used to be called 'primary', which might be a better term.
+
+def all_node_type_set = ['symbol' ,'path' ,'leaf' ,'generator'] as Set
+
+def persistent_node_mark_set = ['cycle_member' ,'wellformed' ,'build_failed'] as Set
+def leaf_q = { node -> node && node.type && node.type == 'leaf' }
+
+// mark
+def has_mark = { node -> node.mark && !node.mark.isEmpty() }
+def set_mark(node ,mark){
+ node.mark = node.mark ?: [] as Set
+ node.mark << mark
+}
+def clear_mark(node ,mark){
+ if( node.mark ) node.mark.remove(mark)
+}
+def marked_good_q(node){
+ return (
+ node
+ && node.mark
+ && ('wellformed' in node.mark)
+ && !('cycle_member' in node.mark)
+ && !('build_failed' in node.mark)
+ )
+}
+
+
+
+/*--------------------------------------------------------------------------------
+ Wellformed Node Check
+
+ The developer defines the nodes, so their form needs to be checked.
+
+ early bail on node not defined
+ legal path in the build directory makedir -p ... not really a acquirement
+
+*/
+def all_form_error_set = [
+ 'no_node'
+ ,'node_must_have_label'
+ ,'label_must_be_string'
+ ,'node_must_have_type'
+ ,'bad_node_type'
+ ,'neighbor_value_must_be_list'
+ ,'neighbor_reference_must_be_string'
+ ,'mark_property_value_must_be_set'
+ ,'unregistered_mark'
+ ,'missing_required_build_code'
+ ,'leaf_given_neighbor_property'
+ ,'leaf_given_build_property'
+]
+def wellformed_q = { node ->
+ def form_error_set = [] as Set
+
+ if( !node ){
+ form_error_set << 'no_node'
+ return form_error_set
+ }
+
+ if( !node.label )
+ form_error_set << 'node_must_have_label'
+ else if( !(node.label instanceof String) )
+ form_error_set << 'label_must_be_string'
+
+ if( !node.type )
+ form_error_set << 'node_must_have_type'
+ else if( !(node.type instanceof String) || !(node.type in all_node_type_set) )
+ form_error_set << 'bad_node_type'
+
+ if( node.neighbor ){
+ if( !(node.neighbor instanceof List) )
+ form_error_set << 'neighbor_value_must_be_list'
+ else if( !(node.neighbor.every { it instanceof String }) )
+ form_error_set << 'neighbor_reference_must_be_string'
+ }
+
+ if( node.mark ){
+ if( !(node.mark instanceof Set) )
+ form_error_set << 'mark_property_value_must_be_set'
+ else if( !(node.mark.every { it in persistent_node_mark_set }) )
+ form_error_set << 'unregistered_mark'
+ }
+
+ // Removed test about symbol build needing neighbors
+
+ if(
+ node.type == "path"
+ && (!node.build || !(node.build instanceof Closure))
+ )
+ form_error_set << 'missing_required_build_code'
+
+ // Removed test about path needing neighbors
+
+ // Can a primary file have neighbors or a build script? Our build model
+ // has the node file as a target, the build script as a means of building
+ // the target (hence its name), and the dependencies as inputs to the build
+ // script. So in the spirit of this model, we will say "no".
+ if( node.type == "leaf" ){
+ if( node.neighbor ) form_error_set << 'leaf_given_neighbor_property'
+ if( node.build ) form_error_set << 'leaf_given_build_property'
+ }
+
+ return form_error_set
+}
+
+
+
+/*--------------------------------------------------------------------------------
+ A well formed graph checker. Traverses entire graph and marks nodes
+ that are not well formed or that are part of a cycle.
+
+*/
+
+// given a node label list, adds the 'wellformed' mark to wellformed nodes.
+def mark_the_wellformed_f(node_label_list ,boolean verbose = true){
+ def all_wellformed = true
+
+ def neighbors = node_label_list.collect{ neighbor_label ->
+ def neighbor_node = lookup(neighbor_label)
+ def form_errors = wellformed_q(neighbor_node)
+ if(form_errors.isEmpty()){
+ neighbor_node.mark = neighbor_node.mark ?: [] as Set
+ neighbor_node.mark << 'wellformed'
+ } else {
+ all_wellformed = false
+ if(verbose){
+ if(neighbor_node.label && neighbor_node.label.length() > 0){
+ print("node ${neighbor_node.label} is malformed due to:")
+ } else {
+ print("anonymous node is malformed due to:")
+ }
+ form_errors.each { error -> print(" ${error}") }
+ println("")
+ }
+ }
+ neighbor_label
+ }
+
+ return all_wellformed ? 'all_wellformed' : 'exists_malformed'
+}
+
+// descends un-visited leftmost path, while marking nodes as wellformed and if
+// they are part of a cycle.
+def markup_graph_f_descend(path_stack ,boolean verbose = true){
+ def ret_value = [] as Set
+ def local_path = path_stack.collect{ it[0] }
+ def local_node_label = local_path[-1]
+ def cycle_start_index
+
+ do{
+ // Check for a cycle in the local path
+ cycle_start_index = local_path[0..-2].findIndexOf{ it == local_node_label }
+ if(cycle_start_index != -1){ // Cycle detected
+ ret_value << 'cycle_found'
+ if(verbose) print "markup_graph_f_descend:: dependency cycle found:"
+ local_path[cycle_start_index..-1].each{ cycle_node_label ->
+ def cycle_node = lookup(cycle_node_label)
+ if(verbose) print " ${cycle_node.label}"
+ cycle_node.mark = cycle_node.mark ?: [] as Set // Initialize mark set if needed
+ cycle_node.mark << 'cycle_member'
+ }
+ if(verbose) println ""
+ // we can not continue searching after the loop so ,we pop back to treat
+ // the first node in the loop as though a leaf node.
+ path_stack = path_stack[0..cycle_start_index]
+ return ret_value
+ }
+
+ // a 'de-facto' leaf node test subtleties here because we have not yet
+ // determined if the nodes we are wellformed. This is purposeful ,as
+ // this function does not know about the relationships between the
+ // possible error marks.
+ def local_node = lookup(local_node_label)
+ if(local_node.neighbor.isEmpty()){
+ ret_value << 'defacto_leaf_node'
+ return ret_value
+ }
+
+ // Mark the wellformed nodes and get the result
+ def result = mark_the_wellformed_f(local_node.neighbor ,verbose)
+ if(result == 'exists_malformed'){
+ ret_value << 'exists_malformed'
+ }
+
+ // Descend further into the tree.
+ path_stack << local_node.neighbor.clone()
+ local_node_label = local_node.neighbor[0]
+ local_path << local_node_label
+ }while(true)
+}
+
+
+
+/*--------------------------------------------------------------------------------
+ This function defines the graph.
+
+ Lookup attempts to lookup a node label in the node_map, and failing that, it
+ tries each label pattern recognition function in order.
+
+ lookup_marked_good can be run after `wellformed_graph_f` has marked up the
+ graph. It will only return a node if a) found b) that is 'good'.
+ Note the `marked_good_q` adjective above.
+
+*/
+def lookup(node_label ,verbose = false){
+ def lookup_node = node_map[node_label]
+ if( lookup_node ){
+ lookup_node.label = node_label
+ } else {
+ def match_result
+ for(func in node_f_list){
+ match_result = func(node_label)
+ if(match_result.status == "matched"){
+ lookup_node = match_result
+ break
+ }
+ }
+ }
+ if( !lookup_node ){
+ if( verbose ) println "lookup:: Node ${node_label} could not be found."
+ return null
+ }
+ return lookup_node
+}
+
+// mark aware lookup function
+def lookup_marked_good(node_label ,verbose = false){
+ def node = lookup(node_label ,verbose)
+ if( node && marked_good_q(node) ) return node;
+ return null;
+}
+
+
+/*
+ Given `root_node_labels` of a DAG. Applies `node_function` to each node in a
+ depth-first traversal order. Returns a set of error tokens encountered
+ during traversal.
+
+ `wellformed_graph_q` must be run on the DAG before this function is called ,or
+ `lookup_marked_good` will not function correctly.
+*/
+def all_DAG_DF(root_node_labels ,node_function ,boolean verbose = true) {
+ def error_token_set = [] as Set
+
+ if (root_node_labels.isEmpty()) return error_token_set
+
+ def visited = [] as Set
+ def in_traversal_order = []
+ def stack = []
+
+ root_node_labels.each { root_label ->
+ stack << root_label
+ }
+
+ do {
+ def node_label = stack.pop()
+
+ def node = lookup_marked_good(node_label ,verbose)
+ if (!node) {
+ error_token_set << 'lookup_fail'
+ continue
+ }
+
+ if (node.label in visited) continue
+ visited << node.label
+
+ in_traversal_order << node
+
+ node.neighbor.each { neighbor_label ->
+ stack << neighbor_label
+ }
+ } while (!stack.isEmpty())
+
+ in_traversal_order.reverse().each { node ->
+ node_function(node ,error_token_set ,verbose)
+ }
+
+ return error_token_set
+}
+
+
+/*--------------------------------------------------------------------------------
+ run the build scripts
+ depends upon is_acyclic having already marked up the graph.
+*/
+
+import java.nio.file.Files
+import java.nio.file.Paths
+
+// a symbol dependency is good ,as long as it is built before the node in question
+def good_dependency_q(node_labels) {
+ return node_labels.every { node_label ->
+ def node = lookup_marked_good(node_label)
+ if (!node) return false
+ if (node.type in ['path' ,'leaf'] && !file_exists_q(node.label)) return false
+ return true
+ }
+}
+
+/*
+ Given a node label and a list of node labels ,returns true if the file at the
+ node label in the first argument is newer than all the files at the
+ corresponding node labels in the second list.
+*/
+def newer_than_all(node_label ,node_label_list) {
+ def node_path = Paths.get(node_label)
+ if (!Files.exists(node_path)) return false
+
+ def node_last_modified = Files.getLastModifiedTime(node_path).toMillis()
+
+ return node_label_list.every { label ->
+ def path = Paths.get(label)
+ if (!Files.exists(path)) return false
+ def last_modified = Files.getLastModifiedTime(path).toMillis()
+ return node_last_modified > last_modified
+ }
+}
+
+def can_be_built_q(node){
+ if( !marked_good_q(node) ) return false;
+ if(
+ (node.type == 'symbol' || type == 'path')
+ && !good_dependency_q( node.neighbor )
+ ){
+ return false
+ }
+ if(
+ node.type == 'leaf'
+ && !file_exists_q(node.label)
+ ){
+ return false;
+ }
+ return true
+}
+
+// `can_be_build_q` must be true for this to be meaningful:
+def should_be_built_q(node ,verbose = true) {
+ if(node.type == 'leaf') return false
+ if(node.type == 'symbol') return true
+ if( node.type == 'path') return !newer_than_all(node.label ,node.neighbor)
+ println("should_be_build_q:: unrecognized node type ,so assuming it should not be built.")
+ return false
+}
+
+/*
+ Runs build scripts for the given root_node_labels in a depth-first traversal order.
+ Uses `all_DAG_DF` to traverse the graph and applies the build function to each node.
+
+ Be sure that `wellformed_graph_q` has been run on DAG.
+
+ Be sure that the 'build_failed' marks have been cleared if this is not the
+ first build attempt.
+
+*/
+def run_build_scripts_f(root_node_labels ,boolean verbose = true){
+ if( root_node_labels.isEmpty() ) return
+
+ // Define the function to be applied to each node
+ def node_function = { node ,error_token_set ->
+
+ if( !can_be_built_q(node) ){
+ println("Skipping build for ${node.label} due to dependency problems or found leaf is missing")
+ return
+ }
+
+ if( !should_be_built_q(node) ){
+ if(verbose) println("${node.label} already up to date")
+ return
+ }
+
+ // if we get here, node can and should be built
+
+ println("Running build script for ${node.label}")
+ node.build(node ,node.neighbor)
+
+ // Check if the build updated the target file
+ if( should_be_built_q(node) ){
+ println("Build failed for ${node.label}")
+ set_mark(node ,'build_failed')
+ }
+
+ }
+
+ println("run_build_scripts_f:: running ...")
+ // Apply the function to all nodes in a depth-first manner
+ all_DAG_DF(root_node_labels ,node_function ,verbose)
+}
+
+
+// LocalWords: FN FPL DN DNL RuleNameListRegx RuleNameList PrintVisitorMethod
+// LocalWords: PrintVisitor SyntaxAnnotate wellformed defacto acyclic
+// LocalWords: wellformed unvisited
diff --git a/developer/deprecated/Graph.java b/developer/deprecated/Graph.java
new file mode 100644
index 0000000..3052338
--- /dev/null
+++ b/developer/deprecated/Graph.java
@@ -0,0 +1,685 @@
+package Ariadne;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+
+public class Graph {
+
+ /*--------------------------------------------------------------------------------
+ type aliases
+ */
+ public class TokenSet extends HashSet{}
+ public class LabelList extends ArrayList
-
However, when attempting applying this method in practice it became
- apparent that the recognition of relationships was insufficient. Consider
- the directories `deprecated` and `scratch_pad`. There is no
- 'Mr. Deprecated' or 'Mr. Scratch_Pad' who the contained files are
- for. (And this conclusion is not for the lack of trying. Even mythological
- beings did not suffice as agents.) Rather than saying a file has a
- relationship with an agent, these properties (directory names) are states
- imposed by decree by an agent on a file. Perhaps the developer, has
+
When attempting to apply the is-for property in practice it
+ became apparent that using this sole property was insufficient. Consider
+ the directories deprecated/ and scratch_pad/. There is no
+ Mr. Deprecated or Mr. Scratch_Pad who the contained
+ files are for. (And this conclusion is not for the lack of trying. Even
+ mythological beings did not suffice as agents.) Rather than being for an
+ agent, the files collected in such a directory have in common a state of
+ being that was imposed upon them by decree. Perhaps the developer, has
decreed that a file is now deprecated, or a build script has decreed that
it is a scratch_pad file. Such decrees are typically more dynamic than the
relationship properties. Also, these properties are disconnected from the
- contents of the file. When, for example, we say a file is for the java
- compiler we can surmise something about its contents. However when we say
- a file is `deprecated` we can surmise nothing about its contents.
+ contents of the file. When, for example, a file has the property of being
+ for the java compiler, we gain some information about its contents. In the
+ universe of possible messages sent through a file, such a file will
+ contain text that is proposed to be java syntax conforming. In contrast,
+ when we learn that a file is deprecated/ we gain no
+ information about the contents of the file, because any file can
+ be deprecated, independent of its contents.
To understand a directory name within this system, one can imagine
reading said name as part of a sentence that integrates the
- property. Consider two property names: 'is-a' and 'is-for'. For example,
- "Each file in the document/ directory is a document," or
- "Each file in the developer/ directory is for the developer."
- Although the property name is not carried over to the conventional file
- system, we can typically infer what it must be. It is beyond the scope of
- discussion here, but in actuality, our collections are defined by
- predicates that are given a file's properties and relationships as
- arguments, where the predicate resolves to true if and only if the file
- belongs to the collection. Now wouldn't that be interesting if we
- instead derived a probability?
+ property. Consider two property names: is-a
+ and is-for. For example, "Each file in
+ the document/ directory is-a document," or "Each
+ file in the developer/ directory is-for the
+ developer." Although the property name is not carried over from the
+ property based file system to the conventional file system, we can
+ typically infer what it must have been. (It is beyond the scope of
+ discussion here, but in actuality, property based file system collections
+ are defined by predicates. Each predicate is given a file's properties and
+ relationships as arguments, then resolves to true if and only if the file
+ belongs to the collection. Now wouldn't that be interesting if we instead
+ derived a probability?)
It is uncommon for a property value to be plural. While it is not
@@ -159,8 +190,8 @@
property. Hence when we make a file collection based on a shared property,
then carry that over as a directory name in a conventional file system,
the resulting directory name will often be singular. This pattern can be
- observed in the case of the `document/` directory, as shown in the prior
- paragraph.
+ observed in the case of the document/ directory, as shown in
+ the prior paragraph.
diff --git a/release/.githolder b/release/.githolder
new file mode 100644
index 0000000..e69de29
diff --git a/release/black b/release/black
new file mode 100755
index 0000000..d94d9cb
--- /dev/null
+++ b/release/black
@@ -0,0 +1,2 @@
+#!/bin/bash
+java com/ReasoningTechnology/PaintIt/Black
diff --git a/release/blue b/release/blue
new file mode 100755
index 0000000..387f82a
--- /dev/null
+++ b/release/blue
@@ -0,0 +1,2 @@
+#!/bin/bash
+java com/ReasoningTechnology/PaintIt/Blue
diff --git a/release/green b/release/green
new file mode 100755
index 0000000..9611a51
--- /dev/null
+++ b/release/green
@@ -0,0 +1,2 @@
+#!/bin/bash
+java com/ReasoningTechnology/PaintIt/Green
diff --git a/release_candidate/.githolder b/release_candidate/.githolder
deleted file mode 100644
index e69de29..0000000
diff --git a/release_candidate/black b/release_candidate/black
deleted file mode 100755
index d94d9cb..0000000
--- a/release_candidate/black
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-java com/ReasoningTechnology/PaintIt/Black
diff --git a/release_candidate/blue b/release_candidate/blue
deleted file mode 100755
index 387f82a..0000000
--- a/release_candidate/blue
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-java com/ReasoningTechnology/PaintIt/Blue
diff --git a/release_candidate/green b/release_candidate/green
deleted file mode 100755
index 9611a51..0000000
--- a/release_candidate/green
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-java com/ReasoningTechnology/PaintIt/Green
diff --git a/tester/javac/TestBench.java b/tester/javac/TestBench.java
new file mode 100644
index 0000000..0a9de3d
--- /dev/null
+++ b/tester/javac/TestBench.java
@@ -0,0 +1,29 @@
+import java.util.Map;
+
+public class TestBench {
+
+ public static void runTest_Map(Map test_map){
+ int totalTest_Map = test_map.size();
+ int passedTest_Map = 0;
+ int failedTest_Map = 0;
+
+ for( Map.Entry test : test_map.entrySet() ){
+ try{
+ if( test.getValue() ){
+ passedTest_Map++;
+ } else{
+ System.out.println( "failed: " + test.getKey() );
+ failedTest_Map++;
+ }
+ } catch(Exception e){
+ System.out.println( "failed: " + test.getKey() );
+ failedTest_Map++;
+ }
+ }
+
+ System.out.println("Total test_map run: " + totalTest_Map);
+ System.out.println("Total test_map passed: " + passedTest_Map);
+ System.out.println("Total test_map failed: " + failedTest_Map);
+ }
+
+}
diff --git a/tester/tool/env b/tester/tool/env
new file mode 100644
index 0000000..a630a47
--- /dev/null
+++ b/tester/tool/env
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+## input guards
+
+# instead of bailing, we will go fetch what we need
+env_should_be="tool_shared/bespoke/env"
+if [ "$ENV" != "$env_should_be" ]; then
+ source "$REPO_HOME"/"$env_should_be"
+fi
+
+if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
+ echo "$script_name:: This script must be sourced, not executed."
+ exit 1
+fi
+
+cd "$REPO_HOME"/tester/
+
+export ENV=$(script_fp)
+export PROJECT="$PROJECT"_tester
+
+export PATH=\
+"$REPO_HOME"/tester/tool/\
+:"$REPO_HOME"/tool_shared/bespoke/\
+"$JAVA_HOME"/bin\
+:"$PATH"
+
+export CLASSPATH=\
+:"$REPO_HOME"/developer/release/Ariadne.jar\
+:"$JAVA_HOME"/lib\
+:"$CLASSPATH"
+
+echo "$ENV complete."
diff --git a/tester/tool/env_tester b/tester/tool/env_tester
deleted file mode 100644
index eb6b6c7..0000000
--- a/tester/tool/env_tester
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-# environment common to all tests
-# each test directory also has an environment
-
-export JAVA_HOME="$REPO_HOME/tool/jdk-11"
-export GROOVY_HOME="$REPO_HOME/tool/groovy-4.0.9"
-
-export PATH=\
-"$REPO_HOME"/release_candidate\
-:"$JAVA_HOME"/bin\
-:"$GROOVY_HOME"/bin\
-:"$PATH"
diff --git a/tester/tool/make b/tester/tool/make
new file mode 100755
index 0000000..c9aca35
--- /dev/null
+++ b/tester/tool/make
@@ -0,0 +1,12 @@
+#!/bin/env bash
+
+script_name=$(basename ${BASH_SOURCE[0]})
+if [ -z "$ENV_TESTER_LOCAL" ]; then
+ echo "make.sh:: script can only be run in the tester environment"
+ env_error=true
+fi
+
+
+
+
+echo "$script_name done."
diff --git a/tester/tool/make.sh b/tester/tool/make.sh
deleted file mode 100755
index 4ecb729..0000000
--- a/tester/tool/make.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/env bash
-
-if [ -z "$ENV_TESTER" ]; then
- echo "make.sh:: script can only be run in the tester environment"
- env_error=true
-fi
-
-set -x
-
-groovyc TestGraph.groovy
diff --git a/tool/env b/tool/env
new file mode 100644
index 0000000..830913d
--- /dev/null
+++ b/tool/env
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+script_name=$(basename ${BASH_SOURCE[0]})
+if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
+ echo "$script_name must be sourced, not executed. Exiting."
+ exit 1
+fi
+
+if [ -z "$ENV_BASE" ]; then
+ script_path="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
+ source "${script_path}/env_base"
+fi
+
+ENV_PM=true
+
+PROJECT="$PROJECT"_administrator
+
+export PATH=\
+"$REPO_HOME"/tool\
+:"$PATH"
+
+# no sneaky hidden files
+alias ls="ls -a"
+
+export ENV_PM=true
+echo "$script_name done."
+
diff --git a/tool/env_administrator b/tool/env_administrator
deleted file mode 100644
index b85bd37..0000000
--- a/tool/env_administrator
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-
-# Ensure the script is sourced
-if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
- echo "This script must be sourced, not executed. Exiting."
- return 1
-fi
-
-if [ -z "$ENV_BASE" ]; then
- script_path="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
- source "${script_path}/env_base"
-fi
-
-ENV_PM=true
-
-PROJECT="$PROJECT"_administrator
-
-export PATH=\
-"$REPO_HOME"/tool\
-:"$PATH"
-
-# no sneaky hidden files
-alias ls="ls -a"
-
-
-export ENV_PM=true
-echo "${BASH_SOURCE[0]}" "complete"
diff --git a/tool/env_base b/tool/env_base
deleted file mode 100644
index ff49183..0000000
--- a/tool/env_base
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-
-# Ensure the script is sourced
-if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
- echo "This script must be sourced, not executed. Exiting."
- return 1
-fi
-
-# These are things set by the `repo` command found in the `resource` project,
-# but if you don't have that, then source this into the environment.
-
-script_path="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
-export REPO_HOME="${script_path%/*}/"
-export PROJECT=$(basename "$REPO_HOME")
-
-PPS1="\n[$PROJECT]\n\u@\h§$(pwd)§\n> "
-PPS2=">> "
-
-echo REPO_HOME "$REPO_HOME"
-echo PROJECT "$PROJECT"
-echo "${BASH_SOURCE[0]}" "complete"
-
-export ENV_BASE=true
diff --git a/tool/env_developer b/tool/env_developer
deleted file mode 100644
index b1c5ffa..0000000
--- a/tool/env_developer
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-
-# Ensure the script is sourced
-if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
- echo "This script must be sourced, not executed. Exiting."
- return 1
-fi
-
-if [ -z "$ENV_BASE" ]; then
- script_path="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
- source "${script_path}/env_base"
-fi
-
-PROJECT="$PROJECT"_developer
-
-export PATH=\
-"$REPO_HOME"/developer/tool/\
-:"$REPO_HOME"/tool_shared/bespoke/\
-:"$PATH"
-
-# so the .gitignore files can be seen:
-alias ls="ls -a"
-
-cd "$REPO_HOME"/developer/
-export ENV_DEVELOPER=true
-source tool/env
-
-echo "${BASH_SOURCE[0]}" "complete"
-
-
-
diff --git a/tool/env_tester b/tool/env_tester
deleted file mode 100644
index 7a52fe9..0000000
--- a/tool/env_tester
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-
-# Ensure the script is sourced
-if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
- echo "This script must be sourced, not executed. Exiting."
- return 1
-fi
-
-# Check if REPO_HOME is set, if not source env_base
-if [ -z "$ENV_BASE" ]; then
- script_path="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
- source "${script_path}/env_base"
-fi
-
-PROJECT="$PROJECT"_TESTER
-
-export PATH=\
-"$REPO_HOME"/tester/executor/\
-:"$REPO_HOME"/tool_shared/bespoke/\
-:"$PATH"
-
-cd "$REPO_HOME"/tester/
-export ENV_TESTER=true
-source tool/env
-
-echo "${BASH_SOURCE[0]}" "complete"
diff --git a/tool_shared/bespoke/deprecate b/tool_shared/bespoke/deprecate
new file mode 100755
index 0000000..821e7ab
--- /dev/null
+++ b/tool_shared/bespoke/deprecate
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# cp subtree at under file path , and make all the copied
+# files read-only. The intended use case is for moving files to a `deprecated`
+# directory. This helps prevent subsequent accidental editing.
+
+SCRIPT_NAME=$(basename "$0")
+if [ "$#" -lt 2 ]; then
+ echo "Usage: $SCRIPT_NAME "
+ exit 1
+fi
+SRC="$1"
+DEST="$2"
+
+mkdir -p "$DEST"
+mv "$SRC" "$DEST"
+
+# make stuff readonly
+cd "$DEST" || exit
+chmod -R u-w,go-rwx "$DEST"
diff --git a/tool_shared/bespoke/env b/tool_shared/bespoke/env
new file mode 100644
index 0000000..1939b29
--- /dev/null
+++ b/tool_shared/bespoke/env
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# environment shared by entire project
+
+# Path to this script
+script_path="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
+
+
+
+# Path to the repo is two directories up
+export REPO_HOME="${script_path%/*/*}/"
+
+# script name and path relative to the top of the project
+script_fn(){
+ echo "$(basename ${BASH_SOURCE[0]})"
+}
+script_fp(){
+ echo "$(realpath --relative-to="$REPO_HOME" "$script_path")/$(script_fn)"
+}
+export -f script_fn script_fp
+
+# REPO_HOME relative file path to this script
+# Calling the function correctly without braces
+export ENV=$(script_fp)
+
+# this script must be sourced, sort of like Python activate
+if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
+ echo "$ENV must be sourced, not executed. Exiting."
+ exit 1
+fi
+
+export PROJECT=$(basename "$REPO_HOME")
+
+# Third party tool(s) that the project admin kindly installed.
+# The developer and tester should use these links to find them.
+export JAVA_HOME="$REPO_HOME/tool_shared/third_party/jdk-11"
+
+# set the shell prompt to show the project
+PPS1="\n[$PROJECT]\n\u@\h§$(pwd)§\n> "
+PPS2=">> "
+
+echo ENV "$ENV"
+echo REPO_HOME "$REPO_HOME"
+echo PROJECT "$PROJECT"
+echo "$ENV completed."
+
+
diff --git a/tool_shared/bespoke/temp b/tool_shared/bespoke/temp
new file mode 100644
index 0000000..0a80f78
--- /dev/null
+++ b/tool_shared/bespoke/temp
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# Path to this script
+script_path="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
+
+# Path to the repo is two directories up
+export REPO_HOME="${script_path%/*/*}/"
+
+# script name and path relative to the top of the project
+script_fn(){
+ echo "$(basename ${BASH_SOURCE[0]})"
+}
+script_fp(){
+ echo "$(realpath --relative-to="$REPO_HOME" "$script_path")/$(script_fn)"
+}
+
+# REPO_HOME relative file path to this script
+# Calling the function correctly without braces
+export ENV=$(script_fp)
+
+# Output the values
+echo "Script path: $script_path"
+echo "Repo home: $REPO_HOME"
+echo "ENV: $ENV"
diff --git a/tool_shared/bespoke/version b/tool_shared/bespoke/version
index 6e696ef..a2fede5 100755
--- a/tool_shared/bespoke/version
+++ b/tool_shared/bespoke/version
@@ -1,4 +1,8 @@
#!/bin/env bash
-echo 0.1
+# 0.1 pulled groovy files from GQL_to_Cypher build.gradle
+# 0.2 conversion to Java
+# 0.3 refactored, split into smaller pieces, made into package
+
+echo 0.3
diff --git a/tool_shared/bespoke/wipe_replease b/tool_shared/bespoke/wipe_replease
new file mode 100755
index 0000000..4b92b4b
--- /dev/null
+++ b/tool_shared/bespoke/wipe_replease
@@ -0,0 +1,17 @@
+#!/bin/bash
+# remove all files in the release directory
+set -e
+
+script_name=$(basename ${BASH_SOURCE[0]})
+if [ -z "$REPO_HOME" ]; then
+ echo "$script_name:: REPO_HOME is not set."
+ exit 1
+fi
+
+set -x
+cd "$REPO_HOME"
+rm -rf release/*
+set +x
+
+echo "$script_name done."
+