Skip to content

Commit 3374218

Browse files
Mergin
2 parents c048ae8 + e84f9a2 commit 3374218

File tree

10 files changed

+53
-23
lines changed

10 files changed

+53
-23
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ The file unroll.py can be called from the CLI passing a --file argument to speci
295295

296296
**strip_cmd(nodes)** - Strips all the commands executed from a series of bash nodes in order. No replacement occurs, it simply returns the raw commands.
297297

298-
**advanced_unroll(nodes, var_list={}, fn_dict={}, alias_table={})** - This function strips the commands executed by the series of bash nodes after resolving and command aliasing, function calls, and variable substitutions.
298+
**advanced_unroll(nodes, var_list={}, fn_dict={}, alias_table={}, strip_cmds=True)** - This function resolves command aliasing, function calls, and variable substitutions in a series of bash nodes, replacing as it progresses. The strip_cmds boolean can be toggeled to return only the commands executed or the replaced nodes.
299299

300300

301301

bashparser.egg-info/PKG-INFO

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
Metadata-Version: 2.1
22
Name: bashparser
3+
<<<<<<< HEAD
34
Version: 0.7
5+
=======
6+
Version: 0.9
7+
>>>>>>> e84f9a27b9e8926d8a4e1e4ab18e3651161dae4d
48
Summary: A framework for manipulating and analysing bash scripts
59
Home-page: https://github.com/BlankCanvasStudio/bashparse
610
Author: Spencer Stingley

bashparser/ast.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def __init__(self, root):
2020
self.no_children = {'operator', 'reservedword', 'pipe', 'parameter', 'tilde', 'heredoc'}
2121
self.parts_children = {'list', 'pipeline', 'if', 'for', 'while', 'until', 'command', 'function', 'word', 'assignment'}
2222
self.command_children = {'commandsubstitution', 'processsubstitution'}
23-
self.passable_nodes = {'command', 'list', 'compound', 'for', 'parameter', 'function', 'pipeline', 'if'}
23+
self.passable_nodes = {'command', 'list', 'for', 'parameter', 'function', 'pipeline', 'if', 'while'}
2424
self.list_children = {}
2525
self.contains_variable_text = {'word', 'assignment'}
2626

@@ -38,27 +38,46 @@ def apply_fn(node):
3838
if node.kind in self.passable_nodes: return CONT
3939
elif node.kind == 'operator': word = node.op
4040
elif node.kind == 'pipe': word = node.pipe
41+
elif node.kind == 'redirect':
42+
if type(node.input) == bashlex.ast.node:
43+
word += str(NodeVisitor(node.input))
44+
elif node.input is not None:
45+
word += str(node.input)
46+
word += str(node.type)
47+
if type(node.output) == bashlex.ast.node:
48+
word += str(NodeVisitor(node.output))
49+
elif node.output is not None:
50+
word += str(node.output)
51+
self._string = self._string + ' ' + word
52+
return DONT_DESCEND
53+
elif node.kind == 'compound':
54+
for part in node.list:
55+
word += ' ' + str(NodeVisitor(part))
56+
if hasattr(node, 'redirects'):
57+
for part in node.redirects:
58+
word += ' ' + str(NodeVisitor(part))
59+
self._string = self._string + ' ' + word
60+
return DONT_DESCEND
4161
elif node.kind == 'commandsubstitution':
4262
word = '$('
4363
cmd = node.command
4464
for part in cmd.parts:
4565
word += str(NodeVisitor(part)) + ' '
4666
word = word[:-1] + ')'
47-
self._string = self._string + word + ' '
67+
self._string = self._string + ' ' + word
4868
return DONT_DESCEND
4969

5070
elif hasattr(node, 'word'):
5171
word = node.word
52-
self._string = self._string + word + ' '
72+
self._string = self._string + ' ' + word
5373
return DONT_DESCEND
5474
else:
55-
print('node: ', node.dump())
5675
raise ValueError('Error! Unsupported node kind encountered when converting NodeVisitor to string: ', node.kind)
57-
self._string = self._string + word + ' '
76+
self._string = self._string + ' ' + word
5877
return CONT
5978

6079
self.apply(apply_fn)
61-
return self._string[:-1] # remove trailing space cause wrong
80+
return self._string.strip() # remove surrounding spaces cause wrong
6281

6382

6483
def __type__(self):
@@ -235,8 +254,10 @@ def children(self, root = None):
235254
elif k == 'redirect':
236255
if isinstance(root.output, bashlex.ast.node):
237256
return [ root.output ]
238-
if root.heredoc:
257+
elif root.heredoc:
239258
return [ root.heredoc[child_num] ]
259+
else:
260+
return []
240261
elif hasattr(root, 'list'):
241262
return root.list
242263
else:

bashparser/generalize.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ def parameter_tracking_generalization(generalize_nodes, params_used = {}, param_
4040

4141
for node in generalize_nodes:
4242
if node.kind == 'word':
43-
print('here1')
4443
if node.word not in params_used:
45-
print('here2')
4644
params_used[node.word] = str(param_num)
4745
param_num += 1
4846
node.word = '%' + params_used[node.word]
@@ -58,9 +56,7 @@ def parameter_tracking_generalization(generalize_nodes, params_used = {}, param_
5856
node.parts[0].word = "%d=%" + str(params_used[value_assigned])
5957
for i in range(1, len(node.parts)):
6058
if hasattr(node.parts[i], 'word'):
61-
print('here3')
6259
if node.parts[i].word not in params_used:
63-
print('here4')
6460
params_used[node.parts[i].word] = str(param_num)
6561
param_num += 1
6662
node.parts[i].word = '%' + str(params_used[node.parts[i].word])

bashparser/test/test_ast.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,14 @@ def test_str(self):
3838
rebuilt_commands = str(NodeVisitor(nodes[0]))
3939
expected_result = "for a in $n do wget that ; cd there ; mv here ; a=b ; done"
4040
self.assertTrue(rebuilt_commands == expected_result)
41-
4241
self.assertTrue(str(NodeVisitor(None)) == '')
43-
42+
"""
43+
node_string = 'history -n >/dev/null 2>&1'
44+
node = bashlex.parse(node_string)[0]
45+
rebuilt_command = str(NodeVisitor(node))
46+
expected_result = 'history -n >/dev/null 2>&1'
47+
self.assertTrue(rebuilt_command == expected_result)
48+
"""
4449

4550
def test_apply(self):
4651
# Build ast to test apply on

bashparser/test/test_variable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def test_update_variable_list(self):
114114
self.assertTrue({'a':['3']} == new_var_list)
115115
node = bashparser.parse('a=4')[0]
116116
new_var_list = update_variable_list(node, new_var_list)
117-
self.assertTrue({'a':['3', '4']} == new_var_list)
117+
self.assertTrue({'a':['4']} == new_var_list)
118118

119119

120120
def test_update_var_list_with_for_loop(self):

bashparser/unroll.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def apply_fn(node, vstr):
3232
return unrolled_commands
3333

3434

35-
def advanced_unroll(nodes, var_list={}, fn_dict={}, alias_table={}):
35+
def advanced_unroll(nodes, var_list={}, fn_dict={}, alias_table={}, strip_cmds=True):
3636
# The ordering of this function is important. Tread lightly
3737

3838
nodes = bashparser.build_and_resolve_aliasing(nodes, alias_table)
@@ -41,9 +41,13 @@ def advanced_unroll(nodes, var_list={}, fn_dict={}, alias_table={}):
4141

4242
nodes = bashparser.substitute_variables(nodes, var_list)
4343

44-
commands = strip_cmd(nodes)
44+
if strip_cmds:
45+
ret_val = strip_cmd(nodes)
46+
else:
47+
ret_val = nodes
48+
49+
return ret_val
4550

46-
return commands
4751

4852
def main():
4953
import argparse

bashparser/variables.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def apply_fn(node, var_list):
161161
""" We need to treat a variable and for loop seperately because a string in a for loop is actually an array """
162162
if node.kind == 'assignment':
163163
name, value = node.word.split('=', maxsplit=1)
164-
var_list = add_variable_to_list(var_list, name, value)
164+
var_list = add_variable_to_list(var_list, name, value, append=False)
165165
elif node.kind == 'for':
166166
var_list = update_var_list_with_for_loop(node, var_list)
167167
return CONT
@@ -170,7 +170,7 @@ def apply_fn(node, var_list):
170170
return var_list
171171

172172

173-
def add_variable_to_list(var_list, name, values):
173+
def add_variable_to_list(var_list, name, values, append=True):
174174
""" (variable dict, name, value) Adds the corresponding name and value to dictionary. If name exists in
175175
the dictionary, the value is added. Prevents bugs with use of the var_list """
176176

@@ -182,7 +182,7 @@ def add_variable_to_list(var_list, name, values):
182182
for i, val in enumerate(values):
183183
if type(val) is not str and type(val) is not bashlex.ast.node: values[i] = str(val)
184184

185-
if name in var_list:
185+
if name in var_list and append:
186186
for val in values:
187187
if val not in var_list[name]:
188188
var_list[name] += [ val ]

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = bashparser
3-
version = 0.8
3+
version = 0.14
44
author = Spencer Stingley
55
description = A framework for manipulating and analysing bash scripts
66
long_description = A framework for manipulating and analysing bash scripts

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
setuptools.setup(
99
name="bashparser",
10-
version="0.8",
10+
version="0.14",
1111
author="Spencer Stingley",
1212
author_email="[email protected]",
1313
description="A framework for manipulating and analysing bash scripts",

0 commit comments

Comments
 (0)