bash-dap 0.2__tar.gz → 0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bash_dap-0.2 → bash_dap-0.3}/PKG-INFO +9 -5
- {bash_dap-0.2 → bash_dap-0.3}/README.md +8 -4
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap/__init__.py +1 -1
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap/adapter.py +10 -4
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap/harness.sh +20 -5
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap.egg-info/PKG-INFO +9 -5
- {bash_dap-0.2 → bash_dap-0.3}/pyproject.toml +1 -1
- {bash_dap-0.2 → bash_dap-0.3}/tests/test_adapter.py +21 -0
- {bash_dap-0.2 → bash_dap-0.3}/LICENSE +0 -0
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap/__main__.py +0 -0
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap.egg-info/SOURCES.txt +0 -0
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap.egg-info/dependency_links.txt +0 -0
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap.egg-info/entry_points.txt +0 -0
- {bash_dap-0.2 → bash_dap-0.3}/bash_dap.egg-info/top_level.txt +0 -0
- {bash_dap-0.2 → bash_dap-0.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bash-dap
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3
|
|
4
4
|
Summary: A debug adapter (Debug Adapter Protocol) for bash scripts, written in bash and Python
|
|
5
5
|
Author-email: Ilia Maslakov <il.smind@gmail.com>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -18,9 +18,9 @@ Dynamic: license-file
|
|
|
18
18
|
# bash-dap
|
|
19
19
|
|
|
20
20
|
A debug adapter of the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)
|
|
21
|
-
for bash scripts: breakpoints on lines and on functions, steps into, over and
|
|
22
|
-
the call stack, the
|
|
23
|
-
|
|
21
|
+
for bash scripts: breakpoints on lines, with conditions, and on functions, steps into, over and
|
|
22
|
+
out of functions, the call stack, the variables (arrays and associative arrays as trees),
|
|
23
|
+
expressions, pause.
|
|
24
24
|
|
|
25
25
|
It needs nothing but bash 4.1 or newer and Python 3.8 or newer: no bashdb, no Node.js. (The bash
|
|
26
26
|
of macOS is 3.2: a newer one, from Homebrew say, is given to the launch as *bash*.) The debugger itself is a script
|
|
@@ -80,12 +80,16 @@ A breakpoint on a function stops at its first command, at each call, in a subshe
|
|
|
80
80
|
what the script defines later, or a file it sources, is found as well, as the name is all
|
|
81
81
|
the debugger looks for.
|
|
82
82
|
|
|
83
|
+
The condition of a breakpoint is a command of bash, `[[ $f == report.pdf ]]` or
|
|
84
|
+
`(( count > 2 ))`: the script stops there when its status is 0. It runs in a subshell, so it
|
|
85
|
+
sees the variables of the script and changes none of them.
|
|
86
|
+
|
|
83
87
|
When the session ends the adapter ends the script by its process group, the session it has to
|
|
84
88
|
itself; never by a parent, never anything else.
|
|
85
89
|
|
|
86
90
|
## Not yet
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
A script that another script runs with a new bash.
|
|
89
93
|
|
|
90
94
|
## License
|
|
91
95
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# bash-dap
|
|
2
2
|
|
|
3
3
|
A debug adapter of the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)
|
|
4
|
-
for bash scripts: breakpoints on lines and on functions, steps into, over and
|
|
5
|
-
the call stack, the
|
|
6
|
-
|
|
4
|
+
for bash scripts: breakpoints on lines, with conditions, and on functions, steps into, over and
|
|
5
|
+
out of functions, the call stack, the variables (arrays and associative arrays as trees),
|
|
6
|
+
expressions, pause.
|
|
7
7
|
|
|
8
8
|
It needs nothing but bash 4.1 or newer and Python 3.8 or newer: no bashdb, no Node.js. (The bash
|
|
9
9
|
of macOS is 3.2: a newer one, from Homebrew say, is given to the launch as *bash*.) The debugger itself is a script
|
|
@@ -63,12 +63,16 @@ A breakpoint on a function stops at its first command, at each call, in a subshe
|
|
|
63
63
|
what the script defines later, or a file it sources, is found as well, as the name is all
|
|
64
64
|
the debugger looks for.
|
|
65
65
|
|
|
66
|
+
The condition of a breakpoint is a command of bash, `[[ $f == report.pdf ]]` or
|
|
67
|
+
`(( count > 2 ))`: the script stops there when its status is 0. It runs in a subshell, so it
|
|
68
|
+
sees the variables of the script and changes none of them.
|
|
69
|
+
|
|
66
70
|
When the session ends the adapter ends the script by its process group, the session it has to
|
|
67
71
|
itself; never by a parent, never anything else.
|
|
68
72
|
|
|
69
73
|
## Not yet
|
|
70
74
|
|
|
71
|
-
|
|
75
|
+
A script that another script runs with a new bash.
|
|
72
76
|
|
|
73
77
|
## License
|
|
74
78
|
|
|
@@ -199,8 +199,11 @@ class Adapter:
|
|
|
199
199
|
return
|
|
200
200
|
with open(os.path.join(self.dir, "breaks"), "w") as f:
|
|
201
201
|
for path, lines in self.breaks.items():
|
|
202
|
-
for line in lines:
|
|
203
|
-
|
|
202
|
+
for line, condition in lines:
|
|
203
|
+
if condition:
|
|
204
|
+
f.write("%s:%d\t%s\n" % (path, line, condition))
|
|
205
|
+
else:
|
|
206
|
+
f.write("%s:%d\n" % (path, line))
|
|
204
207
|
for name in self.functions:
|
|
205
208
|
f.write("%s()\n" % name)
|
|
206
209
|
self.gen += 1
|
|
@@ -297,6 +300,7 @@ class Adapter:
|
|
|
297
300
|
self.respond(request, {
|
|
298
301
|
"supportsConfigurationDoneRequest": True,
|
|
299
302
|
"supportsFunctionBreakpoints": True,
|
|
303
|
+
"supportsConditionalBreakpoints": True,
|
|
300
304
|
"supportsEvaluateForHovers": True,
|
|
301
305
|
"supportsTerminateRequest": True,
|
|
302
306
|
})
|
|
@@ -355,12 +359,14 @@ class Adapter:
|
|
|
355
359
|
def on_setBreakpoints(self, request):
|
|
356
360
|
args = request.get("arguments", {})
|
|
357
361
|
path = os.path.realpath(args.get("source", {}).get("path", ""))
|
|
358
|
-
|
|
362
|
+
# a line and its condition, a command of bash whose status says whether to stop
|
|
363
|
+
lines = [(b["line"], " ".join(b.get("condition", "").split()))
|
|
364
|
+
for b in args.get("breakpoints", []) if "line" in b]
|
|
359
365
|
self.breaks[path] = lines
|
|
360
366
|
self.save_breaks()
|
|
361
367
|
self.respond(request, {"breakpoints": [
|
|
362
368
|
{"id": i + 1, "verified": True, "line": line, "source": {"path": path}}
|
|
363
|
-
for i, line in enumerate(lines)]})
|
|
369
|
+
for i, (line, _) in enumerate(lines)]})
|
|
364
370
|
|
|
365
371
|
def on_setFunctionBreakpoints(self, request):
|
|
366
372
|
"""The functions to stop in at their first command; a name that is no name of a
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
# the script is stopped. At any time the adapter may write the breakpoints to the file "breaks",
|
|
18
18
|
# FILE:LINE a line, then make the empty file "gen.N" of the next generation N; and stop the
|
|
19
19
|
# script at its next command by writing "step 0" to the file "state". A line NAME() of
|
|
20
|
-
# "breaks" is a breakpoint on the function NAME: the script stops at its first command.
|
|
20
|
+
# "breaks" is a breakpoint on the function NAME: the script stops at its first command. After
|
|
21
|
+
# FILE:LINE and a tab, a command of bash is the condition of the breakpoint: the script stops
|
|
22
|
+
# there only when its status is 0.
|
|
21
23
|
#
|
|
22
24
|
# A subshell is a process of its own: what it is told, a step, a breakpoint, goes to the others
|
|
23
25
|
# through these files. The names of the debugger begin with __bdap_.
|
|
@@ -35,8 +37,8 @@ __bdap_mode=run
|
|
|
35
37
|
__bdap_depth=0
|
|
36
38
|
# the breakpoints by FILE:LINE, and the generation of the file they came from; __bdap_names has
|
|
37
39
|
# NAME:LINE, the name of the file only, that the trap tests at each command; __bdap_funcs has
|
|
38
|
-
# NAME() of the functions to stop in
|
|
39
|
-
declare -A __bdap_breaks=() __bdap_names=() __bdap_funcs=()
|
|
40
|
+
# NAME() of the functions to stop in; __bdap_conds the conditions of FILE:LINE
|
|
41
|
+
declare -A __bdap_breaks=() __bdap_names=() __bdap_funcs=() __bdap_conds=()
|
|
40
42
|
__bdap_gen=0
|
|
41
43
|
__bdap_inside=
|
|
42
44
|
__bdap_prev= # the place of the command before: a line stops when it is come to, not again
|
|
@@ -98,8 +100,13 @@ __bdap_breaks_load () {
|
|
|
98
100
|
__bdap_breaks=()
|
|
99
101
|
__bdap_names=()
|
|
100
102
|
__bdap_funcs=()
|
|
101
|
-
|
|
103
|
+
__bdap_conds=()
|
|
104
|
+
while IFS= read -r __bdap_place; do
|
|
102
105
|
[[ -z $__bdap_place ]] && continue
|
|
106
|
+
if [[ $__bdap_place == *$'\t'* ]]; then
|
|
107
|
+
__bdap_conds["${__bdap_place%%$'\t'*}"]=${__bdap_place#*$'\t'}
|
|
108
|
+
__bdap_place=${__bdap_place%%$'\t'*}
|
|
109
|
+
fi
|
|
103
110
|
if [[ $__bdap_place == *"()" ]]; then
|
|
104
111
|
__bdap_funcs["$__bdap_place"]=1
|
|
105
112
|
continue
|
|
@@ -148,6 +155,13 @@ __bdap_on_line () {
|
|
|
148
155
|
[[ -z $__bdap_word || ${__bdap_text[0]-} == *"$__bdap_word"* ]]
|
|
149
156
|
}
|
|
150
157
|
|
|
158
|
+
# Whether the condition of a breakpoint holds, none always: run in a subshell, it sees the
|
|
159
|
+
# variables of the script and changes none of them
|
|
160
|
+
__bdap_condition () {
|
|
161
|
+
[[ -z $1 ]] && return 0
|
|
162
|
+
( eval "$1" ) </dev/null >/dev/null 2>&1
|
|
163
|
+
}
|
|
164
|
+
|
|
151
165
|
# Before a command of the script that may stop: what the script has set, -e, -u, -x, is not
|
|
152
166
|
# the debugger's, which runs without
|
|
153
167
|
__bdap_hook () {
|
|
@@ -179,7 +193,8 @@ __bdap_check () {
|
|
|
179
193
|
next) ((__bdap_d <= __bdap_depth)) && __bdap_reason=step ;;
|
|
180
194
|
finish) ((__bdap_d < __bdap_depth)) && __bdap_reason=step ;;
|
|
181
195
|
esac
|
|
182
|
-
if [[ -z $__bdap_reason && -n ${__bdap_breaks["$__bdap_file:$__bdap_line"]-} ]] && __bdap_on_line
|
|
196
|
+
if [[ -z $__bdap_reason && -n ${__bdap_breaks["$__bdap_file:$__bdap_line"]-} ]] && __bdap_on_line \
|
|
197
|
+
&& __bdap_condition "${__bdap_conds["$__bdap_file:$__bdap_line"]-}"; then
|
|
183
198
|
__bdap_reason=breakpoint
|
|
184
199
|
fi
|
|
185
200
|
# the first command of a function to stop in: the calls are deeper than at the command
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bash-dap
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3
|
|
4
4
|
Summary: A debug adapter (Debug Adapter Protocol) for bash scripts, written in bash and Python
|
|
5
5
|
Author-email: Ilia Maslakov <il.smind@gmail.com>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -18,9 +18,9 @@ Dynamic: license-file
|
|
|
18
18
|
# bash-dap
|
|
19
19
|
|
|
20
20
|
A debug adapter of the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)
|
|
21
|
-
for bash scripts: breakpoints on lines and on functions, steps into, over and
|
|
22
|
-
the call stack, the
|
|
23
|
-
|
|
21
|
+
for bash scripts: breakpoints on lines, with conditions, and on functions, steps into, over and
|
|
22
|
+
out of functions, the call stack, the variables (arrays and associative arrays as trees),
|
|
23
|
+
expressions, pause.
|
|
24
24
|
|
|
25
25
|
It needs nothing but bash 4.1 or newer and Python 3.8 or newer: no bashdb, no Node.js. (The bash
|
|
26
26
|
of macOS is 3.2: a newer one, from Homebrew say, is given to the launch as *bash*.) The debugger itself is a script
|
|
@@ -80,12 +80,16 @@ A breakpoint on a function stops at its first command, at each call, in a subshe
|
|
|
80
80
|
what the script defines later, or a file it sources, is found as well, as the name is all
|
|
81
81
|
the debugger looks for.
|
|
82
82
|
|
|
83
|
+
The condition of a breakpoint is a command of bash, `[[ $f == report.pdf ]]` or
|
|
84
|
+
`(( count > 2 ))`: the script stops there when its status is 0. It runs in a subshell, so it
|
|
85
|
+
sees the variables of the script and changes none of them.
|
|
86
|
+
|
|
83
87
|
When the session ends the adapter ends the script by its process group, the session it has to
|
|
84
88
|
itself; never by a parent, never anything else.
|
|
85
89
|
|
|
86
90
|
## Not yet
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
A script that another script runs with a new bash.
|
|
89
93
|
|
|
90
94
|
## License
|
|
91
95
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "bash-dap"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3"
|
|
8
8
|
description = "A debug adapter (Debug Adapter Protocol) for bash scripts, written in bash and Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "GPL-3.0-or-later" }
|
|
@@ -223,6 +223,27 @@ class SessionTest(unittest.TestCase):
|
|
|
223
223
|
c.request("continue", {"threadId": 1})
|
|
224
224
|
self.assertEqual(c.wait_event("exited")["body"]["exitCode"], 3)
|
|
225
225
|
|
|
226
|
+
def test_conditional_breakpoint(self):
|
|
227
|
+
c = self.client = Client()
|
|
228
|
+
c.request("initialize", {"adapterID": "bash-dap", "linesStartAt1": True})
|
|
229
|
+
c.request("launch", {"program": script("backup.sh"), "cwd": SCRIPTS})
|
|
230
|
+
c.wait_event("initialized")
|
|
231
|
+
response = c.request("setBreakpoints", {"source": {"path": script("backup.sh")},
|
|
232
|
+
"breakpoints": [
|
|
233
|
+
{"line": 15, "condition": "[[ $f == photo.jpg ]]"},
|
|
234
|
+
# an assignment in a condition changes nothing of the script
|
|
235
|
+
{"line": 16, "condition": "total=1000; false"}]})
|
|
236
|
+
self.assertTrue(all(b["verified"] for b in response["body"]["breakpoints"]))
|
|
237
|
+
c.request("configurationDone")
|
|
238
|
+
self.assertEqual(c.wait_event("stopped")["body"]["reason"], "breakpoint")
|
|
239
|
+
self.assertEqual(c.stop_place(), [("main", "backup.sh", 15)])
|
|
240
|
+
self.assertEqual(c.evaluate("$f")["body"]["result"], "photo.jpg")
|
|
241
|
+
self.assertEqual(c.evaluate("$total")["body"]["result"], "900")
|
|
242
|
+
# no other round stops, and the total is the script's own
|
|
243
|
+
c.request("continue", {"threadId": 1})
|
|
244
|
+
self.assertEqual(c.wait_event("exited")["body"]["exitCode"], 3)
|
|
245
|
+
self.assertIn("3 files, 2800 bytes", c.output())
|
|
246
|
+
|
|
226
247
|
def test_pipe_sourced_file_and_dollar_zero(self):
|
|
227
248
|
c = self.client = Client()
|
|
228
249
|
c.start(script("pipe.sh"), [(script("lib.sh"), 3), (script("pipe.sh"), 6)])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|