11import csv
2+ import json
23import os
34import graphviz
5+ import networkx as nx
46from io import StringIO
57from data_prep .random_walk .walkutils import WalkUtils , JavaWalkUtils
68from typing import List , Set , Dict , Tuple
79
810
911class GraphBuilder :
10- facts_dir = None # type: str
12+ tables_dir = None # type: str
1113 join_filepath = None # type: str
1214 language = None # type: str
1315
14- def __init__ (self , facts_dir : str , join_filepath : str , language : str ):
15- self .facts_dir = facts_dir
16+ def __init__ (self , tables_dir : str , join_filepath : str , language : str ):
17+ self .tables_dir = tables_dir
1618 self .join_filepath = join_filepath
1719 self .language = GraphBuilder .parse_language (language )
1820
@@ -33,17 +35,9 @@ def load_columns(self) -> Dict[str, List[str]]:
3335 else :
3436 raise ValueError ('Cannot load columns for language:' , self .language )
3537
36- def load_fact_table (self , fact_file : str ) -> List [Tuple ]:
38+ def load_table (self , table_file : str ) -> List [Tuple ]:
3739 table = []
38- with open (self .facts_dir + '/' + fact_file , 'r' ) as f :
39- reader = csv .reader (f , delimiter = ',' )
40- for line in reader :
41- table .append (tuple (line ))
42- return table
43-
44- def load_csv_table (self , fact_file : str ) -> List [Tuple ]:
45- table = []
46- with open (self .facts_dir + '/' + fact_file , 'r' ) as f :
40+ with open (self .tables_dir + '/' + table_file , 'r' ) as f :
4741 data = f .read ()
4842 data = data .replace ('\x00 ' , '**NULLBYTE**' , - 1 )
4943 reader = csv .reader (StringIO (data ), delimiter = ',' )
@@ -88,54 +82,20 @@ def load_joins(self) -> (Dict, Dict):
8882
8983 return joins , keys
9084
91- def load_db (self , col_dict : Dict ) -> Dict [str , List [Tuple ]]:
85+ def load_db (self , col_dict : Dict , include_callgraph = False ) -> Dict [str , List [Tuple ]]:
9286 database = {} # type: Dict[str, List[Tuple]]
93- for fact_file in os .listdir (self .facts_dir ):
94- if fact_file .endswith ('.csv.facts' ):
95- table_name = fact_file [:- 10 ] # remove ".csv.facts"
96- if table_name in col_dict :
97- database [table_name ] = self .load_fact_table (fact_file )
98- elif fact_file .endswith ('.bqrs.csv' ):
99- table_name = fact_file [:- 9 ] # remove ".bqrs.csv"
100- if table_name in col_dict :
101- database [table_name ] = self .load_csv_table (fact_file )
102- elif fact_file .endswith ('.csv' ):
103- table_name = fact_file [:- 4 ] # remove ".csv"
87+ for table_file in os .listdir (self .tables_dir ):
88+ if table_file .endswith ('.csv' ):
89+ if 'call_graph' in table_file and not include_callgraph :
90+ continue # skip the call_graph if call graph is not requested.
91+ elif 'call_graph' in table_file and include_callgraph :
92+ table_name = 'call_graph'
93+ else :
94+ table_name = table_file [:table_file .find ('.' )] # remove suffixes
10495 if table_name in col_dict :
105- database [table_name ] = self .load_csv_table ( fact_file )
96+ database [table_name ] = self .load_table ( table_file )
10697 return database
10798
108- def load_callgraph (self ):
109- if self .language == 'python' :
110- call_graph = []
111- if 'one_hop_call_graph.csv.facts' in os .listdir (self .facts_dir ):
112- callgraph_file = 'one_hop_call_graph.csv.facts'
113- elif 'full_call_graph.csv.facts' in os .listdir (self .facts_dir ):
114- callgraph_file = 'full_call_graph.csv.facts'
115- elif 'one_hop_call_graph.csv' in os .listdir (self .facts_dir ):
116- callgraph_file = 'one_hop_call_graph.csv'
117- elif 'full_call_graph.csv' in os .listdir (self .facts_dir ):
118- callgraph_file = 'full_call_graph.csv'
119- elif 'one_hop_call_graph.bqrs.csv' in os .listdir (self .facts_dir ):
120- callgraph_file = 'one_hop_call_graph.bqrs.csv'
121- elif 'full_call_graph.bqrs.csv' in os .listdir (self .facts_dir ):
122- callgraph_file = 'full_call_graph.bqrs.csv'
123- else :
124- return []
125-
126- with open (os .path .join (self .facts_dir , callgraph_file ), 'r' ) as cf :
127- for line in cf .readlines ():
128- call_edge = line .split (',' )
129- call_graph .append ([s .strip () for s in call_edge ])
130- if callgraph_file .endswith ('facts' ):
131- return call_graph
132- else :
133- return call_graph [1 :]
134- elif self .language == 'java' :
135- raise NotImplementedError
136- else :
137- raise ValueError ('Cannot load the call graph for langauge:' , self .language )
138-
13999 @staticmethod
140100 def build_value_to_tuple_map (db : Dict , keys : Dict ) -> Dict [str , Set [Tuple [Tuple , str ]]]:
141101 val_tuple_map = {} # type: Dict[str, Set[Tuple[Tuple, str]]]
@@ -182,7 +142,7 @@ def labels_if_joinable(joins: Dict, columns: Dict, l_rel: str, l_tuple: Tuple, r
182142 labels .append (GraphBuilder .edb_edge_label (l_rel , l_col , r_rel , r_col ))
183143 return labels
184144
185- def build_graph (self , db : Dict , joins : Dict , keys : Dict , columns : Dict , call_graph : List ) -> graphviz .Graph :
145+ def build_graph (self , db : Dict , joins : Dict , keys : Dict , columns : Dict ) -> graphviz .Graph :
186146 val_tuple_map = self .build_value_to_tuple_map (db , keys ) # type: Dict[str, Set[Tuple[Tuple, str]]]
187147 tuple_index_map = {} # type: Dict[str, Dict[Tuple, int]]
188148 index_rel_map = {} # type: Dict[int, str]
@@ -199,6 +159,7 @@ def build_graph(self, db: Dict, joins: Dict, keys: Dict, columns: Dict, call_gra
199159 index += 1
200160 # Build the graph
201161 graph = graphviz .Graph ()
162+
202163 for i in index_tuple_map :
203164 graph .node (str (i ), self .edb_tuple_label (index_tuple_map [i ], index_rel_map [i ]))
204165 for val in val_tuple_map :
@@ -216,33 +177,13 @@ def build_graph(self, db: Dict, joins: Dict, keys: Dict, columns: Dict, call_gra
216177 for edge_label in edge_labels :
217178 graph .edge (str (index_i ), str (index_j ), edge_label )
218179
219- def search_py_exprs (expr_id ):
220- indices = []
221- for i in index_rel_map :
222- if index_rel_map [i ] == 'py_exprs' :
223- indices .append (i )
224- for i in indices :
225- if index_tuple_map [i ][0 ] == expr_id :
226- return i
227- return None
228-
229- for call_edge in call_graph :
230- function1_expr_id = search_py_exprs (call_edge [0 ])
231- function2_expr_id = search_py_exprs (call_edge [1 ])
232- edge_label = '(callgraph.0,call_graph.1)'
233- if function1_expr_id and function2_expr_id :
234- graph .edge (str (function1_expr_id ), str (function2_expr_id ), edge_label )
235180 return graph
236181
237182 def build (self , include_callgraph = False ) -> graphviz .Graph :
238183 columns = self .load_columns ()
239- db = self .load_db (columns )
240- if include_callgraph :
241- callgraph = self .load_callgraph ()
242- else :
243- callgraph = []
184+ db = self .load_db (columns , include_callgraph )
244185 joins , keys = self .load_joins ()
245- graph = self .build_graph (db , joins , keys , columns , callgraph )
186+ graph = self .build_graph (db , joins , keys , columns )
246187 return graph
247188
248189 @staticmethod
0 commit comments