fauxnix-cli 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +179 -0
- package/dist/ast.d.ts +72 -0
- package/dist/ast.js +43 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +91 -0
- package/dist/commands/archive.d.ts +2 -0
- package/dist/commands/archive.js +385 -0
- package/dist/commands/files.d.ts +2 -0
- package/dist/commands/files.js +721 -0
- package/dist/commands/install-all.d.ts +2 -0
- package/dist/commands/install-all.js +17 -0
- package/dist/commands/net.d.ts +2 -0
- package/dist/commands/net.js +533 -0
- package/dist/commands/sysinfo.d.ts +2 -0
- package/dist/commands/sysinfo.js +1138 -0
- package/dist/commands/text-filters.d.ts +2 -0
- package/dist/commands/text-filters.js +2281 -0
- package/dist/commands/text-io.d.ts +2 -0
- package/dist/commands/text-io.js +1164 -0
- package/dist/encoding.d.ts +7 -0
- package/dist/encoding.js +29 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +103 -0
- package/dist/executor.d.ts +27 -0
- package/dist/executor.js +299 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.js +79 -0
- package/dist/parser.d.ts +11 -0
- package/dist/parser.js +400 -0
- package/dist/registry.d.ts +79 -0
- package/dist/registry.js +145 -0
- package/dist/translator.d.ts +55 -0
- package/dist/translator.js +318 -0
- package/package.json +57 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { wordToString } from '../ast.js';
|
|
2
|
+
import { psStr } from '../registry.js';
|
|
3
|
+
import { exprOfWord, operandExpr } from '../translator.js';
|
|
4
|
+
/* ------------------------------------------------------------------ */
|
|
5
|
+
/* gzip family — .NET GZipStream helpers */
|
|
6
|
+
/* ------------------------------------------------------------------ */
|
|
7
|
+
const PS_GZ_FNS = [
|
|
8
|
+
'Add-Type -AssemblyName System.IO.Compression',
|
|
9
|
+
'function fx-dec($b) {',
|
|
10
|
+
' try { return (New-Object System.Text.UTF8Encoding($false, $true)).GetString($b) }',
|
|
11
|
+
' catch { try { return [System.Text.Encoding]::GetEncoding(936).GetString($b) } catch { return [System.Text.Encoding]::ASCII.GetString($b) } }',
|
|
12
|
+
'}',
|
|
13
|
+
// emit text as one string per line (trailing newline does not add an empty line)
|
|
14
|
+
'function fx-lines($t) {',
|
|
15
|
+
' if ($null -eq $t) { return @() }',
|
|
16
|
+
' $fx_ls = @($t -split "`r?`n")',
|
|
17
|
+
" if ($fx_ls.Count -eq 1 -and $fx_ls[0] -eq '') { return @() }",
|
|
18
|
+
" if ($fx_ls[$fx_ls.Count - 1] -eq '') { $fx_ls = @($fx_ls[0..($fx_ls.Count - 2)]) }",
|
|
19
|
+
' return $fx_ls',
|
|
20
|
+
'}',
|
|
21
|
+
// compress byte[] → byte[]; -1..-3 ≈ Fastest, -4..-9 ≈ Optimal (.NET has no finer steps)
|
|
22
|
+
'function fx-gz-cbytes($b, $lvl) {',
|
|
23
|
+
' $fx_lv = [System.IO.Compression.CompressionLevel]::Optimal',
|
|
24
|
+
' if ($lvl -le 3) { $fx_lv = [System.IO.Compression.CompressionLevel]::Fastest }',
|
|
25
|
+
' $fx_ms = New-Object System.IO.MemoryStream',
|
|
26
|
+
' $fx_gz = New-Object System.IO.Compression.GZipStream($fx_ms, $fx_lv, $false)',
|
|
27
|
+
' $fx_gz.Write($b, 0, $b.Length)',
|
|
28
|
+
' $fx_gz.Close()',
|
|
29
|
+
' return ,$fx_ms.ToArray()',
|
|
30
|
+
'}',
|
|
31
|
+
'function fx-gz-dbytes($src) {',
|
|
32
|
+
' $fx_fs = [IO.File]::OpenRead($src)',
|
|
33
|
+
' $fx_gz = New-Object System.IO.Compression.GZipStream($fx_fs, [System.IO.Compression.CompressionMode]::Decompress)',
|
|
34
|
+
' $fx_ms = New-Object System.IO.MemoryStream',
|
|
35
|
+
' $fx_buf = New-Object byte[] 65536',
|
|
36
|
+
' while ($true) {',
|
|
37
|
+
' $fx_n = $fx_gz.Read($fx_buf, 0, $fx_buf.Length)',
|
|
38
|
+
' if ($fx_n -le 0) { break }',
|
|
39
|
+
' $fx_ms.Write($fx_buf, 0, $fx_n)',
|
|
40
|
+
' }',
|
|
41
|
+
' $fx_gz.Close()',
|
|
42
|
+
' $fx_fs.Close()',
|
|
43
|
+
' return ,$fx_ms.ToArray()',
|
|
44
|
+
'}',
|
|
45
|
+
].join('\n');
|
|
46
|
+
/** Parse GNU gzip-style argv (works for gzip/gunzip/zcat). */
|
|
47
|
+
function parseGzipArgs(args) {
|
|
48
|
+
const p = {
|
|
49
|
+
decompress: false,
|
|
50
|
+
keep: false,
|
|
51
|
+
stdout: false,
|
|
52
|
+
level: 6,
|
|
53
|
+
test: false,
|
|
54
|
+
files: [],
|
|
55
|
+
};
|
|
56
|
+
const raw = args.map(wordToString);
|
|
57
|
+
let i = 0;
|
|
58
|
+
for (; i < raw.length; i++) {
|
|
59
|
+
const t = raw[i];
|
|
60
|
+
if (t === '--') {
|
|
61
|
+
p.files.push(...args.slice(i + 1));
|
|
62
|
+
return p;
|
|
63
|
+
}
|
|
64
|
+
if (t.startsWith('--')) {
|
|
65
|
+
const eq = t.indexOf('=');
|
|
66
|
+
const name = eq >= 0 ? t.slice(2, eq) : t.slice(2);
|
|
67
|
+
if (name === 'decompress' || name === 'uncompress')
|
|
68
|
+
p.decompress = true;
|
|
69
|
+
else if (name === 'keep')
|
|
70
|
+
p.keep = true;
|
|
71
|
+
else if (name === 'stdout' || name === 'to-stdout')
|
|
72
|
+
p.stdout = true;
|
|
73
|
+
else if (name === 'fast')
|
|
74
|
+
p.level = 1;
|
|
75
|
+
else if (name === 'best')
|
|
76
|
+
p.level = 9;
|
|
77
|
+
else if (name === 'test')
|
|
78
|
+
p.test = true;
|
|
79
|
+
else if (name === 'suffix') {
|
|
80
|
+
if (eq < 0)
|
|
81
|
+
i++; // consumes a following value; unsupported either way
|
|
82
|
+
}
|
|
83
|
+
// other long options (force/quiet/verbose/no-name/recursive...) ignored
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (/^-[1-9]$/.test(t)) {
|
|
87
|
+
p.level = parseInt(t.slice(1), 10);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (t.startsWith('-') && t.length > 1 && !/^-\d/.test(t)) {
|
|
91
|
+
for (const c of t.slice(1)) {
|
|
92
|
+
if (c === 'd')
|
|
93
|
+
p.decompress = true;
|
|
94
|
+
else if (c === 'k')
|
|
95
|
+
p.keep = true;
|
|
96
|
+
else if (c === 'c')
|
|
97
|
+
p.stdout = true;
|
|
98
|
+
else if (c === 't')
|
|
99
|
+
p.test = true;
|
|
100
|
+
// f/q/v/n/r accepted as no-ops
|
|
101
|
+
}
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
p.files.push(args[i]);
|
|
105
|
+
}
|
|
106
|
+
return p;
|
|
107
|
+
}
|
|
108
|
+
/** Build the PS block shared by gzip / gunzip / zcat. */
|
|
109
|
+
function gzBlock(args, ctx, forced) {
|
|
110
|
+
const p = { ...parseGzipArgs(args), ...forced };
|
|
111
|
+
// Compressed stdout is binary; the fauxnix contract only carries text
|
|
112
|
+
// lines (and the executor's capture layer is UTF-8 text anyway), so the
|
|
113
|
+
// stream is emitted as one latin-1-decoded string — byte fidelity is a
|
|
114
|
+
// documented limitation (spec: "binary fidelity limitation acceptable").
|
|
115
|
+
const emitBin = (bytesExpr) => '[System.Text.Encoding]::GetEncoding(28591).GetString(' + bytesExpr + ')';
|
|
116
|
+
const b = (v) => (v ? '$true' : '$false');
|
|
117
|
+
const stdinBranch = !ctx.hasStdin
|
|
118
|
+
? [
|
|
119
|
+
p.decompress || p.test
|
|
120
|
+
? " [Console]::Error.WriteLine('gzip: compressed data not read from a terminal. Use -f to force decompression.')"
|
|
121
|
+
: " [Console]::Error.WriteLine('gzip: compressed data not written to a terminal. Use -f to force compression.')",
|
|
122
|
+
' $script:fx_exit = 1',
|
|
123
|
+
].join('\n')
|
|
124
|
+
: p.decompress
|
|
125
|
+
? [
|
|
126
|
+
// NOTE stdin fidelity limitation: pipeline stdin arrives as decoded
|
|
127
|
+
// text lines, so only gzip streams that survived the text pipeline
|
|
128
|
+
// round-trip can be decompressed here.
|
|
129
|
+
' $fx_txt = (@($input | ForEach-Object { [string]$_ }) -join "`n")',
|
|
130
|
+
" if ($fx_txt -ne '') { $fx_txt = $fx_txt + \"`n\" }",
|
|
131
|
+
' $fx_in = [System.Text.Encoding]::UTF8.GetBytes($fx_txt)',
|
|
132
|
+
' try {',
|
|
133
|
+
' $fx_ms = New-Object System.IO.MemoryStream(,$fx_in)',
|
|
134
|
+
' $fx_gz = New-Object System.IO.Compression.GZipStream($fx_ms, [System.IO.Compression.CompressionMode]::Decompress)',
|
|
135
|
+
' $fx_mo = New-Object System.IO.MemoryStream',
|
|
136
|
+
' $fx_buf = New-Object byte[] 65536',
|
|
137
|
+
' while ($true) { $fx_n = $fx_gz.Read($fx_buf, 0, $fx_buf.Length); if ($fx_n -le 0) { break }; $fx_mo.Write($fx_buf, 0, $fx_n) }',
|
|
138
|
+
' $fx_gz.Close()',
|
|
139
|
+
' fx-lines (fx-dec $fx_mo.ToArray())',
|
|
140
|
+
' } catch {',
|
|
141
|
+
" [Console]::Error.WriteLine('gzip: stdin: not in gzip format')",
|
|
142
|
+
' $script:fx_exit = 1',
|
|
143
|
+
' }',
|
|
144
|
+
].join('\n')
|
|
145
|
+
: [
|
|
146
|
+
// NOTE stdin fidelity limitation: bytes are UTF-8 re-encoded text.
|
|
147
|
+
' $fx_txt = (@($input | ForEach-Object { [string]$_ }) -join "`n")',
|
|
148
|
+
" if ($fx_txt -ne '') { $fx_txt = $fx_txt + \"`n\" }",
|
|
149
|
+
' $fx_in = [System.Text.Encoding]::UTF8.GetBytes($fx_txt)',
|
|
150
|
+
' ' + emitBin('(fx-gz-cbytes $fx_in ' + p.level + ')'),
|
|
151
|
+
].join('\n');
|
|
152
|
+
const fileLoop = [
|
|
153
|
+
' foreach ($fx_f in $fx_files) {',
|
|
154
|
+
' if (-not (Test-Path -LiteralPath $fx_f)) {',
|
|
155
|
+
" [Console]::Error.WriteLine('gzip: ' + $fx_f + ': No such file or directory')",
|
|
156
|
+
' $script:fx_exit = 1',
|
|
157
|
+
' continue',
|
|
158
|
+
' }',
|
|
159
|
+
' if (Test-Path -LiteralPath $fx_f -PathType Container) {',
|
|
160
|
+
" [Console]::Error.WriteLine('gzip: ' + $fx_f + ': is a directory -- ignored')",
|
|
161
|
+
' $script:fx_exit = 1',
|
|
162
|
+
' continue',
|
|
163
|
+
' }',
|
|
164
|
+
];
|
|
165
|
+
if (p.test) {
|
|
166
|
+
fileLoop.push(' try { $fx_tb = fx-gz-dbytes $fx_f }', " catch { [Console]::Error.WriteLine('gzip: ' + $fx_f + ': not in gzip format'); $script:fx_exit = 1 }", ' continue');
|
|
167
|
+
}
|
|
168
|
+
else if (p.decompress) {
|
|
169
|
+
fileLoop.push(' $fx_low = $fx_f.ToLower()', " if (-not ($fx_low.EndsWith('.gz') -or $fx_low.EndsWith('.tgz'))) {", " [Console]::Error.WriteLine('gzip: ' + $fx_f + ': unknown suffix -- ignored')", ' $script:fx_exit = 2', ' continue', ' }', ' $fx_out = $fx_f.Substring(0, $fx_f.Length - 3)', " if ($fx_low.EndsWith('.tgz')) { $fx_out = $fx_f.Substring(0, $fx_f.Length - 4) + '.tar' }", ' try {', p.stdout
|
|
170
|
+
? ' fx-lines (fx-dec (fx-gz-dbytes $fx_f))'
|
|
171
|
+
: [
|
|
172
|
+
' $fx_o = fx-gz-dbytes $fx_f',
|
|
173
|
+
' [IO.File]::WriteAllBytes($fx_out, $fx_o)',
|
|
174
|
+
' try { (Get-Item -LiteralPath $fx_out).LastWriteTime = (Get-Item -LiteralPath $fx_f).LastWriteTime } catch {}',
|
|
175
|
+
' if (-not ' + b(p.keep) + ') { Remove-Item -LiteralPath $fx_f -Force }',
|
|
176
|
+
].join('\n'), " } catch { [Console]::Error.WriteLine('gzip: ' + $fx_f + ': not in gzip format'); $script:fx_exit = 1 }");
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
fileLoop.push(' $fx_low = $fx_f.ToLower()', " if ($fx_low.EndsWith('.gz') -or $fx_low.EndsWith('.tgz')) {", " [Console]::Error.WriteLine('gzip: ' + $fx_f + ': already has .gz suffix -- unchanged')", ' continue', ' }', ' try {', p.stdout
|
|
180
|
+
? ' ' + emitBin('(fx-gz-cbytes ([IO.File]::ReadAllBytes($fx_f)) ' + p.level + ')')
|
|
181
|
+
: [
|
|
182
|
+
' $fx_o = fx-gz-cbytes ([IO.File]::ReadAllBytes($fx_f)) ' + p.level,
|
|
183
|
+
" [IO.File]::WriteAllBytes($fx_f + '.gz', $fx_o)",
|
|
184
|
+
" try { (Get-Item -LiteralPath ($fx_f + '.gz')).LastWriteTime = (Get-Item -LiteralPath $fx_f).LastWriteTime } catch {}",
|
|
185
|
+
' if (-not ' + b(p.keep) + ') { Remove-Item -LiteralPath $fx_f -Force }',
|
|
186
|
+
].join('\n'), " } catch { [Console]::Error.WriteLine('gzip: ' + $fx_f + ': ' + $_.Exception.Message); $script:fx_exit = 1 }");
|
|
187
|
+
}
|
|
188
|
+
fileLoop.push(' }');
|
|
189
|
+
return [
|
|
190
|
+
PS_GZ_FNS,
|
|
191
|
+
'$fx_files = @(' + (p.files.length ? p.files.map(operandExpr).join(', ') : '') + ')',
|
|
192
|
+
'if ($fx_files.Count -eq 0) {',
|
|
193
|
+
stdinBranch,
|
|
194
|
+
'} else {',
|
|
195
|
+
...fileLoop,
|
|
196
|
+
'}',
|
|
197
|
+
].join('\n');
|
|
198
|
+
}
|
|
199
|
+
const gzip = (args, ctx) => gzBlock(args, ctx, {});
|
|
200
|
+
const gunzip = (args, ctx) => gzBlock(args, ctx, { decompress: true });
|
|
201
|
+
const zcat = (args, ctx) => gzBlock(args, ctx, { decompress: true, stdout: true });
|
|
202
|
+
/* ------------------------------------------------------------------ */
|
|
203
|
+
/* tar — Windows 10+ ships bsdtar as tar.exe, pass everything through */
|
|
204
|
+
/* ------------------------------------------------------------------ */
|
|
205
|
+
const tar = (args) => {
|
|
206
|
+
return [
|
|
207
|
+
"$fx_args = @(" + args.map(exprOfWord).join(', ') + ')',
|
|
208
|
+
// Prefer the Windows-shipped bsdtar (System32): it accepts both path
|
|
209
|
+
// styles. A PATH lookup could resolve to Git Bash's GNU tar, which
|
|
210
|
+
// misreads `C:\...` argv as a remote-host spec (host:path syntax).
|
|
211
|
+
'$fx_tar = "$env:SystemRoot\\System32\\tar.exe"',
|
|
212
|
+
'if (-not (Test-Path -LiteralPath $fx_tar)) {',
|
|
213
|
+
" $fx_c = Get-Command 'tar.exe' -ErrorAction SilentlyContinue",
|
|
214
|
+
' if ($fx_c) { $fx_tar = $fx_c.Source } else { $fx_tar = $null }',
|
|
215
|
+
'}',
|
|
216
|
+
'if ($fx_tar) {',
|
|
217
|
+
' & $fx_tar @($fx_args) | ForEach-Object { [string]$_ }',
|
|
218
|
+
' if ($LASTEXITCODE -gt 0) { $script:fx_exit = $LASTEXITCODE }',
|
|
219
|
+
'} else {',
|
|
220
|
+
" [Console]::Error.WriteLine('tar: fauxnix: tar.exe not found (Windows 10+ ships bsdtar as tar.exe)')",
|
|
221
|
+
' $script:fx_exit = 1',
|
|
222
|
+
'}',
|
|
223
|
+
].join('\n');
|
|
224
|
+
};
|
|
225
|
+
/* ------------------------------------------------------------------ */
|
|
226
|
+
/* zip / unzip */
|
|
227
|
+
/* ------------------------------------------------------------------ */
|
|
228
|
+
const zip = (args) => {
|
|
229
|
+
const raw = args.map(wordToString);
|
|
230
|
+
let excludeNote = false;
|
|
231
|
+
const rest = [];
|
|
232
|
+
for (let i = 0; i < raw.length; i++) {
|
|
233
|
+
const t = raw[i];
|
|
234
|
+
if (t === '-x' || t === '--exclude') {
|
|
235
|
+
excludeNote = true;
|
|
236
|
+
if (i + 1 < args.length)
|
|
237
|
+
i++;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (t.startsWith('--exclude=')) {
|
|
241
|
+
excludeNote = true;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (t.startsWith('-') && t.length > 1 && !/^-\d/.test(t))
|
|
245
|
+
continue; // -r -q ... implicit
|
|
246
|
+
rest.push(args[i]);
|
|
247
|
+
}
|
|
248
|
+
const note = excludeNote
|
|
249
|
+
? '[Console]::Error.WriteLine(' +
|
|
250
|
+
psStr('zip: fauxnix: -x/--exclude patterns are not supported, ignoring') +
|
|
251
|
+
')\n'
|
|
252
|
+
: '';
|
|
253
|
+
if (rest.length < 2) {
|
|
254
|
+
return (note +
|
|
255
|
+
"[Console]::Error.WriteLine('zip error: Nothing to do! (fauxnix: usage: zip [-r] ARCHIVE FILES...)'); $script:fx_exit = 12");
|
|
256
|
+
}
|
|
257
|
+
const arc = operandExpr(rest[0]);
|
|
258
|
+
const inputs = rest.slice(1).map(operandExpr).join(', ');
|
|
259
|
+
return [
|
|
260
|
+
note + '$fx_arc = ' + arc,
|
|
261
|
+
'$fx_inputs = @(' + inputs + ')',
|
|
262
|
+
'$fx_valid = @()',
|
|
263
|
+
'foreach ($fx_p in $fx_inputs) {',
|
|
264
|
+
' if (Test-Path -LiteralPath $fx_p) { $fx_valid += $fx_p }',
|
|
265
|
+
" else { [Console]::Error.WriteLine('zip warning: name not matched: ' + $fx_p) }",
|
|
266
|
+
'}',
|
|
267
|
+
'if ($fx_valid.Count -eq 0) {',
|
|
268
|
+
" [Console]::Error.WriteLine('zip error: Nothing to do!')",
|
|
269
|
+
' $script:fx_exit = 12',
|
|
270
|
+
'} else {',
|
|
271
|
+
' try {',
|
|
272
|
+
// Compress-Archive keeps the trailing path component as the archive root,
|
|
273
|
+
// always includes directory contents, and appends .zip when the extension
|
|
274
|
+
// is missing (GNU zip does not) — hence the rename dance.
|
|
275
|
+
" $fx_dst = $fx_arc",
|
|
276
|
+
' $fx_rename = $false',
|
|
277
|
+
" if (-not $fx_arc.ToLower().EndsWith('.zip')) { $fx_dst = $fx_arc + '.zip'; $fx_rename = $true }",
|
|
278
|
+
' Compress-Archive -Path $fx_valid -DestinationPath $fx_dst -Force -ErrorAction Stop',
|
|
279
|
+
// PS 5.1 Compress-Archive writes `\` entry separators; rewrite them to `/`
|
|
280
|
+
// so GNU unzip/bsdtar see proper directory entries.
|
|
281
|
+
' Add-Type -AssemblyName System.IO.Compression.FileSystem',
|
|
282
|
+
' $fx_z = [IO.Compression.ZipFile]::Open($fx_dst, \'Update\')',
|
|
283
|
+
' try {',
|
|
284
|
+
' foreach ($fx_e in @($fx_z.Entries)) {',
|
|
285
|
+
" if ($fx_e.FullName.Contains('\\')) {",
|
|
286
|
+
" $fx_ne = $fx_z.CreateEntry($fx_e.FullName.Replace('\\', '/'))",
|
|
287
|
+
' $fx_os = $fx_ne.Open()',
|
|
288
|
+
' $fx_is = $fx_e.Open()',
|
|
289
|
+
' $fx_is.CopyTo($fx_os)',
|
|
290
|
+
' $fx_is.Close()',
|
|
291
|
+
' $fx_os.Close()',
|
|
292
|
+
' $fx_e.Delete()',
|
|
293
|
+
' }',
|
|
294
|
+
' }',
|
|
295
|
+
' } finally { $fx_z.Dispose() }',
|
|
296
|
+
' if ($fx_rename) { Move-Item -LiteralPath $fx_dst -Destination $fx_arc -Force }',
|
|
297
|
+
" } catch { [Console]::Error.WriteLine('zip: fauxnix: ' + $_.Exception.Message); $script:fx_exit = 1 }",
|
|
298
|
+
'}',
|
|
299
|
+
].join('\n');
|
|
300
|
+
};
|
|
301
|
+
const unzip = (args) => {
|
|
302
|
+
const raw = args.map(wordToString);
|
|
303
|
+
let list = false;
|
|
304
|
+
let over = false;
|
|
305
|
+
let dir = null;
|
|
306
|
+
const rest = [];
|
|
307
|
+
for (let i = 0; i < raw.length; i++) {
|
|
308
|
+
const t = raw[i];
|
|
309
|
+
if (t === '-d' && i + 1 < args.length) {
|
|
310
|
+
dir = args[i + 1];
|
|
311
|
+
i++;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (t.startsWith('--directory=')) {
|
|
315
|
+
const dv = [{ kind: 'Text', text: t.slice('--directory='.length) }];
|
|
316
|
+
dir = dv;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (t === '--directory' && i + 1 < args.length) {
|
|
320
|
+
dir = args[i + 1];
|
|
321
|
+
i++;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (t.startsWith('-') && t.length > 1 && !/^-\d/.test(t)) {
|
|
325
|
+
if (t.includes('l'))
|
|
326
|
+
list = true;
|
|
327
|
+
if (t.includes('o'))
|
|
328
|
+
over = true;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
rest.push(args[i]);
|
|
332
|
+
}
|
|
333
|
+
if (rest.length === 0) {
|
|
334
|
+
return "[Console]::Error.WriteLine('unzip: fauxnix: missing archive operand (usage: unzip ARCHIVE [-d DIR] [-o] [-l])'); $script:fx_exit = 1";
|
|
335
|
+
}
|
|
336
|
+
const arc = operandExpr(rest[0]);
|
|
337
|
+
const dirExpr = dir ? operandExpr(dir) : "'.'";
|
|
338
|
+
return [
|
|
339
|
+
'Add-Type -AssemblyName System.IO.Compression.FileSystem',
|
|
340
|
+
'$fx_arc = ' + arc,
|
|
341
|
+
'if (-not (Test-Path -LiteralPath $fx_arc -PathType Leaf)) {',
|
|
342
|
+
// GNU message shape: "unzip: cannot find x, x.zip or x.Z." (two spaces)
|
|
343
|
+
" [Console]::Error.WriteLine('unzip: cannot find ' + $fx_arc + ', ' + $fx_arc + '.zip or ' + $fx_arc + '.Z.')",
|
|
344
|
+
' $script:fx_exit = 1',
|
|
345
|
+
'}',
|
|
346
|
+
'else {',
|
|
347
|
+
list
|
|
348
|
+
? [
|
|
349
|
+
' $fx_z = [IO.Compression.ZipFile]::OpenRead((Resolve-Path -LiteralPath $fx_arc).ProviderPath)',
|
|
350
|
+
' try {',
|
|
351
|
+
" 'Archive: ' + $fx_arc",
|
|
352
|
+
" ' Length Date Time Name'",
|
|
353
|
+
" '--------- ---------- ----- ----'",
|
|
354
|
+
' $fx_tot = 0',
|
|
355
|
+
' $fx_cnt = 0',
|
|
356
|
+
' foreach ($fx_e in $fx_z.Entries) {',
|
|
357
|
+
" if (-not $fx_e.FullName.EndsWith('/')) { $fx_tot = $fx_tot + $fx_e.Length; $fx_cnt = $fx_cnt + 1 }",
|
|
358
|
+
" ('{0,9} {1} {2}' -f $fx_e.Length, $fx_e.LastWriteTime.ToString('MM-dd-yy HH:mm'), $fx_e.FullName.Replace('\\', '/'))",
|
|
359
|
+
' }',
|
|
360
|
+
" '--------- ---------- ----- ----'",
|
|
361
|
+
" $fx_pl = 's'",
|
|
362
|
+
" if ($fx_cnt -eq 1) { $fx_pl = '' }",
|
|
363
|
+
" ((([string]$fx_tot).PadLeft(9)) + ' ' + $fx_cnt + ' file' + $fx_pl)",
|
|
364
|
+
' } finally { $fx_z.Dispose() }',
|
|
365
|
+
].join('\n')
|
|
366
|
+
: [
|
|
367
|
+
' $fx_dir = ' + dirExpr,
|
|
368
|
+
' try {',
|
|
369
|
+
' Expand-Archive -LiteralPath $fx_arc -DestinationPath $fx_dir -Force:' + (over ? '$true' : '$false') + ' -ErrorAction Stop',
|
|
370
|
+
" } catch { [Console]::Error.WriteLine('unzip: fauxnix: ' + $_.Exception.Message + ' (use -o to overwrite)'); $script:fx_exit = 1 }",
|
|
371
|
+
].join('\n'),
|
|
372
|
+
'}',
|
|
373
|
+
].join('\n');
|
|
374
|
+
};
|
|
375
|
+
/* ------------------------------------------------------------------ */
|
|
376
|
+
/* exports */
|
|
377
|
+
/* ------------------------------------------------------------------ */
|
|
378
|
+
export const handlers = {
|
|
379
|
+
tar,
|
|
380
|
+
gzip,
|
|
381
|
+
gunzip,
|
|
382
|
+
zcat,
|
|
383
|
+
zip,
|
|
384
|
+
unzip,
|
|
385
|
+
};
|