Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 228 lines (179 sloc) 7.296 kb
bc1b81c @espeed intial 0.3.x commit
authored
1 import os
2 import re
3 import sre_parse
4 import sre_compile
5 from sre_constants import BRANCH, SUBPATTERN
6 import hashlib
268bfbd @espeed Bulbs now supports Python 3 and Python 2.7
authored
7 from . import utils
bc1b81c @espeed intial 0.3.x commit
authored
8
9 # GroovyScripts is the only public class
10
11 #
12 # The scanner code came from the TED project.
13 #
14
d13bc8a @espeed updated groovy
authored
15 # TODO: Simplify this. You don't need group pattern detection.
bc1b81c @espeed intial 0.3.x commit
authored
16
17
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
18 class GroovyScripts(object):
8164d61 @espeed updated README
authored
19 """
20 Store and manage an index of Gremlin-Groovy scripts.
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
21
8164d61 @espeed updated README
authored
22 :param file_path: Path to the base Groovy scripts file.
23 :type file_path: str
24
25 :ivar source_files: List containing the absolute paths to the script files,
26 in the order they were added.
27 :ivar methods: Dict mapping Groovy method names to the actual scripts.
28
29 .. note:: Use the update() method to add subsequent script files.
30 Order matters. Groovy methods are overridden if subsequently added
31 files contain the same method name as a previously added file.
32
33 """
34 #: Relative path to the default script file
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
35 default_file = "gremlin.groovy"
36
8164d61 @espeed updated README
authored
37 def __init__(self, file_path=None):
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
38 self.source_files = list() # an ordered set might be better
39
8164d61 @espeed updated README
authored
40 # methods format: methods[method_name] = method_body
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
41 self.methods = dict()
42
baf5f75 @espeed cleaned up utils
authored
43 if file_path is None:
44 file_path = self._get_default_file()
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
45 self.update(file_path)
46
8164d61 @espeed updated README
authored
47 def get(self, method_name):
48 """
49 Returns the Groovy script with the method name.
50
51 :param method_name: Method name of a Groovy script.
52 :type method_name: str
53
54 :rtype: str
55
56 """
57 return self.methods[method_name]
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
58 #script = self._build_script(method_definition, method_signature)
59 #return script
60
8164d61 @espeed updated README
authored
61 def update(self, file_path):
62 """
63 Updates the script index with the Groovy methods in the script file.
64
65 :rtype: None
66
67 """
68 file_path = os.path.abspath(file_path)
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
69 methods = self._get_methods(file_path)
70 self._add_source_file(file_path)
71 self.methods.update(methods)
72
73 def refresh(self):
8164d61 @espeed updated README
authored
74 """
75 Refreshes the script index by re-reading the Groovy source files.
76
77 :rtype: None
78
79 """
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
80 for file_path in self.source_files:
81 methods = self._get_methods(file_path)
82 self.methods.update(methods)
83
84 def _add_source_file(self,file_path):
baf5f75 @espeed cleaned up utils
authored
85 # order matters (last in takes precedence if it overrides a method)
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
86 self.source_files.append(file_path)
87
88 def _get_methods(self,file_path):
89 return Parser(file_path).get_methods()
90
91 def _get_default_file(self):
410619d @espeed fixed model setattr and made the proxy sigs match the element proxies
authored
92 file_path = utils.get_file_path(__file__, self.default_file)
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
93 return file_path
94
95 def _build_script(definition, signature):
baf5f75 @espeed cleaned up utils
authored
96 # This method isn't be used right now...
897e04d @espeed updated groovy
authored
97 # This method is not current (rework it to suit needs).
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
98 script = """
99 try {
100 current_sha1 = methods[name]
101 } catch(e) {
102 current_sha1 = null
103 methods = [:]
104 methods[name] = sha1
105 }
106 if (current_sha1 == sha1)
897e04d @espeed updated groovy
authored
107 %s
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
108
109 try {
897e04d @espeed updated groovy
authored
110 return %s
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
111 } catch(e) {
112
113 return %s
114 }""" % (signature, definition, signature)
115 return script
116
117
118
bc1b81c @espeed intial 0.3.x commit
authored
119 class Scanner:
120 def __init__(self, lexicon, flags=0):
121 self.lexicon = lexicon
122 self.group_pattern = self._get_group_pattern(flags)
f0b5644 @espeed Python 3 tweaks. All tests.pass.
authored
123
bc1b81c @espeed intial 0.3.x commit
authored
124 def _get_group_pattern(self,flags):
125 # combine phrases into a compound pattern
f0b5644 @espeed Python 3 tweaks. All tests.pass.
authored
126 patterns = []
bc1b81c @espeed intial 0.3.x commit
authored
127 sub_pattern = sre_parse.Pattern()
128 sub_pattern.flags = flags
129 for phrase, action in self.lexicon:
130 patterns.append(sre_parse.SubPattern(sub_pattern, [
131 (SUBPATTERN, (len(patterns) + 1, sre_parse.parse(phrase, flags))),
132 ]))
133 sub_pattern.groups = len(patterns) + 1
134 group_pattern = sre_parse.SubPattern(sub_pattern, [(BRANCH, (None, patterns))])
135 return sre_compile.compile(group_pattern)
136
137 def get_multiline(self,f,m):
138 content = []
139 next_line = ''
140 while not re.search("^}",next_line):
141 content.append(next_line)
142 try:
268bfbd @espeed Bulbs now supports Python 3 and Python 2.7
authored
143 next_line = next(f)
bc1b81c @espeed intial 0.3.x commit
authored
144 except StopIteration:
145 # This will happen at end of file
146 next_line = None
147 break
148 content = "".join(content)
149 return content, next_line
150
151 def get_item(self,f,line):
152 # IMPORTANT: Each item needs to be added sequentially
153 # to make sure the record data is grouped properly
154 # so make sure you add content by calling callback()
155 # before doing any recursive calls
156 match = self.group_pattern.scanner(line).match()
157 if not match:
158 return
159 callback = self.lexicon[match.lastindex-1][1]
160 if "def" in match.group():
161 # this is a multi-line get
162 first_line = match.group()
163 body, current_line = self.get_multiline(f,match)
164 sections = [first_line, body, current_line]
165 content = "\n".join(sections).strip()
166 callback(self,content)
167 if current_line:
168 self.get_item(f,current_line)
169 else:
170 callback(self,match.group(1))
171
f9c198c @espeed Refactored index tests into BulbsTestCase
authored
172 def scan(self,file_path):
173 fin = open(file_path, 'r')
bc1b81c @espeed intial 0.3.x commit
authored
174 for line in fin:
175 self.get_item(fin,line)
176
177
178 class Parser(object):
179
180 def __init__(self, groovy_file):
181 self.methods = {}
182 # handler format: (pattern, callback)
183 handlers = [ ("^def( .*)", self.add_method), ]
184 Scanner(handlers).scan(groovy_file)
185
186 def get_methods(self):
187 return self.methods
188
189 # Scanner Callback
190 def add_method(self,scanner,token):
191 method_definition = token
192 method_signature = self._get_method_signature(method_definition)
193 method_name = self._get_method_name(method_signature)
194 method_body = self._get_method_body(method_definition)
195 # NOTE: Not using sha1, signature, or the full method right now
196 # because of the way the GSE works. It's easier to handle version
197 # control by just using the method_body, which the GSE compiles,
198 # creates a class out of, and stores in a classMap for reuse.
199 #sha1 = self._get_sha1(method_definition)
200 #self.methods[method_name] = (method_signature, method_definition, sha1)
201 self.methods[method_name] = method_body
202
203 def _get_method_signature(self,method_definition):
204 pattern = '^def(.*){'
205 return re.search(pattern,method_definition).group(1).strip()
206
207 def _get_method_name(self,method_signature):
208 pattern = '^(.*)\('
209 return re.search(pattern,method_signature).group(1).strip()
210
211 def _get_method_body(self,method_definition):
212 # remove the first and last lines, and return just the method body
213 lines = method_definition.split('\n')
214 body_lines = lines[+1:-1]
215 method_body = "\n".join(body_lines).strip()
216 return method_body
217
218 def _get_sha1(self,method_definition):
219 # this is used to detect version changes
220 sha1 = hashlib.sha1()
221 sha1.update(method_definition)
222 return sha1.hexdigest()
223
224
225
226
227 #print Parser("gremlin.groovy").get_methods()
Something went wrong with that request. Please try again.