diff options
Diffstat (limited to 'site_scons/site_tools/dagger')
-rw-r--r-- | site_scons/site_tools/dagger/__init__.py | 36 | ||||
-rw-r--r-- | site_scons/site_tools/dagger/dagger.py | 37 | ||||
-rw-r--r-- | site_scons/site_tools/dagger/graph.py | 79 | ||||
-rw-r--r-- | site_scons/site_tools/dagger/graph_consts.py | 1 | ||||
-rw-r--r-- | site_scons/site_tools/dagger/graph_test.py | 147 |
5 files changed, 190 insertions, 110 deletions
diff --git a/site_scons/site_tools/dagger/__init__.py b/site_scons/site_tools/dagger/__init__.py index c63bfc6967e..2e82ebeb058 100644 --- a/site_scons/site_tools/dagger/__init__.py +++ b/site_scons/site_tools/dagger/__init__.py @@ -7,6 +7,7 @@ import SCons from . import dagger + def generate(env, **kwargs): """The entry point for our tool. However, the builder for the JSON file is not actually run until the Dagger method is called @@ -14,28 +15,43 @@ def generate(env, **kwargs): to the native builders for object/libraries. """ - env.Replace(LIBEMITTER=SCons.Builder.ListEmitter([env['LIBEMITTER'], dagger.emit_lib_db_entry])) + env.Replace( + LIBEMITTER=SCons.Builder.ListEmitter( + [env["LIBEMITTER"], dagger.emit_lib_db_entry] + ) + ) running_os = os.sys.platform - if not (running_os.startswith('win') or running_os.startswith('sun')): + if not (running_os.startswith("win") or running_os.startswith("sun")): env.Replace( - PROGEMITTER=SCons.Builder.ListEmitter([env['PROGEMITTER'], dagger.emit_prog_db_entry])) + PROGEMITTER=SCons.Builder.ListEmitter( + [env["PROGEMITTER"], dagger.emit_prog_db_entry] + ) + ) static_obj, shared_obj = SCons.Tool.createObjBuilders(env) - suffixes = ['.c', '.cc', '.cxx', '.cpp'] + suffixes = [".c", ".cc", ".cxx", ".cpp"] obj_builders = [static_obj, shared_obj] - default_emitters = [SCons.Defaults.StaticObjectEmitter, SCons.Defaults.SharedObjectEmitter] + default_emitters = [ + SCons.Defaults.StaticObjectEmitter, + SCons.Defaults.SharedObjectEmitter, + ] for suffix in suffixes: for i in range(len(obj_builders)): obj_builders[i].add_emitter( - suffix, SCons.Builder.ListEmitter([dagger.emit_obj_db_entry, default_emitters[i]])) + suffix, + SCons.Builder.ListEmitter( + [dagger.emit_obj_db_entry, default_emitters[i]] + ), + ) - env['BUILDERS']['__OBJ_DATABASE'] = SCons.Builder.Builder( - action=SCons.Action.Action(dagger.write_obj_db, None)) + env["BUILDERS"]["__OBJ_DATABASE"] = SCons.Builder.Builder( + action=SCons.Action.Action(dagger.write_obj_db, None) + ) def Dagger(env, target="library_dependency_graph.json"): - if running_os.startswith('win') or running_os.startswith('sun'): + if running_os.startswith("win") or running_os.startswith("sun"): logging.error("Dagger is only supported on OSX and Linux") return result = env.__OBJ_DATABASE(target=target, source=[]) @@ -44,7 +60,7 @@ def generate(env, **kwargs): return result - env.AddMethod(Dagger, 'Dagger') + env.AddMethod(Dagger, "Dagger") def exists(env): diff --git a/site_scons/site_tools/dagger/dagger.py b/site_scons/site_tools/dagger/dagger.py index cc208dd23c2..061401e9bd7 100644 --- a/site_scons/site_tools/dagger/dagger.py +++ b/site_scons/site_tools/dagger/dagger.py @@ -44,9 +44,12 @@ from . import graph from . import graph_consts -LIB_DB = [] # Stores every SCons library nodes -OBJ_DB = [] # Stores every SCons object file node -EXE_DB = {} # Stores every SCons executable node, with the object files that build into it {Executable: [object files]} +LIB_DB = [] # Stores every SCons library nodes +OBJ_DB = [] # Stores every SCons object file node +EXE_DB = ( + {} +) # Stores every SCons executable node, with the object files that build into it {Executable: [object files]} + def list_process(items): """From WIL, converts lists generated from an NM command with unicode strings to lists @@ -57,12 +60,12 @@ def list_process(items): for l in items: if isinstance(l, list): for i in l: - if i.startswith('.L'): + if i.startswith(".L"): continue else: r.append(str(i)) else: - if l.startswith('.L'): + if l.startswith(".L"): continue else: r.append(str(l)) @@ -75,26 +78,26 @@ def get_symbol_worker(object_file, task): """From WIL, launches a worker subprocess which collects either symbols defined or symbols required by an object file""" - platform = 'linux' if sys.platform.startswith('linux') else 'darwin' + platform = "linux" if sys.platform.startswith("linux") else "darwin" - if platform == 'linux': - if task == 'used': + if platform == "linux": + if task == "used": cmd = r'nm "' + object_file + r'" | grep -e "U " | c++filt' - elif task == 'defined': + elif task == "defined": cmd = r'nm "' + object_file + r'" | grep -v -e "U " | c++filt' - elif platform == 'darwin': - if task == 'used': + elif platform == "darwin": + if task == "used": cmd = "nm -u " + object_file + " | c++filt" - elif task == 'defined': + elif task == "defined": cmd = "nm -jU " + object_file + " | c++filt" p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) uses = p.communicate()[0].decode() - if platform == 'linux': - return list_process([use[19:] for use in uses.split('\n') if use != '']) - elif platform == 'darwin': - return list_process([use.strip() for use in uses.split('\n') if use != '']) + if platform == "linux": + return list_process([use[19:] for use in uses.split("\n") if use != ""]) + elif platform == "darwin": + return list_process([use.strip() for use in uses.split("\n") if use != ""]) def emit_obj_db_entry(target, source, env): @@ -135,7 +138,7 @@ def __compute_libdeps(node): env = node.get_env() deps = set() - for child in env.Flatten(getattr(node.attributes, 'libdeps_direct', [])): + for child in env.Flatten(getattr(node.attributes, "libdeps_direct", [])): if not child: continue deps.add(child) diff --git a/site_scons/site_tools/dagger/graph.py b/site_scons/site_tools/dagger/graph.py index d8d1e6938ee..fdbc4dc98ba 100644 --- a/site_scons/site_tools/dagger/graph.py +++ b/site_scons/site_tools/dagger/graph.py @@ -6,6 +6,7 @@ import copy from . import graph_consts + class Graph(object): """Graph class for storing the build dependency graph. The graph stores the directed edges as a nested dict of { RelationshipType: {From_Node: Set of @@ -18,8 +19,8 @@ class Graph(object): A graph can be initialized with a .json file, graph object, or with no args """ if isinstance(input, str): - if input.endswith('.json'): - with open(input, 'r') as f: + if input.endswith(".json"): + with open(input, "r") as f: data = json.load(f, encoding="ascii") nodes = {} should_fail = False @@ -27,8 +28,9 @@ class Graph(object): for node in data["nodes"]: id = str(node["id"]) try: - nodes[id] = node_factory(id, int(node["node"]["type"]), - dict_source=node["node"]) + nodes[id] = node_factory( + id, int(node["node"]["type"]), dict_source=node["node"] + ) except Exception as e: logging.warning("Malformed Data: " + id) should_fail = True @@ -116,7 +118,9 @@ class Graph(object): if from_node not in self._edges[relationship]: self._edges[relationship][from_node] = set() - if any(item is None for item in (from_node, to_node, from_node_obj, to_node_obj)): + if any( + item is None for item in (from_node, to_node, from_node_obj, to_node_obj) + ): raise ValueError self._edges[relationship][from_node].add(to_node) @@ -150,21 +154,28 @@ class Graph(object): edges_dict = self._edges[edge_type] for node in list(edges_dict.keys()): to_nodes = list(self._edges[edge_type][node]) - to_nodes_dicts = [{"index": node_index[to_node], "id": to_node} - for to_node in to_nodes] - - data["edges"].append({"type": edge_type, - "from_node": {"id": node, - "index": node_index[node]}, - "to_node": to_nodes_dicts}) - - with open(filename, 'w', encoding="ascii") as outfile: + to_nodes_dicts = [ + {"index": node_index[to_node], "id": to_node} + for to_node in to_nodes + ] + + data["edges"].append( + { + "type": edge_type, + "from_node": {"id": node, "index": node_index[node]}, + "to_node": to_nodes_dicts, + } + ) + + with open(filename, "w", encoding="ascii") as outfile: json.dump(data, outfile, indent=4) def __str__(self): - return ("<Number of Nodes : {0}, Number of Edges : {1}, " - "Hash: {2}>").format(len(list(self._nodes.keys())), - sum(len(x) for x in list(self._edges.values())), hash(self)) + return ("<Number of Nodes : {0}, Number of Edges : {1}, " "Hash: {2}>").format( + len(list(self._nodes.keys())), + sum(len(x) for x in list(self._edges.values())), + hash(self), + ) class NodeInterface(object, metaclass=abc.ABCMeta): @@ -183,6 +194,7 @@ class NodeInterface(object, metaclass=abc.ABCMeta): class NodeLib(NodeInterface): """NodeLib class which represents a library within the graph """ + def __init__(self, id, name, input=None): if isinstance(input, dict): should_fail = False @@ -283,10 +295,13 @@ class NodeLib(NodeInterface): def __eq__(self, other): if isinstance(other, NodeLib): - return (self._id == other._id and self._defined_symbols == other._defined_symbols - and self._defined_files == other._defined_files - and self._dependent_libs == other._dependent_libs - and self._dependent_files == other._dependent_files) + return ( + self._id == other._id + and self._defined_symbols == other._defined_symbols + and self._defined_files == other._defined_files + and self._dependent_libs == other._dependent_libs + and self._dependent_files == other._dependent_files + ) else: return False @@ -409,10 +424,13 @@ class NodeSymbol(NodeInterface): def __eq__(self, other): if isinstance(other, NodeSymbol): - return (self.id == other.id and self._libs == other._libs - and self._files == other._files - and self._dependent_libs == other._dependent_libs - and self._dependent_files == other._dependent_files) + return ( + self.id == other.id + and self._libs == other._libs + and self._files == other._files + and self._dependent_libs == other._dependent_libs + and self._dependent_files == other._dependent_files + ) else: return False @@ -527,10 +545,13 @@ class NodeFile(NodeInterface): def __eq__(self, other): if isinstance(other, NodeSymbol): - return (self.id == other.id and self._lib == other._lib - and self._dependent_libs == other._dependent_libs - and self._dependent_files == other._dependent_files - and self._defined_symbols == other._defined_symbols) + return ( + self.id == other.id + and self._lib == other._lib + and self._dependent_libs == other._dependent_libs + and self._dependent_files == other._dependent_files + and self._defined_symbols == other._defined_symbols + ) else: return False diff --git a/site_scons/site_tools/dagger/graph_consts.py b/site_scons/site_tools/dagger/graph_consts.py index eae5db9b6c6..a2077675463 100644 --- a/site_scons/site_tools/dagger/graph_consts.py +++ b/site_scons/site_tools/dagger/graph_consts.py @@ -22,4 +22,3 @@ NODE_TYPES = list(range(1, 5)) """Error/query codes""" NODE_NOT_FOUND = 1 - diff --git a/site_scons/site_tools/dagger/graph_test.py b/site_scons/site_tools/dagger/graph_test.py index 39bdf77ab7c..e532386f852 100644 --- a/site_scons/site_tools/dagger/graph_test.py +++ b/site_scons/site_tools/dagger/graph_test.py @@ -73,22 +73,33 @@ class CustomAssertions: raise AssertionError("Nodes not of same type") if node1.type == graph_consts.NODE_LIB: - if (node1._defined_symbols != node2._defined_symbols - or node1._defined_files != node2._defined_files - or node1._dependent_libs != node2._dependent_libs - or node1._dependent_files != node2._dependent_files or node1._id != node2._id): + if ( + node1._defined_symbols != node2._defined_symbols + or node1._defined_files != node2._defined_files + or node1._dependent_libs != node2._dependent_libs + or node1._dependent_files != node2._dependent_files + or node1._id != node2._id + ): raise AssertionError("Nodes not equal") elif node1.type == graph_consts.NODE_SYM: - if (node1._libs != node2._libs or node1._files != node2._files - or node1._dependent_libs != node2._dependent_libs - or node1._dependent_files != node2._dependent_files or node1.id != node2.id): + if ( + node1._libs != node2._libs + or node1._files != node2._files + or node1._dependent_libs != node2._dependent_libs + or node1._dependent_files != node2._dependent_files + or node1.id != node2.id + ): raise AssertionError("Nodes not equal") else: - if (node1._lib != node2._lib or node1._dependent_libs != node2._dependent_libs - or node1._dependent_files != node2._dependent_files or node1.id != node2.id - or node1._defined_symbols != node2._defined_symbols): + if ( + node1._lib != node2._lib + or node1._dependent_libs != node2._dependent_libs + or node1._dependent_files != node2._dependent_files + or node1.id != node2.id + or node1._defined_symbols != node2._defined_symbols + ): raise AssertionError("Nodes not equal") @@ -131,51 +142,80 @@ class TestGraphMethods(unittest.TestCase, CustomAssertions): self.assertRaises(TypeError, self.g.add_node, "not a node") def test_add_edge_exceptions(self): - self.assertRaises(TypeError, self.g.add_edge, "NOT A RELATIONSHIP", - self.from_node_lib.id, self.to_node_lib.id) - - self.assertRaises(ValueError, self.g.add_edge, - graph_consts.LIB_LIB, "not a node", "not a node") + self.assertRaises( + TypeError, + self.g.add_edge, + "NOT A RELATIONSHIP", + self.from_node_lib.id, + self.to_node_lib.id, + ) + + self.assertRaises( + ValueError, + self.g.add_edge, + graph_consts.LIB_LIB, + "not a node", + "not a node", + ) def test_add_edge_libs(self): - self.g.add_edge(graph_consts.LIB_LIB, self.from_node_lib.id, - self.to_node_lib.id) - self.g.add_edge(graph_consts.LIB_LIB, self.from_node_lib.id, - self.to_node_lib.id) - self.g.add_edge(graph_consts.LIB_SYM, self.from_node_lib.id, - self.to_node_sym.id) - self.g.add_edge(graph_consts.LIB_FIL, self.from_node_lib.id, - self.to_node_file.id) - - self.assertEqual(self.g.edges[graph_consts.LIB_LIB][ - self.from_node_lib.id], set([self.to_node_lib.id])) - - self.assertEqual(self.g.edges[graph_consts.LIB_SYM][ - self.from_node_lib.id], set([self.to_node_sym.id])) - - self.assertEqual(self.g.edges[graph_consts.LIB_FIL][ - self.from_node_lib.id], set([self.to_node_file.id])) - - self.assertEqual(self.to_node_lib.dependent_libs, - set([self.from_node_lib.id])) + self.g.add_edge( + graph_consts.LIB_LIB, self.from_node_lib.id, self.to_node_lib.id + ) + self.g.add_edge( + graph_consts.LIB_LIB, self.from_node_lib.id, self.to_node_lib.id + ) + self.g.add_edge( + graph_consts.LIB_SYM, self.from_node_lib.id, self.to_node_sym.id + ) + self.g.add_edge( + graph_consts.LIB_FIL, self.from_node_lib.id, self.to_node_file.id + ) + + self.assertEqual( + self.g.edges[graph_consts.LIB_LIB][self.from_node_lib.id], + set([self.to_node_lib.id]), + ) + + self.assertEqual( + self.g.edges[graph_consts.LIB_SYM][self.from_node_lib.id], + set([self.to_node_sym.id]), + ) + + self.assertEqual( + self.g.edges[graph_consts.LIB_FIL][self.from_node_lib.id], + set([self.to_node_file.id]), + ) + + self.assertEqual(self.to_node_lib.dependent_libs, set([self.from_node_lib.id])) def test_add_edge_files(self): - self.g.add_edge(graph_consts.FIL_FIL, self.from_node_file.id, - self.to_node_file.id) - self.g.add_edge(graph_consts.FIL_SYM, self.from_node_file.id, - self.to_node_sym.id) - self.g.add_edge(graph_consts.FIL_LIB, self.from_node_file.id, - self.to_node_lib.id) - - self.assertEqual(self.g.edges[graph_consts.FIL_FIL][ - self.from_node_file.id], set([self.to_node_file.id])) - self.assertEqual(self.g.edges[graph_consts.FIL_SYM][ - self.from_node_file.id], set([self.to_node_sym.id])) - self.assertEqual(self.g.edges[graph_consts.FIL_LIB][ - self.from_node_file.id], set([self.to_node_lib.id])) - - self.assertEqual(self.to_node_file.dependent_files, - set([self.from_node_file.id])) + self.g.add_edge( + graph_consts.FIL_FIL, self.from_node_file.id, self.to_node_file.id + ) + self.g.add_edge( + graph_consts.FIL_SYM, self.from_node_file.id, self.to_node_sym.id + ) + self.g.add_edge( + graph_consts.FIL_LIB, self.from_node_file.id, self.to_node_lib.id + ) + + self.assertEqual( + self.g.edges[graph_consts.FIL_FIL][self.from_node_file.id], + set([self.to_node_file.id]), + ) + self.assertEqual( + self.g.edges[graph_consts.FIL_SYM][self.from_node_file.id], + set([self.to_node_sym.id]), + ) + self.assertEqual( + self.g.edges[graph_consts.FIL_LIB][self.from_node_file.id], + set([self.to_node_lib.id]), + ) + + self.assertEqual( + self.to_node_file.dependent_files, set([self.from_node_file.id]) + ) def test_export_to_json(self): generated_graph = generate_graph() @@ -197,10 +237,11 @@ class TestGraphMethods(unittest.TestCase, CustomAssertions): # the need for a custom assertion self.assertNodeEquals( - graph_fromJSON.get_node(id), correct_graph.get_node(id)) + graph_fromJSON.get_node(id), correct_graph.get_node(id) + ) self.assertEqual(graph_fromJSON.edges, correct_graph.edges) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() |