Skip to content

Commit 5f79dea

Browse files
Python 3.8 backport and minor code cleanup (#1)
* Backport to Python 3.8 Only requires adding a few `from __future__ import annotations` Signed-off-by: Bolun Thompson <bolunthompson@ucla.edu> * Add runnable tests Signed-off-by: Bolun Thompson <bolunthompson@ucla.edu> * Add github action for tests Signed-off-by: Bolun Thompson <bolunthompson@ucla.edu> * Update submodule to use pash libbash Signed-off-by: Bolun Thompson <bolunthompson@ucla.edu> * Fix simple type-hint errors Signed-off-by: Bolun Thompson <bolunthompson@ucla.edu> * Format with black Signed-off-by: Bolun Thompson <bolunthompson@ucla.edu> * Remove editable --------- Signed-off-by: Bolun Thompson <bolunthompson@ucla.edu>
1 parent 3cfd4f0 commit 5f79dea

File tree

14 files changed

+473
-354
lines changed

14 files changed

+473
-354
lines changed

.github/workflows/test.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Test
2+
on:
3+
pull_request_target:
4+
types: [assigned, opened, synchronize, reopened, ready_for_review]
5+
paths:
6+
- libbash/**
7+
push:
8+
branches:
9+
- main
10+
paths:
11+
- libbash/**
12+
jobs:
13+
LibBash-Test:
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
os:
18+
- ubuntu-latest
19+
runs-on: ${{ matrix.os }}
20+
if: github.event.pull_request.draft == false
21+
steps:
22+
- uses: actions/checkout@v2
23+
with:
24+
ref: ${{ github.event.pull_request.head.sha }}
25+
- name: Running Tests
26+
run: |
27+
python3 -m venv venv
28+
. venv/bin/activate
29+
./setup_test.sh
30+
31+
./test.py | tee python.log
32+
test_succ=$?
33+
34+
# TODO: Is this working?
35+
timer="$(LANG=en_us_88591; date)"
36+
echo "VERSION<<EOF" >> "$GITHUB_ENV"
37+
echo "OS:${{matrix.os}}" >> "$GITHUB_ENV"
38+
echo "$timer" >> "$GITHUB_ENV"
39+
cat python.log >> "$GITHUB_ENV"
40+
echo 'EOF' >> "$GITHUB_ENV"
41+
42+
exit $test_succ

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[submodule "bash-5.2"]
22
path = libbash/bash-5.2
3-
url = https://github.com/sethsabar/bash-for-libbash.git
3+
url = https://github.com/binpash/bash-for-libbash

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**NOTE: This project is mostly functional, however there are a few minor bugs with the Bash source code causing issues with our API. Take a look at `test.py` to see which tests we are currently not testing because they will fail!**
44

5-
`libbash` can be installed via pip: https://pypi.org/project/libbash/
5+
`libbash` can be installed via pip: https://pypi.org/project/libbash/
66

77
## API
88

@@ -44,8 +44,8 @@ while [ $counter -le 5 ]; do
4444
done
4545
```
4646

47-
Whether `while` is aliased or not depends on the time of day that the script is run, and this affects the functionality of the `while` loop. This is because alias expansion is done
48-
*before* parsing in Bash. As this example shows, determining alias expansions is not possible without executing a Bash script. Therefore, one can not expect any uses of `alias` or
47+
Whether `while` is aliased or not depends on the time of day that the script is run, and this affects the functionality of the `while` loop. This is because alias expansion is done
48+
*before* parsing in Bash. As this example shows, determining alias expansions is not possible without executing a Bash script. Therefore, one can not expect any uses of `alias` or
4949
other programs that change the script before parse-time to be reflected.
5050

5151
## Additional Documents

libbash/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
11
from .api import ast_to_json, bash_to_ast, ast_to_bash
2-
from .test import run_tests
3-
4-

libbash/api.py

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
1+
from __future__ import annotations
2+
13
from .bash_command import *
24
import ctypes
35
import os
46

7+
from typing import Any
8+
59
# current location + ../../bash-5.2/bash.so
6-
BASH_FILE_PATH = os.path.join(os.path.dirname(
7-
__file__), "bash-5.2", "bash.so")
10+
BASH_FILE_PATH = os.path.join(os.path.dirname(__file__), "bash-5.2", "bash.so")
11+
812

913
def _setup_bash() -> ctypes.CDLL:
1014
if not os.path.isfile(BASH_FILE_PATH):
1115
# run configure and make clean all
1216
# this will compile the bash source code into a shared object file
1317
# that can be called from python using ctypes
14-
result = os.system("cd " + os.path.dirname(BASH_FILE_PATH) +
15-
" && ./configure && make clean all")
18+
result = os.system(
19+
"cd "
20+
+ os.path.dirname(BASH_FILE_PATH)
21+
+ " && ./configure && make clean all"
22+
)
1623
if result != 0:
1724
raise Exception("Bash compilation failed")
1825

@@ -22,8 +29,7 @@ def _setup_bash() -> ctypes.CDLL:
2229
try:
2330
bash = ctypes.CDLL(BASH_FILE_PATH)
2431
except OSError:
25-
raise Exception(
26-
"Bash shared object file not found at path: " + BASH_FILE_PATH)
32+
raise Exception("Bash shared object file not found at path: " + BASH_FILE_PATH)
2733

2834
# tell python arg types and return type of the initialize_shell_libbash
2935
bash.initialize_shell_libbash.argtypes = []
@@ -56,13 +62,14 @@ def ast_to_bash(ast: list[Command], write_to: str):
5662
for comm in ast:
5763
command_string = bash.make_command_string(comm._to_ctypes())
5864
bash_str += command_string
59-
bash_str += "\n".encode('utf-8')
65+
bash_str += "\n".encode("utf-8")
6066

6167
with open(write_to, "wb") as f:
6268
# don't decode the bytes, just write them to the file
6369
f.write(bash_str)
6470

65-
def ast_to_json(ast: list[Command]) -> list[dict[str, any]]:
71+
72+
def ast_to_json(ast: list[Command]) -> list[dict[str, Any]]:
6673
"""
6774
Converts the AST to a JSON style object.
6875
:param ast: The AST, a list of Command objects.
@@ -71,8 +78,9 @@ def ast_to_json(ast: list[Command]) -> list[dict[str, any]]:
7178
return [command._to_json() for command in ast]
7279

7380

74-
def bash_to_ast(bash_file: str, with_linno_info: bool=False) -> \
75-
[list[Command], list[Command, bytes, int, int]]:
81+
def bash_to_ast(
82+
bash_file: str, with_linno_info: bool = False
83+
) -> list[Command] | list[tuple[Command, bytes, int, int]]:
7684
"""
7785
Extracts the AST from the bash source code.
7886
Uses ctypes to call an injected bash function that returns the AST.
@@ -90,7 +98,7 @@ def bash_to_ast(bash_file: str, with_linno_info: bool=False) -> \
9098
bash.set_bash_file.restype = ctypes.c_int
9199

92100
# call the function
93-
set_result: ctypes.c_int = bash.set_bash_file(bash_file.encode('utf-8'))
101+
set_result: int = bash.set_bash_file(bash_file.encode("utf-8"))
94102
if set_result < 0:
95103
raise IOError("Setting bash file failed")
96104

@@ -108,22 +116,21 @@ def bash_to_ast(bash_file: str, with_linno_info: bool=False) -> \
108116

109117
while True:
110118
# call the function
111-
linno_before: int = ctypes.c_int.in_dll(bash, 'line_number').value
119+
linno_before: int = ctypes.c_int.in_dll(bash, "line_number").value
112120
read_result: ctypes.c_int = bash.read_command_safe()
113-
linno_after: int = ctypes.c_int.in_dll(bash, 'line_number').value
121+
linno_after: int = ctypes.c_int.in_dll(bash, "line_number").value
114122
if read_result != 0:
115123
bash.unset_bash_input(0)
116-
raise RuntimeError(
117-
"Bash read command failed, shell script may be invalid")
124+
raise RuntimeError("Bash read command failed, shell script may be invalid")
118125

119126
# read the global_command variable
120-
global_command: ctypes.POINTER(c_bash.command) = ctypes.POINTER(
121-
c_bash.command).in_dll(bash, 'global_command')
127+
global_command: ctypes._Pointer[c_bash.command] = ctypes.POINTER(
128+
c_bash.command
129+
).in_dll(bash, "global_command")
122130

123131
# global_command is null
124132
if not global_command:
125-
eof_reached: ctypes.c_int = ctypes.c_int.in_dll(
126-
bash, 'EOF_Reached')
133+
eof_reached: ctypes.c_int = ctypes.c_int.in_dll(bash, "EOF_Reached")
127134
if eof_reached:
128135
bash.unset_bash_input(0)
129136
break
@@ -136,9 +143,9 @@ def bash_to_ast(bash_file: str, with_linno_info: bool=False) -> \
136143

137144
# add the command to the list
138145
if with_linno_info:
139-
command_string = b''.join(lines[linno_before:linno_after])
146+
command_string = b"".join(lines[linno_before:linno_after])
140147
command_list.append((command, command_string, linno_before, linno_after))
141148
else:
142149
command_list.append(command)
143150

144-
return command_list
151+
return command_list

libbash/bash-5.2

0 commit comments

Comments
 (0)