@ecmaos/coreutils 0.1.5 → 0.2.1
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +45 -0
- package/dist/commands/basename.d.ts +4 -0
- package/dist/commands/basename.d.ts.map +1 -0
- package/dist/commands/basename.js +78 -0
- package/dist/commands/basename.js.map +1 -0
- package/dist/commands/cal.d.ts +4 -0
- package/dist/commands/cal.d.ts.map +1 -0
- package/dist/commands/cal.js +105 -0
- package/dist/commands/cal.js.map +1 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +33 -25
- package/dist/commands/cat.js.map +1 -1
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +38 -10
- package/dist/commands/cd.js.map +1 -1
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +31 -9
- package/dist/commands/chmod.js.map +1 -1
- package/dist/commands/comm.d.ts +4 -0
- package/dist/commands/comm.d.ts.map +1 -0
- package/dist/commands/comm.js +162 -0
- package/dist/commands/comm.js.map +1 -0
- package/dist/commands/cp.d.ts.map +1 -1
- package/dist/commands/cp.js +61 -12
- package/dist/commands/cp.js.map +1 -1
- package/dist/commands/cut.d.ts +4 -0
- package/dist/commands/cut.d.ts.map +1 -0
- package/dist/commands/cut.js +208 -0
- package/dist/commands/cut.js.map +1 -0
- package/dist/commands/date.d.ts +4 -0
- package/dist/commands/date.d.ts.map +1 -0
- package/dist/commands/date.js +100 -0
- package/dist/commands/date.js.map +1 -0
- package/dist/commands/diff.d.ts +4 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +194 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/dirname.d.ts +4 -0
- package/dist/commands/dirname.d.ts.map +1 -0
- package/dist/commands/dirname.js +50 -0
- package/dist/commands/dirname.js.map +1 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +49 -10
- package/dist/commands/echo.js.map +1 -1
- package/dist/commands/false.d.ts +4 -0
- package/dist/commands/false.d.ts.map +1 -0
- package/dist/commands/false.js +27 -0
- package/dist/commands/false.js.map +1 -0
- package/dist/commands/find.d.ts +4 -0
- package/dist/commands/find.d.ts.map +1 -0
- package/dist/commands/find.js +181 -0
- package/dist/commands/find.js.map +1 -0
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +45 -10
- package/dist/commands/grep.js.map +1 -1
- package/dist/commands/head.d.ts.map +1 -1
- package/dist/commands/head.js +46 -9
- package/dist/commands/head.js.map +1 -1
- package/dist/commands/hex.d.ts.map +1 -1
- package/dist/commands/hex.js +16 -6
- package/dist/commands/hex.js.map +1 -1
- package/dist/commands/id.d.ts +4 -0
- package/dist/commands/id.d.ts.map +1 -0
- package/dist/commands/id.js +97 -0
- package/dist/commands/id.js.map +1 -0
- package/dist/commands/join.d.ts +4 -0
- package/dist/commands/join.d.ts.map +1 -0
- package/dist/commands/join.js +152 -0
- package/dist/commands/join.js.map +1 -0
- package/dist/commands/less.d.ts.map +1 -1
- package/dist/commands/less.js +16 -7
- package/dist/commands/less.js.map +1 -1
- package/dist/commands/ln.d.ts.map +1 -1
- package/dist/commands/ln.js +54 -12
- package/dist/commands/ln.js.map +1 -1
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +96 -91
- package/dist/commands/ls.js.map +1 -1
- package/dist/commands/mkdir.d.ts.map +1 -1
- package/dist/commands/mkdir.js +34 -9
- package/dist/commands/mkdir.js.map +1 -1
- package/dist/commands/mv.d.ts.map +1 -1
- package/dist/commands/mv.js +25 -7
- package/dist/commands/mv.js.map +1 -1
- package/dist/commands/nc.d.ts +4 -0
- package/dist/commands/nc.d.ts.map +1 -0
- package/dist/commands/nc.js +451 -0
- package/dist/commands/nc.js.map +1 -0
- package/dist/commands/nl.d.ts +4 -0
- package/dist/commands/nl.d.ts.map +1 -0
- package/dist/commands/nl.js +208 -0
- package/dist/commands/nl.js.map +1 -0
- package/dist/commands/passkey.d.ts.map +1 -1
- package/dist/commands/passkey.js +44 -18
- package/dist/commands/passkey.js.map +1 -1
- package/dist/commands/paste.d.ts +4 -0
- package/dist/commands/paste.d.ts.map +1 -0
- package/dist/commands/paste.js +161 -0
- package/dist/commands/paste.js.map +1 -0
- package/dist/commands/pwd.d.ts.map +1 -1
- package/dist/commands/pwd.js +13 -4
- package/dist/commands/pwd.js.map +1 -1
- package/dist/commands/rm.d.ts.map +1 -1
- package/dist/commands/rm.js +105 -12
- package/dist/commands/rm.js.map +1 -1
- package/dist/commands/rmdir.d.ts.map +1 -1
- package/dist/commands/rmdir.js +34 -9
- package/dist/commands/rmdir.js.map +1 -1
- package/dist/commands/sed.d.ts.map +1 -1
- package/dist/commands/sed.js +73 -28
- package/dist/commands/sed.js.map +1 -1
- package/dist/commands/seq.d.ts +4 -0
- package/dist/commands/seq.d.ts.map +1 -0
- package/dist/commands/seq.js +148 -0
- package/dist/commands/seq.js.map +1 -0
- package/dist/commands/sockets.d.ts +4 -0
- package/dist/commands/sockets.d.ts.map +1 -0
- package/dist/commands/sockets.js +239 -0
- package/dist/commands/sockets.js.map +1 -0
- package/dist/commands/sort.d.ts +4 -0
- package/dist/commands/sort.d.ts.map +1 -0
- package/dist/commands/sort.js +175 -0
- package/dist/commands/sort.js.map +1 -0
- package/dist/commands/split.d.ts +4 -0
- package/dist/commands/split.d.ts.map +1 -0
- package/dist/commands/split.js +147 -0
- package/dist/commands/split.js.map +1 -0
- package/dist/commands/stat.d.ts.map +1 -1
- package/dist/commands/stat.js +14 -6
- package/dist/commands/stat.js.map +1 -1
- package/dist/commands/tail.d.ts.map +1 -1
- package/dist/commands/tail.js +46 -9
- package/dist/commands/tail.js.map +1 -1
- package/dist/commands/tee.d.ts.map +1 -1
- package/dist/commands/tee.js +45 -10
- package/dist/commands/tee.js.map +1 -1
- package/dist/commands/test.d.ts +4 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +99 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/touch.d.ts.map +1 -1
- package/dist/commands/touch.js +34 -9
- package/dist/commands/touch.js.map +1 -1
- package/dist/commands/tr.d.ts +4 -0
- package/dist/commands/tr.d.ts.map +1 -0
- package/dist/commands/tr.js +162 -0
- package/dist/commands/tr.js.map +1 -0
- package/dist/commands/true.d.ts +4 -0
- package/dist/commands/true.d.ts.map +1 -0
- package/dist/commands/true.js +27 -0
- package/dist/commands/true.js.map +1 -0
- package/dist/commands/uniq.d.ts +4 -0
- package/dist/commands/uniq.d.ts.map +1 -0
- package/dist/commands/uniq.js +187 -0
- package/dist/commands/uniq.js.map +1 -0
- package/dist/commands/user.d.ts +4 -0
- package/dist/commands/user.d.ts.map +1 -0
- package/dist/commands/user.js +427 -0
- package/dist/commands/user.js.map +1 -0
- package/dist/commands/wc.d.ts +4 -0
- package/dist/commands/wc.d.ts.map +1 -0
- package/dist/commands/wc.js +178 -0
- package/dist/commands/wc.js.map +1 -0
- package/dist/commands/which.d.ts +4 -0
- package/dist/commands/which.d.ts.map +1 -0
- package/dist/commands/which.js +78 -0
- package/dist/commands/which.js.map +1 -0
- package/dist/commands/whoami.d.ts +4 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +28 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +67 -1
- package/dist/index.js.map +1 -1
- package/dist/shared/terminal-command.d.ts +8 -2
- package/dist/shared/terminal-command.d.ts.map +1 -1
- package/dist/shared/terminal-command.js +42 -17
- package/dist/shared/terminal-command.js.map +1 -1
- package/package.json +4 -2
- package/src/commands/basename.ts +84 -0
- package/src/commands/cal.ts +111 -0
- package/src/commands/cat.ts +37 -27
- package/src/commands/cd.ts +40 -12
- package/src/commands/chmod.ts +37 -11
- package/src/commands/comm.ts +169 -0
- package/src/commands/cp.ts +73 -15
- package/src/commands/cut.ts +214 -0
- package/src/commands/date.ts +97 -0
- package/src/commands/diff.ts +204 -0
- package/src/commands/dirname.ts +57 -0
- package/src/commands/echo.ts +51 -11
- package/src/commands/false.ts +31 -0
- package/src/commands/find.ts +184 -0
- package/src/commands/grep.ts +44 -11
- package/src/commands/head.ts +46 -10
- package/src/commands/hex.ts +19 -7
- package/src/commands/id.ts +94 -0
- package/src/commands/join.ts +162 -0
- package/src/commands/less.ts +20 -8
- package/src/commands/ln.ts +50 -13
- package/src/commands/ls.ts +110 -87
- package/src/commands/mkdir.ts +41 -12
- package/src/commands/mv.ts +31 -9
- package/src/commands/nc.ts +499 -0
- package/src/commands/nl.ts +201 -0
- package/src/commands/passkey.ts +46 -19
- package/src/commands/paste.ts +172 -0
- package/src/commands/pwd.ts +16 -4
- package/src/commands/rm.ts +118 -13
- package/src/commands/rmdir.ts +41 -12
- package/src/commands/sed.ts +64 -30
- package/src/commands/seq.ts +147 -0
- package/src/commands/sockets.ts +283 -0
- package/src/commands/sort.ts +175 -0
- package/src/commands/split.ts +154 -0
- package/src/commands/stat.ts +17 -8
- package/src/commands/tail.ts +46 -10
- package/src/commands/tee.ts +43 -11
- package/src/commands/test.ts +116 -0
- package/src/commands/touch.ts +41 -12
- package/src/commands/tr.ts +170 -0
- package/src/commands/true.ts +31 -0
- package/src/commands/uniq.ts +189 -0
- package/src/commands/user.ts +436 -0
- package/src/commands/wc.ts +181 -0
- package/src/commands/which.ts +89 -0
- package/src/commands/whoami.ts +32 -0
- package/src/index.ts +67 -1
- package/src/shared/terminal-command.ts +43 -16
package/src/commands/passkey.ts
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
|
-
import type { CommandLineOptions } from 'command-line-args'
|
|
3
2
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
4
3
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
5
4
|
import { writelnStdout, writelnStderr } from '../shared/helpers.js'
|
|
6
5
|
|
|
6
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
7
|
+
const usage = `Usage: passkey <subcommand> [options]
|
|
8
|
+
|
|
9
|
+
Subcommands:
|
|
10
|
+
register [--name <name>] Register a new passkey
|
|
11
|
+
list List all registered passkeys
|
|
12
|
+
remove --id <id> Remove a specific passkey
|
|
13
|
+
remove-all Remove all passkeys
|
|
14
|
+
|
|
15
|
+
--help display this help and exit`
|
|
16
|
+
writelnStdout(process, terminal, usage)
|
|
17
|
+
}
|
|
18
|
+
|
|
7
19
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
8
20
|
return new TerminalCommand({
|
|
9
21
|
command: 'passkey',
|
|
@@ -11,15 +23,16 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
11
23
|
kernel,
|
|
12
24
|
shell,
|
|
13
25
|
terminal,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{ name: 'name', type: String, description: 'Name/description for the passkey (used with register)' },
|
|
18
|
-
{ name: 'id', type: String, description: 'Passkey ID to remove (used with remove)' }
|
|
19
|
-
],
|
|
20
|
-
run: async (argv: CommandLineOptions, process?: Process) => {
|
|
26
|
+
run: async (pid: number, argv: string[]) => {
|
|
27
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
28
|
+
|
|
21
29
|
if (!process) return 1
|
|
22
30
|
|
|
31
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
32
|
+
printUsage(process, terminal)
|
|
33
|
+
return 0
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
const currentUid = shell.credentials.uid
|
|
24
37
|
const user = kernel.users.get(currentUid)
|
|
25
38
|
if (!user) {
|
|
@@ -27,16 +40,32 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
27
40
|
return 1
|
|
28
41
|
}
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
if (argv.length === 0) {
|
|
44
|
+
printUsage(process, terminal)
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const subcommand = argv[0]?.toLowerCase()
|
|
49
|
+
let name: string | undefined
|
|
50
|
+
let id: string | undefined
|
|
51
|
+
|
|
52
|
+
for (let i = 1; i < argv.length; i++) {
|
|
53
|
+
const arg = argv[i]
|
|
54
|
+
if (!arg) continue
|
|
55
|
+
|
|
56
|
+
if (arg === '--name' && i + 1 < argv.length) {
|
|
57
|
+
name = argv[++i]
|
|
58
|
+
} else if (arg.startsWith('--name=')) {
|
|
59
|
+
name = arg.slice(7)
|
|
60
|
+
} else if (arg === '--id' && i + 1 < argv.length) {
|
|
61
|
+
id = argv[++i]
|
|
62
|
+
} else if (arg.startsWith('--id=')) {
|
|
63
|
+
id = arg.slice(5)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
31
66
|
|
|
32
|
-
if (!subcommand || subcommand === 'help'
|
|
33
|
-
|
|
34
|
-
await writelnStdout(process, terminal, '')
|
|
35
|
-
await writelnStdout(process, terminal, 'Subcommands:')
|
|
36
|
-
await writelnStdout(process, terminal, ' register [--name <name>] Register a new passkey')
|
|
37
|
-
await writelnStdout(process, terminal, ' list List all registered passkeys')
|
|
38
|
-
await writelnStdout(process, terminal, ' remove --id <id> Remove a specific passkey')
|
|
39
|
-
await writelnStdout(process, terminal, ' remove-all Remove all passkeys')
|
|
67
|
+
if (!subcommand || subcommand === 'help') {
|
|
68
|
+
printUsage(process, terminal)
|
|
40
69
|
return 0
|
|
41
70
|
}
|
|
42
71
|
|
|
@@ -48,7 +77,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
48
77
|
return 1
|
|
49
78
|
}
|
|
50
79
|
|
|
51
|
-
const name = (argv.name as string) || undefined
|
|
52
80
|
const username = user.username
|
|
53
81
|
const userId = new TextEncoder().encode(username)
|
|
54
82
|
|
|
@@ -156,7 +184,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
156
184
|
}
|
|
157
185
|
|
|
158
186
|
case 'remove': {
|
|
159
|
-
const id = argv.id as string
|
|
160
187
|
if (!id) {
|
|
161
188
|
await writelnStderr(process, terminal, chalk.red('Error: --id is required for remove command'))
|
|
162
189
|
await writelnStdout(process, terminal, 'Usage: passkey remove --id <id>')
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
3
|
+
import { TerminalEvents } from '@ecmaos/types'
|
|
4
|
+
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
5
|
+
import { writelnStderr } from '../shared/helpers.js'
|
|
6
|
+
|
|
7
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
8
|
+
const usage = `Usage: paste [OPTION]... [FILE]...
|
|
9
|
+
Merge lines of files.
|
|
10
|
+
|
|
11
|
+
-d, --delimiters=LIST reuse characters from LIST instead of TABs
|
|
12
|
+
-s, --serial paste one file at a time instead of in parallel
|
|
13
|
+
--help display this help and exit`
|
|
14
|
+
writelnStderr(process, terminal, usage)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
18
|
+
return new TerminalCommand({
|
|
19
|
+
command: 'paste',
|
|
20
|
+
description: 'Merge lines of files',
|
|
21
|
+
kernel,
|
|
22
|
+
shell,
|
|
23
|
+
terminal,
|
|
24
|
+
run: async (pid: number, argv: string[]) => {
|
|
25
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
26
|
+
|
|
27
|
+
if (!process) return 1
|
|
28
|
+
|
|
29
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
30
|
+
printUsage(process, terminal)
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const files: string[] = []
|
|
35
|
+
let delimiters = '\t'
|
|
36
|
+
let serial = false
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < argv.length; i++) {
|
|
39
|
+
const arg = argv[i]
|
|
40
|
+
if (!arg) continue
|
|
41
|
+
|
|
42
|
+
if (arg === '--help' || arg === '-h') {
|
|
43
|
+
printUsage(process, terminal)
|
|
44
|
+
return 0
|
|
45
|
+
} else if (arg === '-d' || arg === '--delimiters') {
|
|
46
|
+
if (i + 1 < argv.length) {
|
|
47
|
+
delimiters = argv[++i] || '\t'
|
|
48
|
+
}
|
|
49
|
+
} else if (arg.startsWith('--delimiters=')) {
|
|
50
|
+
delimiters = arg.slice(13)
|
|
51
|
+
} else if (arg.startsWith('-d')) {
|
|
52
|
+
delimiters = arg.slice(2) || '\t'
|
|
53
|
+
} else if (arg === '-s' || arg === '--serial') {
|
|
54
|
+
serial = true
|
|
55
|
+
} else if (!arg.startsWith('-')) {
|
|
56
|
+
files.push(arg)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const writer = process.stdout.getWriter()
|
|
61
|
+
|
|
62
|
+
const readFileLines = async (filePath: string): Promise<string[]> => {
|
|
63
|
+
if (filePath.startsWith('/dev')) {
|
|
64
|
+
throw new Error('cannot paste device files')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let interrupted = false
|
|
68
|
+
const interruptHandler = () => { interrupted = true }
|
|
69
|
+
kernel.terminal.events.on(TerminalEvents.INTERRUPT, interruptHandler)
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const handle = await shell.context.fs.promises.open(filePath, 'r')
|
|
73
|
+
const stat = await shell.context.fs.promises.stat(filePath)
|
|
74
|
+
|
|
75
|
+
const decoder = new TextDecoder()
|
|
76
|
+
let content = ''
|
|
77
|
+
let bytesRead = 0
|
|
78
|
+
const chunkSize = 1024
|
|
79
|
+
|
|
80
|
+
while (bytesRead < stat.size) {
|
|
81
|
+
if (interrupted) break
|
|
82
|
+
const data = new Uint8Array(chunkSize)
|
|
83
|
+
const readSize = Math.min(chunkSize, stat.size - bytesRead)
|
|
84
|
+
await handle.read(data, 0, readSize, bytesRead)
|
|
85
|
+
const chunk = data.subarray(0, readSize)
|
|
86
|
+
content += decoder.decode(chunk, { stream: true })
|
|
87
|
+
bytesRead += readSize
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const lines = content.split('\n')
|
|
91
|
+
if (lines[lines.length - 1] === '') {
|
|
92
|
+
lines.pop()
|
|
93
|
+
}
|
|
94
|
+
return lines
|
|
95
|
+
} finally {
|
|
96
|
+
kernel.terminal.events.off(TerminalEvents.INTERRUPT, interruptHandler)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
if (files.length === 0) {
|
|
102
|
+
if (!process.stdin) {
|
|
103
|
+
return 0
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const reader = process.stdin.getReader()
|
|
107
|
+
const decoder = new TextDecoder()
|
|
108
|
+
let content = ''
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
while (true) {
|
|
112
|
+
const { done, value } = await reader.read()
|
|
113
|
+
if (done) break
|
|
114
|
+
if (value) {
|
|
115
|
+
content += decoder.decode(value, { stream: true })
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} finally {
|
|
119
|
+
reader.releaseLock()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const lines = content.split('\n')
|
|
123
|
+
if (lines[lines.length - 1] === '') {
|
|
124
|
+
lines.pop()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const line of lines) {
|
|
128
|
+
await writer.write(new TextEncoder().encode(line + '\n'))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return 0
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const fileLines: string[][] = []
|
|
135
|
+
|
|
136
|
+
for (const file of files) {
|
|
137
|
+
const fullPath = path.resolve(shell.cwd, file)
|
|
138
|
+
try {
|
|
139
|
+
const lines = await readFileLines(fullPath)
|
|
140
|
+
fileLines.push(lines)
|
|
141
|
+
} catch (error) {
|
|
142
|
+
await writelnStderr(process, terminal, `paste: ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
|
143
|
+
return 1
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (serial) {
|
|
148
|
+
for (const file of fileLines) {
|
|
149
|
+
for (const line of file) {
|
|
150
|
+
await writer.write(new TextEncoder().encode(line + '\n'))
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
const maxLines = Math.max(...fileLines.map(f => f.length))
|
|
155
|
+
const delimiter = delimiters[0] || '\t'
|
|
156
|
+
|
|
157
|
+
for (let i = 0; i < maxLines; i++) {
|
|
158
|
+
const parts: string[] = []
|
|
159
|
+
for (const file of fileLines) {
|
|
160
|
+
parts.push(file[i] || '')
|
|
161
|
+
}
|
|
162
|
+
await writer.write(new TextEncoder().encode(parts.join(delimiter) + '\n'))
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return 0
|
|
167
|
+
} finally {
|
|
168
|
+
writer.releaseLock()
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
}
|
package/src/commands/pwd.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
|
2
2
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
3
3
|
import { writelnStdout } from '../shared/helpers.js'
|
|
4
4
|
|
|
5
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
6
|
+
const usage = `Usage: pwd
|
|
7
|
+
Print the name of the current working directory.
|
|
8
|
+
|
|
9
|
+
--help display this help and exit`
|
|
10
|
+
writelnStdout(process, terminal, usage)
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
6
14
|
return new TerminalCommand({
|
|
7
15
|
command: 'pwd',
|
|
@@ -9,10 +17,14 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
9
17
|
kernel,
|
|
10
18
|
shell,
|
|
11
19
|
terminal,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
run: async (pid: number, argv: string[]) => {
|
|
21
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
22
|
+
|
|
23
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
24
|
+
printUsage(process, terminal)
|
|
25
|
+
return 0
|
|
26
|
+
}
|
|
27
|
+
|
|
16
28
|
await writelnStdout(process, terminal, shell.cwd)
|
|
17
29
|
return 0
|
|
18
30
|
}
|
package/src/commands/rm.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
|
-
import type {
|
|
3
|
-
import type { Kernel, Shell, Terminal } from '@ecmaos/types'
|
|
2
|
+
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
4
3
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
4
|
+
import { writelnStderr } from '../shared/helpers.js'
|
|
5
|
+
|
|
6
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
7
|
+
const usage = `Usage: rm [OPTION]... FILE...
|
|
8
|
+
Remove (unlink) the FILE(s).
|
|
9
|
+
|
|
10
|
+
--help display this help and exit`
|
|
11
|
+
writelnStderr(process, terminal, usage)
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
7
15
|
return new TerminalCommand({
|
|
@@ -10,17 +18,114 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
10
18
|
kernel,
|
|
11
19
|
shell,
|
|
12
20
|
terminal,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
run: async (pid: number, argv: string[]) => {
|
|
22
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
23
|
+
|
|
24
|
+
if (argv.length === 0) {
|
|
25
|
+
await writelnStderr(process, terminal, 'rm: missing operand')
|
|
26
|
+
await writelnStderr(process, terminal, "Try 'rm --help' for more information.")
|
|
27
|
+
return 1
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (argv[0] === '--help' || argv[0] === '-h') {
|
|
31
|
+
printUsage(process, terminal)
|
|
32
|
+
return 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const pathArray: string[] = []
|
|
36
|
+
for (const arg of argv) {
|
|
37
|
+
if (arg.startsWith('-') && arg !== '--') {
|
|
38
|
+
if (arg !== '-f' && arg !== '-r' && arg !== '-rf' && arg !== '-fr') {
|
|
39
|
+
await writelnStderr(process, terminal, `rm: invalid option -- '${arg.slice(1)}'`)
|
|
40
|
+
await writelnStderr(process, terminal, "Try 'rm --help' for more information.")
|
|
41
|
+
return 1
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
pathArray.push(arg)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (pathArray.length === 0) {
|
|
49
|
+
await writelnStderr(process, terminal, 'rm: missing operand')
|
|
50
|
+
await writelnStderr(process, terminal, "Try 'rm --help' for more information.")
|
|
51
|
+
return 1
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const expandGlob = async (pattern: string): Promise<string[]> => {
|
|
55
|
+
if (!pattern.includes('*') && !pattern.includes('?')) {
|
|
56
|
+
return [pattern]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const lastSlashIndex = pattern.lastIndexOf('/')
|
|
60
|
+
const searchDir = lastSlashIndex !== -1
|
|
61
|
+
? path.resolve(shell.cwd, pattern.substring(0, lastSlashIndex + 1))
|
|
62
|
+
: shell.cwd
|
|
63
|
+
const globPattern = lastSlashIndex !== -1
|
|
64
|
+
? pattern.substring(lastSlashIndex + 1)
|
|
65
|
+
: pattern
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const entries = await shell.context.fs.promises.readdir(searchDir)
|
|
69
|
+
const regexPattern = globPattern
|
|
70
|
+
.replace(/\./g, '\\.')
|
|
71
|
+
.replace(/\*/g, '.*')
|
|
72
|
+
.replace(/\?/g, '.')
|
|
73
|
+
const regex = new RegExp(`^${regexPattern}$`)
|
|
74
|
+
|
|
75
|
+
const matches = entries.filter(entry => regex.test(entry))
|
|
76
|
+
|
|
77
|
+
if (lastSlashIndex !== -1) {
|
|
78
|
+
const dirPart = pattern.substring(0, lastSlashIndex + 1)
|
|
79
|
+
return matches.map(match => dirPart + match)
|
|
80
|
+
}
|
|
81
|
+
return matches
|
|
82
|
+
} catch (error) {
|
|
83
|
+
return []
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const expandedPaths: string[] = []
|
|
88
|
+
for (const pattern of pathArray) {
|
|
89
|
+
const expanded = await expandGlob(pattern)
|
|
90
|
+
if (expanded.length === 0) {
|
|
91
|
+
expandedPaths.push(pattern)
|
|
92
|
+
} else {
|
|
93
|
+
expandedPaths.push(...expanded)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (expandedPaths.length === 0) {
|
|
98
|
+
await writelnStderr(process, terminal, 'rm: missing operand')
|
|
99
|
+
await writelnStderr(process, terminal, "Try 'rm --help' for more information.")
|
|
100
|
+
return 1
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let hasError = false
|
|
104
|
+
|
|
105
|
+
for (const target of expandedPaths) {
|
|
106
|
+
if (!target || typeof target !== 'string') {
|
|
107
|
+
await writelnStderr(process, terminal, `rm: ${String(target)}: No such file or directory`)
|
|
108
|
+
hasError = true
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const fullPath = path.resolve(shell.cwd, target)
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const stat = await shell.context.fs.promises.stat(fullPath)
|
|
116
|
+
if (stat.isDirectory()) {
|
|
117
|
+
await shell.context.fs.promises.rmdir(fullPath)
|
|
118
|
+
} else {
|
|
119
|
+
await shell.context.fs.promises.unlink(fullPath)
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
123
|
+
await writelnStderr(process, terminal, `rm: ${target}: ${errorMessage}`)
|
|
124
|
+
hasError = true
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return hasError ? 1 : 0
|
|
23
129
|
}
|
|
24
130
|
})
|
|
25
131
|
}
|
|
26
|
-
|
package/src/commands/rmdir.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
|
-
import type {
|
|
3
|
-
import type { Kernel, Shell, Terminal } from '@ecmaos/types'
|
|
2
|
+
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
4
3
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
4
|
+
import { writelnStdout, writelnStderr } from '../shared/helpers.js'
|
|
5
|
+
|
|
6
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
7
|
+
const usage = `Usage: rmdir [OPTION]... DIRECTORY...
|
|
8
|
+
Remove the DIRECTORY(ies), if they are empty.
|
|
9
|
+
|
|
10
|
+
--help display this help and exit`
|
|
11
|
+
writelnStdout(process, terminal, usage)
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
7
15
|
return new TerminalCommand({
|
|
@@ -10,16 +18,37 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
10
18
|
kernel,
|
|
11
19
|
shell,
|
|
12
20
|
terminal,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
run: async (pid: number, argv: string[]) => {
|
|
22
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
23
|
+
|
|
24
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
25
|
+
printUsage(process, terminal)
|
|
26
|
+
return 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (argv.length === 0) {
|
|
30
|
+
await writelnStderr(process, terminal, 'rmdir: missing operand')
|
|
31
|
+
await writelnStderr(process, terminal, "Try 'rmdir --help' for more information.")
|
|
32
|
+
return 1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let hasError = false
|
|
36
|
+
|
|
37
|
+
for (const target of argv) {
|
|
38
|
+
if (!target || target.startsWith('-')) continue
|
|
39
|
+
|
|
40
|
+
const fullPath = target ? path.resolve(shell.cwd, target) : shell.cwd
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
await shell.context.fs.promises.rm(fullPath, { recursive: true, force: true })
|
|
44
|
+
} catch (error) {
|
|
45
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
46
|
+
await writelnStderr(process, terminal, `rmdir: ${target}: ${errorMessage}`)
|
|
47
|
+
hasError = true
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return hasError ? 1 : 0
|
|
22
52
|
}
|
|
23
53
|
})
|
|
24
54
|
}
|
|
25
|
-
|
package/src/commands/sed.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
|
-
import type { CommandLineOptions } from 'command-line-args'
|
|
3
2
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
4
3
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
5
4
|
import { writelnStderr } from '../shared/helpers.js'
|
|
@@ -16,6 +15,19 @@ interface SedCommand {
|
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
17
|
|
|
18
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
19
|
+
const usage = `Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...
|
|
20
|
+
|
|
21
|
+
Stream editor for filtering and transforming text.
|
|
22
|
+
|
|
23
|
+
-e, --expression=script add the script to the commands to be executed
|
|
24
|
+
-f, --file=script-file add the contents of script-file to the commands
|
|
25
|
+
-i[SUFFIX], --in-place[=SUFFIX] edit files in place (makes backup if SUFFIX supplied)
|
|
26
|
+
-q, --quiet suppress normal output
|
|
27
|
+
--help display this help and exit`
|
|
28
|
+
writelnStderr(process, terminal, usage)
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
function parseSedExpression(expr: string): SedCommand | null {
|
|
20
32
|
expr = expr.trim()
|
|
21
33
|
|
|
@@ -203,21 +215,21 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
203
215
|
kernel,
|
|
204
216
|
shell,
|
|
205
217
|
terminal,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
{ name: 'file', type: String, alias: 'f', description: 'Add the contents of script-file to the commands to be executed' },
|
|
210
|
-
{ name: 'inplace', type: String, alias: 'i', description: 'Edit files in place (makes backup if extension supplied)' },
|
|
211
|
-
{ name: 'quiet', type: Boolean, alias: 'q', description: 'Suppress normal output' },
|
|
212
|
-
{ name: 'path', type: String, typeLabel: '{underline path}', defaultOption: true, multiple: true, description: 'Expression or input file(s)' }
|
|
213
|
-
],
|
|
214
|
-
run: async (argv: CommandLineOptions, process?: Process) => {
|
|
218
|
+
run: async (pid: number, argv: string[]) => {
|
|
219
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
220
|
+
|
|
215
221
|
if (!process) return 1
|
|
216
222
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
223
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
224
|
+
printUsage(process, terminal)
|
|
225
|
+
return 0
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
let expressions: string[] = []
|
|
229
|
+
const files: string[] = []
|
|
230
|
+
let scriptFile: string | undefined
|
|
231
|
+
let inplace: string | undefined
|
|
232
|
+
let quiet = false
|
|
221
233
|
|
|
222
234
|
const isSedExpression = (arg: string): boolean => {
|
|
223
235
|
if (!arg) return false
|
|
@@ -232,34 +244,56 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
232
244
|
)
|
|
233
245
|
}
|
|
234
246
|
|
|
235
|
-
|
|
236
|
-
|
|
247
|
+
for (let i = 0; i < argv.length; i++) {
|
|
248
|
+
const arg = argv[i]
|
|
249
|
+
if (!arg) continue
|
|
237
250
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
} else {
|
|
242
|
-
|
|
251
|
+
if (arg === '--help' || arg === '-h') {
|
|
252
|
+
printUsage(process, terminal)
|
|
253
|
+
return 0
|
|
254
|
+
} else if (arg === '-e' || arg === '--expression') {
|
|
255
|
+
if (i + 1 < argv.length) {
|
|
256
|
+
expressions.push(argv[++i] || '')
|
|
257
|
+
}
|
|
258
|
+
} else if (arg.startsWith('--expression=')) {
|
|
259
|
+
expressions.push(arg.slice(13))
|
|
260
|
+
} else if (arg.startsWith('-e')) {
|
|
261
|
+
expressions.push(arg.slice(2))
|
|
262
|
+
} else if (arg === '-f' || arg === '--file') {
|
|
263
|
+
if (i + 1 < argv.length) {
|
|
264
|
+
scriptFile = argv[++i]
|
|
265
|
+
}
|
|
266
|
+
} else if (arg.startsWith('--file=')) {
|
|
267
|
+
scriptFile = arg.slice(7)
|
|
268
|
+
} else if (arg.startsWith('-f')) {
|
|
269
|
+
scriptFile = arg.slice(2)
|
|
270
|
+
} else if (arg === '-i' || arg === '--in-place') {
|
|
271
|
+
inplace = ''
|
|
272
|
+
} else if (arg.startsWith('--in-place=')) {
|
|
273
|
+
inplace = arg.slice(12)
|
|
274
|
+
} else if (arg.startsWith('-i')) {
|
|
275
|
+
inplace = arg.slice(2) || ''
|
|
276
|
+
} else if (arg === '-q' || arg === '--quiet') {
|
|
277
|
+
quiet = true
|
|
278
|
+
} else if (isSedExpression(arg)) {
|
|
279
|
+
expressions.push(arg)
|
|
280
|
+
} else if (!arg.startsWith('-')) {
|
|
281
|
+
files.push(arg)
|
|
243
282
|
}
|
|
244
283
|
}
|
|
245
284
|
|
|
246
|
-
if (
|
|
247
|
-
expressions = [...expressions, ...potentialExpressions]
|
|
248
|
-
files = potentialFiles
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (expressions.length === 0 && !argv.file) {
|
|
285
|
+
if (expressions.length === 0 && !scriptFile) {
|
|
252
286
|
await writelnStderr(process, terminal, 'sed: No expression provided')
|
|
253
287
|
return 1
|
|
254
288
|
}
|
|
255
289
|
|
|
256
290
|
const commands: SedCommand[] = []
|
|
257
291
|
|
|
258
|
-
if (
|
|
259
|
-
const scriptPath = path.resolve(shell.cwd,
|
|
292
|
+
if (scriptFile) {
|
|
293
|
+
const scriptPath = path.resolve(shell.cwd, scriptFile)
|
|
260
294
|
const exists = await shell.context.fs.promises.exists(scriptPath)
|
|
261
295
|
if (!exists) {
|
|
262
|
-
await writelnStderr(process, terminal, `sed: ${
|
|
296
|
+
await writelnStderr(process, terminal, `sed: ${scriptFile}: No such file or directory`)
|
|
263
297
|
return 1
|
|
264
298
|
}
|
|
265
299
|
|