just-bash 0.1.5__py3-none-any.whl

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.
Files changed (193) hide show
  1. just_bash/__init__.py +55 -0
  2. just_bash/ast/__init__.py +213 -0
  3. just_bash/ast/factory.py +320 -0
  4. just_bash/ast/types.py +953 -0
  5. just_bash/bash.py +220 -0
  6. just_bash/commands/__init__.py +23 -0
  7. just_bash/commands/argv/__init__.py +5 -0
  8. just_bash/commands/argv/argv.py +21 -0
  9. just_bash/commands/awk/__init__.py +5 -0
  10. just_bash/commands/awk/awk.py +1168 -0
  11. just_bash/commands/base64/__init__.py +5 -0
  12. just_bash/commands/base64/base64.py +138 -0
  13. just_bash/commands/basename/__init__.py +5 -0
  14. just_bash/commands/basename/basename.py +72 -0
  15. just_bash/commands/bash/__init__.py +5 -0
  16. just_bash/commands/bash/bash.py +188 -0
  17. just_bash/commands/cat/__init__.py +5 -0
  18. just_bash/commands/cat/cat.py +173 -0
  19. just_bash/commands/checksum/__init__.py +5 -0
  20. just_bash/commands/checksum/checksum.py +179 -0
  21. just_bash/commands/chmod/__init__.py +5 -0
  22. just_bash/commands/chmod/chmod.py +216 -0
  23. just_bash/commands/column/__init__.py +5 -0
  24. just_bash/commands/column/column.py +180 -0
  25. just_bash/commands/comm/__init__.py +5 -0
  26. just_bash/commands/comm/comm.py +150 -0
  27. just_bash/commands/compression/__init__.py +5 -0
  28. just_bash/commands/compression/compression.py +298 -0
  29. just_bash/commands/cp/__init__.py +5 -0
  30. just_bash/commands/cp/cp.py +149 -0
  31. just_bash/commands/curl/__init__.py +5 -0
  32. just_bash/commands/curl/curl.py +801 -0
  33. just_bash/commands/cut/__init__.py +5 -0
  34. just_bash/commands/cut/cut.py +327 -0
  35. just_bash/commands/date/__init__.py +5 -0
  36. just_bash/commands/date/date.py +258 -0
  37. just_bash/commands/diff/__init__.py +5 -0
  38. just_bash/commands/diff/diff.py +118 -0
  39. just_bash/commands/dirname/__init__.py +5 -0
  40. just_bash/commands/dirname/dirname.py +56 -0
  41. just_bash/commands/du/__init__.py +5 -0
  42. just_bash/commands/du/du.py +150 -0
  43. just_bash/commands/echo/__init__.py +5 -0
  44. just_bash/commands/echo/echo.py +125 -0
  45. just_bash/commands/env/__init__.py +5 -0
  46. just_bash/commands/env/env.py +163 -0
  47. just_bash/commands/expand/__init__.py +5 -0
  48. just_bash/commands/expand/expand.py +299 -0
  49. just_bash/commands/expr/__init__.py +5 -0
  50. just_bash/commands/expr/expr.py +273 -0
  51. just_bash/commands/file/__init__.py +5 -0
  52. just_bash/commands/file/file.py +274 -0
  53. just_bash/commands/find/__init__.py +5 -0
  54. just_bash/commands/find/find.py +623 -0
  55. just_bash/commands/fold/__init__.py +5 -0
  56. just_bash/commands/fold/fold.py +160 -0
  57. just_bash/commands/grep/__init__.py +5 -0
  58. just_bash/commands/grep/grep.py +418 -0
  59. just_bash/commands/head/__init__.py +5 -0
  60. just_bash/commands/head/head.py +167 -0
  61. just_bash/commands/help/__init__.py +5 -0
  62. just_bash/commands/help/help.py +67 -0
  63. just_bash/commands/hostname/__init__.py +5 -0
  64. just_bash/commands/hostname/hostname.py +21 -0
  65. just_bash/commands/html_to_markdown/__init__.py +5 -0
  66. just_bash/commands/html_to_markdown/html_to_markdown.py +191 -0
  67. just_bash/commands/join/__init__.py +5 -0
  68. just_bash/commands/join/join.py +252 -0
  69. just_bash/commands/jq/__init__.py +5 -0
  70. just_bash/commands/jq/jq.py +280 -0
  71. just_bash/commands/ln/__init__.py +5 -0
  72. just_bash/commands/ln/ln.py +127 -0
  73. just_bash/commands/ls/__init__.py +5 -0
  74. just_bash/commands/ls/ls.py +280 -0
  75. just_bash/commands/mkdir/__init__.py +5 -0
  76. just_bash/commands/mkdir/mkdir.py +92 -0
  77. just_bash/commands/mv/__init__.py +5 -0
  78. just_bash/commands/mv/mv.py +142 -0
  79. just_bash/commands/nl/__init__.py +5 -0
  80. just_bash/commands/nl/nl.py +180 -0
  81. just_bash/commands/od/__init__.py +5 -0
  82. just_bash/commands/od/od.py +157 -0
  83. just_bash/commands/paste/__init__.py +5 -0
  84. just_bash/commands/paste/paste.py +100 -0
  85. just_bash/commands/printf/__init__.py +5 -0
  86. just_bash/commands/printf/printf.py +157 -0
  87. just_bash/commands/pwd/__init__.py +5 -0
  88. just_bash/commands/pwd/pwd.py +23 -0
  89. just_bash/commands/read/__init__.py +5 -0
  90. just_bash/commands/read/read.py +185 -0
  91. just_bash/commands/readlink/__init__.py +5 -0
  92. just_bash/commands/readlink/readlink.py +86 -0
  93. just_bash/commands/registry.py +844 -0
  94. just_bash/commands/rev/__init__.py +5 -0
  95. just_bash/commands/rev/rev.py +74 -0
  96. just_bash/commands/rg/__init__.py +5 -0
  97. just_bash/commands/rg/rg.py +1048 -0
  98. just_bash/commands/rm/__init__.py +5 -0
  99. just_bash/commands/rm/rm.py +106 -0
  100. just_bash/commands/search_engine/__init__.py +13 -0
  101. just_bash/commands/search_engine/matcher.py +170 -0
  102. just_bash/commands/search_engine/regex.py +159 -0
  103. just_bash/commands/sed/__init__.py +5 -0
  104. just_bash/commands/sed/sed.py +863 -0
  105. just_bash/commands/seq/__init__.py +5 -0
  106. just_bash/commands/seq/seq.py +190 -0
  107. just_bash/commands/shell/__init__.py +5 -0
  108. just_bash/commands/shell/shell.py +206 -0
  109. just_bash/commands/sleep/__init__.py +5 -0
  110. just_bash/commands/sleep/sleep.py +62 -0
  111. just_bash/commands/sort/__init__.py +5 -0
  112. just_bash/commands/sort/sort.py +411 -0
  113. just_bash/commands/split/__init__.py +5 -0
  114. just_bash/commands/split/split.py +237 -0
  115. just_bash/commands/sqlite3/__init__.py +5 -0
  116. just_bash/commands/sqlite3/sqlite3_cmd.py +505 -0
  117. just_bash/commands/stat/__init__.py +5 -0
  118. just_bash/commands/stat/stat.py +150 -0
  119. just_bash/commands/strings/__init__.py +5 -0
  120. just_bash/commands/strings/strings.py +150 -0
  121. just_bash/commands/tac/__init__.py +5 -0
  122. just_bash/commands/tac/tac.py +158 -0
  123. just_bash/commands/tail/__init__.py +5 -0
  124. just_bash/commands/tail/tail.py +180 -0
  125. just_bash/commands/tar/__init__.py +5 -0
  126. just_bash/commands/tar/tar.py +1067 -0
  127. just_bash/commands/tee/__init__.py +5 -0
  128. just_bash/commands/tee/tee.py +63 -0
  129. just_bash/commands/timeout/__init__.py +5 -0
  130. just_bash/commands/timeout/timeout.py +188 -0
  131. just_bash/commands/touch/__init__.py +5 -0
  132. just_bash/commands/touch/touch.py +91 -0
  133. just_bash/commands/tr/__init__.py +5 -0
  134. just_bash/commands/tr/tr.py +297 -0
  135. just_bash/commands/tree/__init__.py +5 -0
  136. just_bash/commands/tree/tree.py +139 -0
  137. just_bash/commands/true/__init__.py +5 -0
  138. just_bash/commands/true/true.py +32 -0
  139. just_bash/commands/uniq/__init__.py +5 -0
  140. just_bash/commands/uniq/uniq.py +323 -0
  141. just_bash/commands/wc/__init__.py +5 -0
  142. just_bash/commands/wc/wc.py +169 -0
  143. just_bash/commands/which/__init__.py +5 -0
  144. just_bash/commands/which/which.py +52 -0
  145. just_bash/commands/xan/__init__.py +5 -0
  146. just_bash/commands/xan/xan.py +1663 -0
  147. just_bash/commands/xargs/__init__.py +5 -0
  148. just_bash/commands/xargs/xargs.py +136 -0
  149. just_bash/commands/yq/__init__.py +5 -0
  150. just_bash/commands/yq/yq.py +848 -0
  151. just_bash/fs/__init__.py +29 -0
  152. just_bash/fs/in_memory_fs.py +621 -0
  153. just_bash/fs/mountable_fs.py +504 -0
  154. just_bash/fs/overlay_fs.py +894 -0
  155. just_bash/fs/read_write_fs.py +455 -0
  156. just_bash/interpreter/__init__.py +37 -0
  157. just_bash/interpreter/builtins/__init__.py +92 -0
  158. just_bash/interpreter/builtins/alias.py +154 -0
  159. just_bash/interpreter/builtins/cd.py +76 -0
  160. just_bash/interpreter/builtins/control.py +127 -0
  161. just_bash/interpreter/builtins/declare.py +336 -0
  162. just_bash/interpreter/builtins/export.py +56 -0
  163. just_bash/interpreter/builtins/let.py +44 -0
  164. just_bash/interpreter/builtins/local.py +57 -0
  165. just_bash/interpreter/builtins/mapfile.py +152 -0
  166. just_bash/interpreter/builtins/misc.py +378 -0
  167. just_bash/interpreter/builtins/readonly.py +80 -0
  168. just_bash/interpreter/builtins/set.py +234 -0
  169. just_bash/interpreter/builtins/shopt.py +201 -0
  170. just_bash/interpreter/builtins/source.py +136 -0
  171. just_bash/interpreter/builtins/test.py +290 -0
  172. just_bash/interpreter/builtins/unset.py +53 -0
  173. just_bash/interpreter/conditionals.py +387 -0
  174. just_bash/interpreter/control_flow.py +381 -0
  175. just_bash/interpreter/errors.py +116 -0
  176. just_bash/interpreter/expansion.py +1156 -0
  177. just_bash/interpreter/interpreter.py +813 -0
  178. just_bash/interpreter/types.py +134 -0
  179. just_bash/network/__init__.py +1 -0
  180. just_bash/parser/__init__.py +39 -0
  181. just_bash/parser/lexer.py +948 -0
  182. just_bash/parser/parser.py +2162 -0
  183. just_bash/py.typed +0 -0
  184. just_bash/query_engine/__init__.py +83 -0
  185. just_bash/query_engine/builtins/__init__.py +1283 -0
  186. just_bash/query_engine/evaluator.py +578 -0
  187. just_bash/query_engine/parser.py +525 -0
  188. just_bash/query_engine/tokenizer.py +329 -0
  189. just_bash/query_engine/types.py +373 -0
  190. just_bash/types.py +180 -0
  191. just_bash-0.1.5.dist-info/METADATA +410 -0
  192. just_bash-0.1.5.dist-info/RECORD +193 -0
  193. just_bash-0.1.5.dist-info/WHEEL +4 -0
@@ -0,0 +1,185 @@
1
+ """Read command implementation.
2
+
3
+ Usage: read [-r] [-d delim] [-n nchars] [-p prompt] [-t timeout] [name ...]
4
+
5
+ Read a line from stdin and split it into fields.
6
+
7
+ Options:
8
+ -r Do not treat backslash as escape character
9
+ -d delim Use delim as line delimiter instead of newline
10
+ -n nchars Read only nchars characters
11
+ -p prompt Output the string prompt before reading
12
+ -t timeout Time out after timeout seconds
13
+
14
+ If no names are given, the line is stored in REPLY.
15
+ """
16
+
17
+ from ...types import CommandContext, ExecResult
18
+
19
+
20
+ class ReadCommand:
21
+ """The read builtin command."""
22
+
23
+ name = "read"
24
+
25
+ async def execute(self, args: list[str], ctx: CommandContext) -> ExecResult:
26
+ """Execute the read command."""
27
+ # Parse options
28
+ raw_mode = False
29
+ delimiter = "\n"
30
+ nchars = None
31
+ array_name = None # -a option
32
+ var_names = []
33
+
34
+ i = 0
35
+ while i < len(args):
36
+ arg = args[i]
37
+ if arg == "-r":
38
+ raw_mode = True
39
+ elif arg == "-a" and i + 1 < len(args):
40
+ i += 1
41
+ array_name = args[i]
42
+ elif arg == "-d" and i + 1 < len(args):
43
+ i += 1
44
+ delimiter = args[i]
45
+ elif arg == "-n" and i + 1 < len(args):
46
+ i += 1
47
+ try:
48
+ nchars = int(args[i])
49
+ except ValueError:
50
+ return ExecResult(
51
+ stdout="",
52
+ stderr=f"bash: read: {args[i]}: invalid number\n",
53
+ exit_code=1,
54
+ )
55
+ elif arg == "-p" and i + 1 < len(args):
56
+ # Prompt option - we ignore it since we can't prompt
57
+ i += 1
58
+ elif arg == "-t" and i + 1 < len(args):
59
+ # Timeout option - we ignore it
60
+ i += 1
61
+ elif arg.startswith("-"):
62
+ # Unknown option - ignore for compatibility
63
+ pass
64
+ else:
65
+ var_names.append(arg)
66
+ i += 1
67
+
68
+ # Default variable is REPLY
69
+ if not var_names:
70
+ var_names = ["REPLY"]
71
+
72
+ # Get input from stdin
73
+ stdin = ctx.stdin or ""
74
+
75
+ # Find the line to read
76
+ if delimiter == "\n":
77
+ # Standard line reading
78
+ lines = stdin.split("\n")
79
+ line = lines[0] if lines else ""
80
+ else:
81
+ # Custom delimiter
82
+ parts = stdin.split(delimiter)
83
+ line = parts[0] if parts else ""
84
+
85
+ # Apply nchars limit
86
+ if nchars is not None:
87
+ line = line[:nchars]
88
+
89
+ # Process backslash escapes if not in raw mode
90
+ if not raw_mode:
91
+ # Handle backslash-newline continuation (remove them)
92
+ line = line.replace("\\\n", "")
93
+ # Handle other escapes
94
+ result = []
95
+ i = 0
96
+ while i < len(line):
97
+ if line[i] == "\\" and i + 1 < len(line):
98
+ # Escape the next character
99
+ result.append(line[i + 1])
100
+ i += 2
101
+ else:
102
+ result.append(line[i])
103
+ i += 1
104
+ line = "".join(result)
105
+
106
+ # Split on IFS
107
+ ifs = ctx.env.get("IFS", " \t\n")
108
+ if ifs:
109
+ # Split on IFS characters
110
+ words = self._split_on_ifs(line, ifs)
111
+ else:
112
+ # Empty IFS - no splitting
113
+ words = [line] if line else []
114
+
115
+ # Handle -a option (read into array)
116
+ if array_name:
117
+ # Clear existing array elements
118
+ prefix = f"{array_name}_"
119
+ to_remove = [k for k in ctx.env if k.startswith(prefix) and not k.startswith(f"{array_name}__")]
120
+ for k in to_remove:
121
+ del ctx.env[k]
122
+
123
+ # Mark as array
124
+ ctx.env[f"{array_name}__is_array"] = "indexed"
125
+
126
+ # Store each word as array element
127
+ for idx, word in enumerate(words):
128
+ ctx.env[f"{array_name}_{idx}"] = word
129
+
130
+ exit_code = 0 if stdin else 1
131
+ return ExecResult(stdout="", stderr="", exit_code=exit_code)
132
+
133
+ # Assign to variables
134
+ for i, var in enumerate(var_names):
135
+ if i < len(words):
136
+ if i == len(var_names) - 1:
137
+ # Last variable gets all remaining words
138
+ ctx.env[var] = " ".join(words[i:])
139
+ else:
140
+ ctx.env[var] = words[i]
141
+ else:
142
+ ctx.env[var] = ""
143
+
144
+ # Return success if we read something, failure if EOF
145
+ exit_code = 0 if stdin else 1
146
+ return ExecResult(stdout="", stderr="", exit_code=exit_code)
147
+
148
+ def _split_on_ifs(self, value: str, ifs: str) -> list[str]:
149
+ """Split a string on IFS characters."""
150
+ if not value:
151
+ return []
152
+
153
+ # Identify IFS whitespace vs non-whitespace
154
+ ifs_whitespace = "".join(c for c in ifs if c in " \t\n")
155
+
156
+ # Simple split for whitespace-only IFS
157
+ if ifs == ifs_whitespace:
158
+ return value.split()
159
+
160
+ # Complex case with non-whitespace delimiters
161
+ result = []
162
+ current = []
163
+ i = 0
164
+ while i < len(value):
165
+ c = value[i]
166
+ if c in ifs_whitespace:
167
+ if current:
168
+ result.append("".join(current))
169
+ current = []
170
+ # Skip consecutive whitespace
171
+ while i < len(value) and value[i] in ifs_whitespace:
172
+ i += 1
173
+ elif c in ifs:
174
+ # Non-whitespace delimiter
175
+ result.append("".join(current))
176
+ current = []
177
+ i += 1
178
+ else:
179
+ current.append(c)
180
+ i += 1
181
+
182
+ if current:
183
+ result.append("".join(current))
184
+
185
+ return result
@@ -0,0 +1,5 @@
1
+ """Readlink command."""
2
+
3
+ from .readlink import ReadlinkCommand
4
+
5
+ __all__ = ["ReadlinkCommand"]
@@ -0,0 +1,86 @@
1
+ """Readlink command implementation."""
2
+
3
+ from ...types import CommandContext, ExecResult
4
+
5
+
6
+ class ReadlinkCommand:
7
+ """The readlink command."""
8
+
9
+ name = "readlink"
10
+
11
+ async def execute(self, args: list[str], ctx: CommandContext) -> ExecResult:
12
+ """Execute the readlink command."""
13
+ canonicalize = False
14
+ paths: list[str] = []
15
+
16
+ i = 0
17
+ while i < len(args):
18
+ arg = args[i]
19
+ if arg in ("-f", "--canonicalize", "-e", "--canonicalize-existing"):
20
+ canonicalize = True
21
+ elif arg == "--help":
22
+ return ExecResult(
23
+ stdout="Usage: readlink [OPTION]... FILE...\n",
24
+ stderr="",
25
+ exit_code=0,
26
+ )
27
+ elif arg == "--":
28
+ paths.extend(args[i + 1:])
29
+ break
30
+ elif arg.startswith("-") and len(arg) > 1:
31
+ return ExecResult(
32
+ stdout="",
33
+ stderr=f"readlink: invalid option -- '{arg[1]}'\n",
34
+ exit_code=1,
35
+ )
36
+ else:
37
+ paths.append(arg)
38
+ i += 1
39
+
40
+ if not paths:
41
+ return ExecResult(
42
+ stdout="",
43
+ stderr="readlink: missing operand\n",
44
+ exit_code=1,
45
+ )
46
+
47
+ stdout_parts = []
48
+ stderr = ""
49
+ exit_code = 0
50
+
51
+ for path in paths:
52
+ try:
53
+ resolved = ctx.fs.resolve_path(ctx.cwd, path)
54
+ # Use lstat to not follow symlinks
55
+ stat = await ctx.fs.lstat(resolved)
56
+
57
+ if canonicalize:
58
+ # Return the canonical path
59
+ if stat.is_symbolic_link:
60
+ target = await ctx.fs.readlink(resolved)
61
+ if not target.startswith("/"):
62
+ import os
63
+ target = ctx.fs.resolve_path(os.path.dirname(resolved), target)
64
+ stdout_parts.append(target)
65
+ else:
66
+ stdout_parts.append(resolved)
67
+ else:
68
+ # Only works on symlinks
69
+ if stat.is_symbolic_link:
70
+ target = await ctx.fs.readlink(resolved)
71
+ stdout_parts.append(target)
72
+ else:
73
+ stderr += f"readlink: {path}: Not a symbolic link\n"
74
+ exit_code = 1
75
+ except FileNotFoundError:
76
+ stderr += f"readlink: {path}: No such file or directory\n"
77
+ exit_code = 1
78
+ except Exception as e:
79
+ stderr += f"readlink: {path}: {e}\n"
80
+ exit_code = 1
81
+
82
+ stdout = "\n".join(stdout_parts)
83
+ if stdout:
84
+ stdout += "\n"
85
+
86
+ return ExecResult(stdout=stdout, stderr=stderr, exit_code=exit_code)