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.
- just_bash/__init__.py +55 -0
- just_bash/ast/__init__.py +213 -0
- just_bash/ast/factory.py +320 -0
- just_bash/ast/types.py +953 -0
- just_bash/bash.py +220 -0
- just_bash/commands/__init__.py +23 -0
- just_bash/commands/argv/__init__.py +5 -0
- just_bash/commands/argv/argv.py +21 -0
- just_bash/commands/awk/__init__.py +5 -0
- just_bash/commands/awk/awk.py +1168 -0
- just_bash/commands/base64/__init__.py +5 -0
- just_bash/commands/base64/base64.py +138 -0
- just_bash/commands/basename/__init__.py +5 -0
- just_bash/commands/basename/basename.py +72 -0
- just_bash/commands/bash/__init__.py +5 -0
- just_bash/commands/bash/bash.py +188 -0
- just_bash/commands/cat/__init__.py +5 -0
- just_bash/commands/cat/cat.py +173 -0
- just_bash/commands/checksum/__init__.py +5 -0
- just_bash/commands/checksum/checksum.py +179 -0
- just_bash/commands/chmod/__init__.py +5 -0
- just_bash/commands/chmod/chmod.py +216 -0
- just_bash/commands/column/__init__.py +5 -0
- just_bash/commands/column/column.py +180 -0
- just_bash/commands/comm/__init__.py +5 -0
- just_bash/commands/comm/comm.py +150 -0
- just_bash/commands/compression/__init__.py +5 -0
- just_bash/commands/compression/compression.py +298 -0
- just_bash/commands/cp/__init__.py +5 -0
- just_bash/commands/cp/cp.py +149 -0
- just_bash/commands/curl/__init__.py +5 -0
- just_bash/commands/curl/curl.py +801 -0
- just_bash/commands/cut/__init__.py +5 -0
- just_bash/commands/cut/cut.py +327 -0
- just_bash/commands/date/__init__.py +5 -0
- just_bash/commands/date/date.py +258 -0
- just_bash/commands/diff/__init__.py +5 -0
- just_bash/commands/diff/diff.py +118 -0
- just_bash/commands/dirname/__init__.py +5 -0
- just_bash/commands/dirname/dirname.py +56 -0
- just_bash/commands/du/__init__.py +5 -0
- just_bash/commands/du/du.py +150 -0
- just_bash/commands/echo/__init__.py +5 -0
- just_bash/commands/echo/echo.py +125 -0
- just_bash/commands/env/__init__.py +5 -0
- just_bash/commands/env/env.py +163 -0
- just_bash/commands/expand/__init__.py +5 -0
- just_bash/commands/expand/expand.py +299 -0
- just_bash/commands/expr/__init__.py +5 -0
- just_bash/commands/expr/expr.py +273 -0
- just_bash/commands/file/__init__.py +5 -0
- just_bash/commands/file/file.py +274 -0
- just_bash/commands/find/__init__.py +5 -0
- just_bash/commands/find/find.py +623 -0
- just_bash/commands/fold/__init__.py +5 -0
- just_bash/commands/fold/fold.py +160 -0
- just_bash/commands/grep/__init__.py +5 -0
- just_bash/commands/grep/grep.py +418 -0
- just_bash/commands/head/__init__.py +5 -0
- just_bash/commands/head/head.py +167 -0
- just_bash/commands/help/__init__.py +5 -0
- just_bash/commands/help/help.py +67 -0
- just_bash/commands/hostname/__init__.py +5 -0
- just_bash/commands/hostname/hostname.py +21 -0
- just_bash/commands/html_to_markdown/__init__.py +5 -0
- just_bash/commands/html_to_markdown/html_to_markdown.py +191 -0
- just_bash/commands/join/__init__.py +5 -0
- just_bash/commands/join/join.py +252 -0
- just_bash/commands/jq/__init__.py +5 -0
- just_bash/commands/jq/jq.py +280 -0
- just_bash/commands/ln/__init__.py +5 -0
- just_bash/commands/ln/ln.py +127 -0
- just_bash/commands/ls/__init__.py +5 -0
- just_bash/commands/ls/ls.py +280 -0
- just_bash/commands/mkdir/__init__.py +5 -0
- just_bash/commands/mkdir/mkdir.py +92 -0
- just_bash/commands/mv/__init__.py +5 -0
- just_bash/commands/mv/mv.py +142 -0
- just_bash/commands/nl/__init__.py +5 -0
- just_bash/commands/nl/nl.py +180 -0
- just_bash/commands/od/__init__.py +5 -0
- just_bash/commands/od/od.py +157 -0
- just_bash/commands/paste/__init__.py +5 -0
- just_bash/commands/paste/paste.py +100 -0
- just_bash/commands/printf/__init__.py +5 -0
- just_bash/commands/printf/printf.py +157 -0
- just_bash/commands/pwd/__init__.py +5 -0
- just_bash/commands/pwd/pwd.py +23 -0
- just_bash/commands/read/__init__.py +5 -0
- just_bash/commands/read/read.py +185 -0
- just_bash/commands/readlink/__init__.py +5 -0
- just_bash/commands/readlink/readlink.py +86 -0
- just_bash/commands/registry.py +844 -0
- just_bash/commands/rev/__init__.py +5 -0
- just_bash/commands/rev/rev.py +74 -0
- just_bash/commands/rg/__init__.py +5 -0
- just_bash/commands/rg/rg.py +1048 -0
- just_bash/commands/rm/__init__.py +5 -0
- just_bash/commands/rm/rm.py +106 -0
- just_bash/commands/search_engine/__init__.py +13 -0
- just_bash/commands/search_engine/matcher.py +170 -0
- just_bash/commands/search_engine/regex.py +159 -0
- just_bash/commands/sed/__init__.py +5 -0
- just_bash/commands/sed/sed.py +863 -0
- just_bash/commands/seq/__init__.py +5 -0
- just_bash/commands/seq/seq.py +190 -0
- just_bash/commands/shell/__init__.py +5 -0
- just_bash/commands/shell/shell.py +206 -0
- just_bash/commands/sleep/__init__.py +5 -0
- just_bash/commands/sleep/sleep.py +62 -0
- just_bash/commands/sort/__init__.py +5 -0
- just_bash/commands/sort/sort.py +411 -0
- just_bash/commands/split/__init__.py +5 -0
- just_bash/commands/split/split.py +237 -0
- just_bash/commands/sqlite3/__init__.py +5 -0
- just_bash/commands/sqlite3/sqlite3_cmd.py +505 -0
- just_bash/commands/stat/__init__.py +5 -0
- just_bash/commands/stat/stat.py +150 -0
- just_bash/commands/strings/__init__.py +5 -0
- just_bash/commands/strings/strings.py +150 -0
- just_bash/commands/tac/__init__.py +5 -0
- just_bash/commands/tac/tac.py +158 -0
- just_bash/commands/tail/__init__.py +5 -0
- just_bash/commands/tail/tail.py +180 -0
- just_bash/commands/tar/__init__.py +5 -0
- just_bash/commands/tar/tar.py +1067 -0
- just_bash/commands/tee/__init__.py +5 -0
- just_bash/commands/tee/tee.py +63 -0
- just_bash/commands/timeout/__init__.py +5 -0
- just_bash/commands/timeout/timeout.py +188 -0
- just_bash/commands/touch/__init__.py +5 -0
- just_bash/commands/touch/touch.py +91 -0
- just_bash/commands/tr/__init__.py +5 -0
- just_bash/commands/tr/tr.py +297 -0
- just_bash/commands/tree/__init__.py +5 -0
- just_bash/commands/tree/tree.py +139 -0
- just_bash/commands/true/__init__.py +5 -0
- just_bash/commands/true/true.py +32 -0
- just_bash/commands/uniq/__init__.py +5 -0
- just_bash/commands/uniq/uniq.py +323 -0
- just_bash/commands/wc/__init__.py +5 -0
- just_bash/commands/wc/wc.py +169 -0
- just_bash/commands/which/__init__.py +5 -0
- just_bash/commands/which/which.py +52 -0
- just_bash/commands/xan/__init__.py +5 -0
- just_bash/commands/xan/xan.py +1663 -0
- just_bash/commands/xargs/__init__.py +5 -0
- just_bash/commands/xargs/xargs.py +136 -0
- just_bash/commands/yq/__init__.py +5 -0
- just_bash/commands/yq/yq.py +848 -0
- just_bash/fs/__init__.py +29 -0
- just_bash/fs/in_memory_fs.py +621 -0
- just_bash/fs/mountable_fs.py +504 -0
- just_bash/fs/overlay_fs.py +894 -0
- just_bash/fs/read_write_fs.py +455 -0
- just_bash/interpreter/__init__.py +37 -0
- just_bash/interpreter/builtins/__init__.py +92 -0
- just_bash/interpreter/builtins/alias.py +154 -0
- just_bash/interpreter/builtins/cd.py +76 -0
- just_bash/interpreter/builtins/control.py +127 -0
- just_bash/interpreter/builtins/declare.py +336 -0
- just_bash/interpreter/builtins/export.py +56 -0
- just_bash/interpreter/builtins/let.py +44 -0
- just_bash/interpreter/builtins/local.py +57 -0
- just_bash/interpreter/builtins/mapfile.py +152 -0
- just_bash/interpreter/builtins/misc.py +378 -0
- just_bash/interpreter/builtins/readonly.py +80 -0
- just_bash/interpreter/builtins/set.py +234 -0
- just_bash/interpreter/builtins/shopt.py +201 -0
- just_bash/interpreter/builtins/source.py +136 -0
- just_bash/interpreter/builtins/test.py +290 -0
- just_bash/interpreter/builtins/unset.py +53 -0
- just_bash/interpreter/conditionals.py +387 -0
- just_bash/interpreter/control_flow.py +381 -0
- just_bash/interpreter/errors.py +116 -0
- just_bash/interpreter/expansion.py +1156 -0
- just_bash/interpreter/interpreter.py +813 -0
- just_bash/interpreter/types.py +134 -0
- just_bash/network/__init__.py +1 -0
- just_bash/parser/__init__.py +39 -0
- just_bash/parser/lexer.py +948 -0
- just_bash/parser/parser.py +2162 -0
- just_bash/py.typed +0 -0
- just_bash/query_engine/__init__.py +83 -0
- just_bash/query_engine/builtins/__init__.py +1283 -0
- just_bash/query_engine/evaluator.py +578 -0
- just_bash/query_engine/parser.py +525 -0
- just_bash/query_engine/tokenizer.py +329 -0
- just_bash/query_engine/types.py +373 -0
- just_bash/types.py +180 -0
- just_bash-0.1.5.dist-info/METADATA +410 -0
- just_bash-0.1.5.dist-info/RECORD +193 -0
- just_bash-0.1.5.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"""File command implementation - determine file type."""
|
|
2
|
+
|
|
3
|
+
from ...types import CommandContext, ExecResult
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FileCommand:
|
|
7
|
+
"""The file command - determine file type."""
|
|
8
|
+
|
|
9
|
+
name = "file"
|
|
10
|
+
|
|
11
|
+
# Magic bytes for common file types (ordered by specificity - longer prefixes first)
|
|
12
|
+
MAGIC_BYTES: list[tuple[bytes, str]] = [
|
|
13
|
+
# Images
|
|
14
|
+
(b"\x89PNG\r\n\x1a\n", "PNG image data"),
|
|
15
|
+
(b"GIF87a", "GIF image data, version 87a"),
|
|
16
|
+
(b"GIF89a", "GIF image data, version 89a"),
|
|
17
|
+
(b"\xff\xd8\xff", "JPEG image data"),
|
|
18
|
+
(b"RIFF", "RIFF data"),
|
|
19
|
+
(b"BM", "PC bitmap"),
|
|
20
|
+
(b"\x00\x00\x01\x00", "MS Windows icon resource"),
|
|
21
|
+
(b"\x00\x00\x02\x00", "MS Windows cursor resource"),
|
|
22
|
+
|
|
23
|
+
# Archives
|
|
24
|
+
(b"PK\x03\x04", "Zip archive data"),
|
|
25
|
+
(b"PK\x05\x06", "Zip archive data (empty)"),
|
|
26
|
+
(b"Rar!\x1a\x07", "RAR archive data"),
|
|
27
|
+
(b"7z\xbc\xaf\x27\x1c", "7-zip archive data"),
|
|
28
|
+
|
|
29
|
+
# Compressed
|
|
30
|
+
(b"\x1f\x8b", "gzip compressed data"),
|
|
31
|
+
(b"BZh", "bzip2 compressed data"),
|
|
32
|
+
(b"\xfd7zXZ\x00", "XZ compressed data"),
|
|
33
|
+
|
|
34
|
+
# Documents
|
|
35
|
+
(b"%PDF", "PDF document"),
|
|
36
|
+
|
|
37
|
+
# Executables
|
|
38
|
+
(b"\x7fELF", "ELF"),
|
|
39
|
+
(b"MZ", "DOS/Windows executable"),
|
|
40
|
+
(b"\xca\xfe\xba\xbe", "Mach-O universal binary"),
|
|
41
|
+
(b"\xfe\xed\xfa\xce", "Mach-O 32-bit executable"),
|
|
42
|
+
(b"\xfe\xed\xfa\xcf", "Mach-O 64-bit executable"),
|
|
43
|
+
(b"\xcf\xfa\xed\xfe", "Mach-O 64-bit executable"),
|
|
44
|
+
(b"\xce\xfa\xed\xfe", "Mach-O 32-bit executable"),
|
|
45
|
+
|
|
46
|
+
# Databases
|
|
47
|
+
(b"SQLite format 3", "SQLite 3.x database"),
|
|
48
|
+
|
|
49
|
+
# Audio/Video
|
|
50
|
+
(b"ID3", "Audio file with ID3 tag"),
|
|
51
|
+
(b"\xff\xfb", "MPEG ADTS, layer III (MP3)"),
|
|
52
|
+
(b"\xff\xfa", "MPEG ADTS, layer III (MP3)"),
|
|
53
|
+
(b"OggS", "Ogg data"),
|
|
54
|
+
(b"fLaC", "FLAC audio"),
|
|
55
|
+
|
|
56
|
+
# Web/Data
|
|
57
|
+
(b"<!DOCTYPE html", "HTML document"),
|
|
58
|
+
(b"<!doctype html", "HTML document"),
|
|
59
|
+
(b"<html", "HTML document"),
|
|
60
|
+
(b"<?xml", "XML document"),
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
MIME_TYPES = {
|
|
64
|
+
"PNG image data": "image/png",
|
|
65
|
+
"GIF image data, version 87a": "image/gif",
|
|
66
|
+
"GIF image data, version 89a": "image/gif",
|
|
67
|
+
"GIF image data": "image/gif",
|
|
68
|
+
"JPEG image data": "image/jpeg",
|
|
69
|
+
"Zip archive data": "application/zip",
|
|
70
|
+
"Zip archive data (empty)": "application/zip",
|
|
71
|
+
"PDF document": "application/pdf",
|
|
72
|
+
"gzip compressed data": "application/gzip",
|
|
73
|
+
"bzip2 compressed data": "application/x-bzip2",
|
|
74
|
+
"ASCII text": "text/plain",
|
|
75
|
+
"directory": "inode/directory",
|
|
76
|
+
"empty": "inode/x-empty",
|
|
77
|
+
"JSON text data": "application/json",
|
|
78
|
+
"ELF": "application/x-executable",
|
|
79
|
+
"Mach-O 64-bit executable": "application/x-mach-binary",
|
|
80
|
+
"Mach-O 32-bit executable": "application/x-mach-binary",
|
|
81
|
+
"Mach-O universal binary": "application/x-mach-binary",
|
|
82
|
+
"SQLite 3.x database": "application/x-sqlite3",
|
|
83
|
+
"XML document": "text/xml",
|
|
84
|
+
"HTML document": "text/html",
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Extension-based detection
|
|
88
|
+
EXTENSION_MAP: dict[str, tuple[str, str]] = {
|
|
89
|
+
# Programming languages
|
|
90
|
+
".py": ("Python script", "text/x-python"),
|
|
91
|
+
".js": ("JavaScript source", "text/javascript"),
|
|
92
|
+
".ts": ("TypeScript source", "text/typescript"),
|
|
93
|
+
".jsx": ("JavaScript JSX source", "text/jsx"),
|
|
94
|
+
".tsx": ("TypeScript JSX source", "text/tsx"),
|
|
95
|
+
".rb": ("Ruby script", "text/x-ruby"),
|
|
96
|
+
".go": ("Go source", "text/x-go"),
|
|
97
|
+
".rs": ("Rust source", "text/x-rust"),
|
|
98
|
+
".c": ("C source", "text/x-c"),
|
|
99
|
+
".cpp": ("C++ source", "text/x-c++"),
|
|
100
|
+
".h": ("C header", "text/x-c"),
|
|
101
|
+
".java": ("Java source", "text/x-java"),
|
|
102
|
+
".kt": ("Kotlin source", "text/x-kotlin"),
|
|
103
|
+
".swift": ("Swift source", "text/x-swift"),
|
|
104
|
+
".php": ("PHP script", "text/x-php"),
|
|
105
|
+
".pl": ("Perl script", "text/x-perl"),
|
|
106
|
+
".sh": ("Bourne-Again shell script", "text/x-shellscript"),
|
|
107
|
+
".bash": ("Bourne-Again shell script", "text/x-shellscript"),
|
|
108
|
+
".zsh": ("Zsh script", "text/x-shellscript"),
|
|
109
|
+
|
|
110
|
+
# Data formats
|
|
111
|
+
".json": ("JSON text data", "application/json"),
|
|
112
|
+
".yaml": ("YAML document", "text/yaml"),
|
|
113
|
+
".yml": ("YAML document", "text/yaml"),
|
|
114
|
+
".xml": ("XML document", "text/xml"),
|
|
115
|
+
".csv": ("CSV text", "text/csv"),
|
|
116
|
+
".toml": ("TOML document", "text/toml"),
|
|
117
|
+
|
|
118
|
+
# Documentation
|
|
119
|
+
".md": ("Markdown document", "text/markdown"),
|
|
120
|
+
".rst": ("reStructuredText document", "text/x-rst"),
|
|
121
|
+
".txt": ("ASCII text", "text/plain"),
|
|
122
|
+
|
|
123
|
+
# Config
|
|
124
|
+
".ini": ("INI configuration", "text/plain"),
|
|
125
|
+
".conf": ("Configuration file", "text/plain"),
|
|
126
|
+
".cfg": ("Configuration file", "text/plain"),
|
|
127
|
+
".env": ("Environment file", "text/plain"),
|
|
128
|
+
|
|
129
|
+
# Web
|
|
130
|
+
".html": ("HTML document", "text/html"),
|
|
131
|
+
".htm": ("HTML document", "text/html"),
|
|
132
|
+
".css": ("CSS stylesheet", "text/css"),
|
|
133
|
+
".scss": ("Sass stylesheet", "text/x-scss"),
|
|
134
|
+
".less": ("Less stylesheet", "text/x-less"),
|
|
135
|
+
".svg": ("SVG image", "image/svg+xml"),
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# Shebang interpreter detection
|
|
139
|
+
SHEBANG_MAP = {
|
|
140
|
+
"python": "Python script",
|
|
141
|
+
"python3": "Python script",
|
|
142
|
+
"python2": "Python script",
|
|
143
|
+
"node": "Node.js script",
|
|
144
|
+
"nodejs": "Node.js script",
|
|
145
|
+
"bash": "Bourne-Again shell script",
|
|
146
|
+
"sh": "POSIX shell script",
|
|
147
|
+
"zsh": "Zsh script",
|
|
148
|
+
"ruby": "Ruby script",
|
|
149
|
+
"perl": "Perl script",
|
|
150
|
+
"php": "PHP script",
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async def execute(self, args: list[str], ctx: CommandContext) -> ExecResult:
|
|
154
|
+
"""Execute the file command."""
|
|
155
|
+
mime_mode = False
|
|
156
|
+
brief_mode = False
|
|
157
|
+
paths: list[str] = []
|
|
158
|
+
|
|
159
|
+
i = 0
|
|
160
|
+
while i < len(args):
|
|
161
|
+
arg = args[i]
|
|
162
|
+
if arg in ("-i", "--mime"):
|
|
163
|
+
mime_mode = True
|
|
164
|
+
elif arg in ("-b", "--brief"):
|
|
165
|
+
brief_mode = True
|
|
166
|
+
elif arg == "--help":
|
|
167
|
+
return ExecResult(
|
|
168
|
+
stdout="Usage: file [OPTION...] [FILE...]\n",
|
|
169
|
+
stderr="",
|
|
170
|
+
exit_code=0,
|
|
171
|
+
)
|
|
172
|
+
elif arg.startswith("-"):
|
|
173
|
+
pass # Ignore unknown options
|
|
174
|
+
else:
|
|
175
|
+
paths.append(arg)
|
|
176
|
+
i += 1
|
|
177
|
+
|
|
178
|
+
if not paths:
|
|
179
|
+
return ExecResult(
|
|
180
|
+
stdout="",
|
|
181
|
+
stderr="file: missing file operand\n",
|
|
182
|
+
exit_code=1,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
output_lines = []
|
|
186
|
+
exit_code = 0
|
|
187
|
+
|
|
188
|
+
for path in paths:
|
|
189
|
+
try:
|
|
190
|
+
resolved = ctx.fs.resolve_path(ctx.cwd, path)
|
|
191
|
+
stat = await ctx.fs.stat(resolved)
|
|
192
|
+
|
|
193
|
+
if stat.is_directory:
|
|
194
|
+
file_type = "directory"
|
|
195
|
+
else:
|
|
196
|
+
content = await ctx.fs.read_file(resolved)
|
|
197
|
+
# Check for empty file
|
|
198
|
+
if len(content) == 0:
|
|
199
|
+
file_type = "empty"
|
|
200
|
+
else:
|
|
201
|
+
file_type = self._detect_type(path, content)
|
|
202
|
+
|
|
203
|
+
if mime_mode:
|
|
204
|
+
mime = self.MIME_TYPES.get(file_type, "application/octet-stream")
|
|
205
|
+
if file_type == "ASCII text":
|
|
206
|
+
mime += "; charset=us-ascii"
|
|
207
|
+
result = mime
|
|
208
|
+
else:
|
|
209
|
+
result = file_type
|
|
210
|
+
|
|
211
|
+
if brief_mode:
|
|
212
|
+
output_lines.append(result)
|
|
213
|
+
else:
|
|
214
|
+
output_lines.append(f"{path}: {result}")
|
|
215
|
+
|
|
216
|
+
except FileNotFoundError:
|
|
217
|
+
output_lines.append(f"{path}: cannot open (No such file or directory)")
|
|
218
|
+
exit_code = 1
|
|
219
|
+
except Exception as e:
|
|
220
|
+
output_lines.append(f"{path}: cannot open ({e})")
|
|
221
|
+
exit_code = 1
|
|
222
|
+
|
|
223
|
+
return ExecResult(
|
|
224
|
+
stdout="\n".join(output_lines) + "\n",
|
|
225
|
+
stderr="",
|
|
226
|
+
exit_code=exit_code,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
def _detect_type(self, path: str, content: str) -> str:
|
|
230
|
+
"""Detect file type from content."""
|
|
231
|
+
# Try binary detection first (magic bytes)
|
|
232
|
+
try:
|
|
233
|
+
content_bytes = content.encode("latin-1")
|
|
234
|
+
|
|
235
|
+
for magic, file_type in self.MAGIC_BYTES:
|
|
236
|
+
if content_bytes.startswith(magic):
|
|
237
|
+
return file_type
|
|
238
|
+
except Exception:
|
|
239
|
+
pass
|
|
240
|
+
|
|
241
|
+
# Check for shebang
|
|
242
|
+
if content.startswith("#!"):
|
|
243
|
+
first_line = content.split("\n")[0]
|
|
244
|
+
# Parse the interpreter from shebang
|
|
245
|
+
shebang = first_line[2:].strip()
|
|
246
|
+
parts = shebang.split()
|
|
247
|
+
if parts:
|
|
248
|
+
# Handle /usr/bin/env <interpreter>
|
|
249
|
+
interpreter = parts[0].rsplit("/", 1)[-1]
|
|
250
|
+
if interpreter == "env" and len(parts) > 1:
|
|
251
|
+
interpreter = parts[1].rsplit("/", 1)[-1]
|
|
252
|
+
|
|
253
|
+
# Check against SHEBANG_MAP
|
|
254
|
+
for key, script_type in self.SHEBANG_MAP.items():
|
|
255
|
+
if interpreter.startswith(key):
|
|
256
|
+
return f"{script_type}, ASCII text executable"
|
|
257
|
+
|
|
258
|
+
# Fallback for unknown interpreters
|
|
259
|
+
return "script, ASCII text executable"
|
|
260
|
+
|
|
261
|
+
# Check extension using EXTENSION_MAP
|
|
262
|
+
if "." in path:
|
|
263
|
+
ext = "." + path.rsplit(".", 1)[-1].lower()
|
|
264
|
+
if ext in self.EXTENSION_MAP:
|
|
265
|
+
return self.EXTENSION_MAP[ext][0]
|
|
266
|
+
|
|
267
|
+
# Check for text
|
|
268
|
+
try:
|
|
269
|
+
content.encode("ascii")
|
|
270
|
+
if "\r\n" in content:
|
|
271
|
+
return "ASCII text, with CRLF line terminators"
|
|
272
|
+
return "ASCII text"
|
|
273
|
+
except UnicodeEncodeError:
|
|
274
|
+
return "UTF-8 Unicode text"
|