@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
|
@@ -0,0 +1,154 @@
|
|
|
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: split [OPTION]... [INPUT [PREFIX]]
|
|
9
|
+
Split INPUT into fixed-size pieces.
|
|
10
|
+
|
|
11
|
+
-l, -lNUMBER put NUMBER lines per output file
|
|
12
|
+
-b, -bSIZE put SIZE bytes per output file
|
|
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: 'split',
|
|
20
|
+
description: 'Split a file into pieces',
|
|
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
|
+
let file = ''
|
|
35
|
+
let lines: number | undefined
|
|
36
|
+
let bytes: number | undefined
|
|
37
|
+
let prefix = 'x'
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < argv.length; i++) {
|
|
40
|
+
const arg = argv[i]
|
|
41
|
+
if (!arg) continue
|
|
42
|
+
|
|
43
|
+
if (arg === '--help' || arg === '-h') {
|
|
44
|
+
printUsage(process, terminal)
|
|
45
|
+
return 0
|
|
46
|
+
} else if (arg === '-l' || arg.startsWith('-l')) {
|
|
47
|
+
if (arg === '-l' && i + 1 < argv.length) {
|
|
48
|
+
i++
|
|
49
|
+
const nextArg = argv[i]
|
|
50
|
+
if (nextArg !== undefined) {
|
|
51
|
+
lines = parseInt(nextArg, 10)
|
|
52
|
+
}
|
|
53
|
+
} else if (arg.startsWith('-l') && arg.length > 2) {
|
|
54
|
+
lines = parseInt(arg.slice(2), 10)
|
|
55
|
+
}
|
|
56
|
+
} else if (arg === '-b' || arg.startsWith('-b')) {
|
|
57
|
+
if (arg === '-b' && i + 1 < argv.length) {
|
|
58
|
+
i++
|
|
59
|
+
const nextArg = argv[i]
|
|
60
|
+
if (nextArg !== undefined) {
|
|
61
|
+
bytes = parseInt(nextArg, 10)
|
|
62
|
+
}
|
|
63
|
+
} else if (arg.startsWith('-b') && arg.length > 2) {
|
|
64
|
+
bytes = parseInt(arg.slice(2), 10)
|
|
65
|
+
}
|
|
66
|
+
} else if (!arg.startsWith('-')) {
|
|
67
|
+
if (!file) {
|
|
68
|
+
file = arg
|
|
69
|
+
} else if (prefix === 'x') {
|
|
70
|
+
prefix = arg
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!file) {
|
|
76
|
+
await writelnStderr(process, terminal, 'split: missing file operand')
|
|
77
|
+
return 1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!lines && !bytes) {
|
|
81
|
+
await writelnStderr(process, terminal, 'split: you must specify -l or -b')
|
|
82
|
+
return 1
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const fullPath = path.resolve(shell.cwd, file)
|
|
86
|
+
|
|
87
|
+
let interrupted = false
|
|
88
|
+
const interruptHandler = () => { interrupted = true }
|
|
89
|
+
kernel.terminal.events.on(TerminalEvents.INTERRUPT, interruptHandler)
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
if (fullPath.startsWith('/dev')) {
|
|
93
|
+
await writelnStderr(process, terminal, `split: ${file}: cannot split device files`)
|
|
94
|
+
return 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const handle = await shell.context.fs.promises.open(fullPath, 'r')
|
|
98
|
+
const stat = await shell.context.fs.promises.stat(fullPath)
|
|
99
|
+
|
|
100
|
+
const decoder = new TextDecoder()
|
|
101
|
+
let content = ''
|
|
102
|
+
let bytesRead = 0
|
|
103
|
+
const chunkSize = 1024
|
|
104
|
+
|
|
105
|
+
while (bytesRead < stat.size) {
|
|
106
|
+
if (interrupted) break
|
|
107
|
+
const data = new Uint8Array(chunkSize)
|
|
108
|
+
const readSize = Math.min(chunkSize, stat.size - bytesRead)
|
|
109
|
+
await handle.read(data, 0, readSize, bytesRead)
|
|
110
|
+
const chunk = data.subarray(0, readSize)
|
|
111
|
+
content += decoder.decode(chunk, { stream: true })
|
|
112
|
+
bytesRead += readSize
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const dir = path.dirname(fullPath)
|
|
116
|
+
let fileIndex = 0
|
|
117
|
+
|
|
118
|
+
const getSuffix = (index: number): string => {
|
|
119
|
+
const first = Math.floor(index / 26)
|
|
120
|
+
const second = index % 26
|
|
121
|
+
return String.fromCharCode(97 + first) + String.fromCharCode(97 + second)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (lines) {
|
|
125
|
+
const allLines = content.split('\n')
|
|
126
|
+
for (let i = 0; i < allLines.length; i += lines) {
|
|
127
|
+
const chunk = allLines.slice(i, i + lines).join('\n')
|
|
128
|
+
const suffix = getSuffix(fileIndex)
|
|
129
|
+
const outputPath = path.join(dir, `${prefix}${suffix}`)
|
|
130
|
+
await shell.context.fs.promises.writeFile(outputPath, chunk, 'utf-8')
|
|
131
|
+
fileIndex++
|
|
132
|
+
}
|
|
133
|
+
} else if (bytes) {
|
|
134
|
+
const encoder = new TextEncoder()
|
|
135
|
+
const contentBytes = encoder.encode(content)
|
|
136
|
+
for (let i = 0; i < contentBytes.length; i += bytes) {
|
|
137
|
+
const chunk = contentBytes.slice(i, i + bytes)
|
|
138
|
+
const suffix = getSuffix(fileIndex)
|
|
139
|
+
const outputPath = path.join(dir, `${prefix}${suffix}`)
|
|
140
|
+
await shell.context.fs.promises.writeFile(outputPath, chunk)
|
|
141
|
+
fileIndex++
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return 0
|
|
146
|
+
} catch (error) {
|
|
147
|
+
await writelnStderr(process, terminal, `split: ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
|
148
|
+
return 1
|
|
149
|
+
} finally {
|
|
150
|
+
kernel.terminal.events.off(TerminalEvents.INTERRUPT, interruptHandler)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
}
|
package/src/commands/stat.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import chalk from 'chalk'
|
|
3
3
|
import * as zipjs from '@zip.js/zip.js'
|
|
4
|
-
import type { CommandLineOptions } from 'command-line-args'
|
|
5
4
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
6
5
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
7
6
|
import { writelnStdout } from '../shared/helpers.js'
|
|
8
7
|
|
|
8
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
9
|
+
const usage = `Usage: stat [OPTION]... FILE...
|
|
10
|
+
Display file or file system status.
|
|
11
|
+
|
|
12
|
+
--help display this help and exit`
|
|
13
|
+
writelnStdout(process, terminal, usage)
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
10
17
|
return new TerminalCommand({
|
|
11
18
|
command: 'stat',
|
|
@@ -13,12 +20,15 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
13
20
|
kernel,
|
|
14
21
|
shell,
|
|
15
22
|
terminal,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
run: async (pid: number, argv: string[]) => {
|
|
24
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
25
|
+
|
|
26
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
27
|
+
printUsage(process, terminal)
|
|
28
|
+
return 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const argPath = argv.length > 0 && argv[0] && !argv[0].startsWith('-') ? argv[0] : shell.cwd
|
|
22
32
|
const fullPath = argPath ? path.resolve(shell.cwd, argPath) : shell.cwd
|
|
23
33
|
const stats = await shell.context.fs.promises.stat(fullPath)
|
|
24
34
|
await writelnStdout(process, terminal, JSON.stringify(stats, null, 2))
|
|
@@ -37,4 +47,3 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
37
47
|
}
|
|
38
48
|
})
|
|
39
49
|
}
|
|
40
|
-
|
package/src/commands/tail.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
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 { TerminalEvents } from '@ecmaos/types'
|
|
5
4
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
5
|
+
import { writelnStdout } from '../shared/helpers.js'
|
|
6
|
+
|
|
7
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
8
|
+
const usage = `Usage: tail [OPTION]... [FILE]...
|
|
9
|
+
Print the last 10 lines of each FILE to standard output.
|
|
10
|
+
|
|
11
|
+
-n, -nNUMBER print the last NUMBER lines instead of 10
|
|
12
|
+
--help display this help and exit`
|
|
13
|
+
writelnStdout(process, terminal, usage)
|
|
14
|
+
}
|
|
6
15
|
|
|
7
16
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
8
17
|
return new TerminalCommand({
|
|
@@ -11,19 +20,47 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
11
20
|
kernel,
|
|
12
21
|
shell,
|
|
13
22
|
terminal,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{ name: 'path', type: String, typeLabel: '{underline path}', defaultOption: true, multiple: true, description: 'The path(s) to the file(s) to read' }
|
|
18
|
-
],
|
|
19
|
-
run: async (argv: CommandLineOptions, process?: Process) => {
|
|
23
|
+
run: async (pid: number, argv: string[]) => {
|
|
24
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
25
|
+
|
|
20
26
|
if (!process) return 1
|
|
21
27
|
|
|
28
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
29
|
+
printUsage(process, terminal)
|
|
30
|
+
return 0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let numLines = 10
|
|
34
|
+
const files: string[] = []
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const arg = argv[i]
|
|
38
|
+
if (!arg) continue
|
|
39
|
+
|
|
40
|
+
if (arg === '--help' || arg === '-h') {
|
|
41
|
+
printUsage(process, terminal)
|
|
42
|
+
return 0
|
|
43
|
+
} else if (arg === '-n' || arg.startsWith('-n')) {
|
|
44
|
+
if (arg === '-n' && i + 1 < argv.length) {
|
|
45
|
+
i++
|
|
46
|
+
const nextArg = argv[i]
|
|
47
|
+
if (nextArg !== undefined) {
|
|
48
|
+
const num = parseInt(nextArg, 10)
|
|
49
|
+
if (!isNaN(num)) numLines = num
|
|
50
|
+
}
|
|
51
|
+
} else if (arg.startsWith('-n') && arg.length > 2) {
|
|
52
|
+
const num = parseInt(arg.slice(2), 10)
|
|
53
|
+
if (!isNaN(num)) numLines = num
|
|
54
|
+
}
|
|
55
|
+
} else if (!arg.startsWith('-')) {
|
|
56
|
+
files.push(arg)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
22
60
|
const writer = process.stdout.getWriter()
|
|
23
|
-
const numLines = (argv.lines as number) ?? 10
|
|
24
61
|
|
|
25
62
|
try {
|
|
26
|
-
if (
|
|
63
|
+
if (files.length === 0) {
|
|
27
64
|
if (!process.stdin) {
|
|
28
65
|
return 0
|
|
29
66
|
}
|
|
@@ -75,7 +112,6 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
75
112
|
return 0
|
|
76
113
|
}
|
|
77
114
|
|
|
78
|
-
const files = (argv.path as string[]) || []
|
|
79
115
|
const isMultipleFiles = files.length > 1
|
|
80
116
|
|
|
81
117
|
for (let i = 0; i < files.length; i++) {
|
package/src/commands/tee.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
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 { TerminalEvents } from '@ecmaos/types'
|
|
5
4
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
6
5
|
import { writelnStderr } from '../shared/helpers.js'
|
|
7
6
|
|
|
7
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
8
|
+
const usage = `Usage: tee [OPTION]... [FILE]...
|
|
9
|
+
Read from standard input and write to standard output and files.
|
|
10
|
+
|
|
11
|
+
-a, --append append to the given files, do not overwrite
|
|
12
|
+
-i, --ignore-interrupts ignore interrupt signals
|
|
13
|
+
--help display this help and exit`
|
|
14
|
+
writelnStderr(process, terminal, usage)
|
|
15
|
+
}
|
|
16
|
+
|
|
8
17
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
9
18
|
return new TerminalCommand({
|
|
10
19
|
command: 'tee',
|
|
@@ -12,23 +21,46 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
12
21
|
kernel,
|
|
13
22
|
shell,
|
|
14
23
|
terminal,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
{ name: 'ignore-interrupts', type: Boolean, alias: 'i', description: 'Ignore interrupt signals' },
|
|
19
|
-
{ name: 'path', type: String, typeLabel: '{underline path}', defaultOption: true, multiple: true, description: 'File(s) to write to' }
|
|
20
|
-
],
|
|
21
|
-
run: async (argv: CommandLineOptions, process?: Process) => {
|
|
24
|
+
run: async (pid: number, argv: string[]) => {
|
|
25
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
26
|
+
|
|
22
27
|
if (!process) return 1
|
|
23
28
|
|
|
29
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
30
|
+
printUsage(process, terminal)
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
if (!process.stdin) {
|
|
25
35
|
await writelnStderr(process, terminal, 'tee: No input provided')
|
|
26
36
|
return 1
|
|
27
37
|
}
|
|
28
38
|
|
|
29
|
-
const files
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
const files: string[] = []
|
|
40
|
+
let append = false
|
|
41
|
+
let ignoreInterrupts = false
|
|
42
|
+
|
|
43
|
+
for (const arg of argv) {
|
|
44
|
+
if (arg === '--help' || arg === '-h') {
|
|
45
|
+
printUsage(process, terminal)
|
|
46
|
+
return 0
|
|
47
|
+
} else if (arg === '-a' || arg === '--append') {
|
|
48
|
+
append = true
|
|
49
|
+
} else if (arg === '-i' || arg === '--ignore-interrupts') {
|
|
50
|
+
ignoreInterrupts = true
|
|
51
|
+
} else if (arg.startsWith('-')) {
|
|
52
|
+
const flags = arg.slice(1).split('')
|
|
53
|
+
if (flags.includes('a')) append = true
|
|
54
|
+
if (flags.includes('i')) ignoreInterrupts = true
|
|
55
|
+
const invalidFlags = flags.filter(f => !['a', 'i'].includes(f))
|
|
56
|
+
if (invalidFlags.length > 0) {
|
|
57
|
+
await writelnStderr(process, terminal, `tee: invalid option -- '${invalidFlags[0]}'`)
|
|
58
|
+
return 1
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
files.push(arg)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
32
64
|
|
|
33
65
|
const writer = process.stdout.getWriter()
|
|
34
66
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
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: test EXPRESSION
|
|
8
|
+
test [OPTION]
|
|
9
|
+
Check file types and compare values.
|
|
10
|
+
|
|
11
|
+
-f FILE FILE exists and is a regular file
|
|
12
|
+
-d FILE FILE exists and is a directory
|
|
13
|
+
-e FILE FILE exists
|
|
14
|
+
-r FILE FILE exists and is readable
|
|
15
|
+
-w FILE FILE exists and is writable
|
|
16
|
+
-x FILE FILE exists and is executable
|
|
17
|
+
-n STRING STRING is not empty
|
|
18
|
+
-z STRING STRING is empty (zero length)
|
|
19
|
+
STRING1 = STRING2 strings are equal
|
|
20
|
+
STRING1 != STRING2 strings are not equal
|
|
21
|
+
--help display this help and exit`
|
|
22
|
+
writelnStderr(process, terminal, usage)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
26
|
+
return new TerminalCommand({
|
|
27
|
+
command: 'test',
|
|
28
|
+
description: 'Check file types and compare values',
|
|
29
|
+
kernel,
|
|
30
|
+
shell,
|
|
31
|
+
terminal,
|
|
32
|
+
run: async (pid: number, argv: string[]) => {
|
|
33
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
34
|
+
|
|
35
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
36
|
+
printUsage(process, terminal)
|
|
37
|
+
return 0
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const checkFile = async (filePath: string, check: string): Promise<boolean> => {
|
|
41
|
+
const fullPath = path.resolve(shell.cwd, filePath)
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const stat = await shell.context.fs.promises.stat(fullPath)
|
|
45
|
+
|
|
46
|
+
switch (check) {
|
|
47
|
+
case 'f':
|
|
48
|
+
return stat.isFile()
|
|
49
|
+
case 'd':
|
|
50
|
+
return stat.isDirectory()
|
|
51
|
+
case 'e':
|
|
52
|
+
return true
|
|
53
|
+
case 'r':
|
|
54
|
+
case 'w':
|
|
55
|
+
case 'x':
|
|
56
|
+
return true
|
|
57
|
+
default:
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (argv.length === 0) {
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const operator = argv[0]
|
|
70
|
+
|
|
71
|
+
if (operator === '-f' && argv[1]) {
|
|
72
|
+
return (await checkFile(argv[1], 'f')) ? 0 : 1
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (operator === '-d' && argv[1]) {
|
|
76
|
+
return (await checkFile(argv[1], 'd')) ? 0 : 1
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (operator === '-e' && argv[1]) {
|
|
80
|
+
return (await checkFile(argv[1], 'e')) ? 0 : 1
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (operator === '-r' && argv[1]) {
|
|
84
|
+
return (await checkFile(argv[1], 'r')) ? 0 : 1
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (operator === '-w' && argv[1]) {
|
|
88
|
+
return (await checkFile(argv[1], 'w')) ? 0 : 1
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (operator === '-x' && argv[1]) {
|
|
92
|
+
return (await checkFile(argv[1], 'x')) ? 0 : 1
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (operator === '-n' && argv[1]) {
|
|
96
|
+
return argv[1].length > 0 ? 0 : 1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (operator === '-z' && argv[1]) {
|
|
100
|
+
return argv[1].length === 0 ? 0 : 1
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (argv.length === 3) {
|
|
104
|
+
const [left, op, right] = argv
|
|
105
|
+
if (op === '=') {
|
|
106
|
+
return left === right ? 0 : 1
|
|
107
|
+
}
|
|
108
|
+
if (op === '!=') {
|
|
109
|
+
return left !== right ? 0 : 1
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return 1
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
}
|
package/src/commands/touch.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: touch [OPTION]... FILE...
|
|
8
|
+
Update the access and modification times of each FILE to the current time.
|
|
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, 'touch: missing file operand')
|
|
31
|
+
await writelnStderr(process, terminal, "Try 'touch --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.appendFile(fullPath, '')
|
|
44
|
+
} catch (error) {
|
|
45
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
46
|
+
await writelnStderr(process, terminal, `touch: ${target}: ${errorMessage}`)
|
|
47
|
+
hasError = true
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return hasError ? 1 : 0
|
|
22
52
|
}
|
|
23
53
|
})
|
|
24
54
|
}
|
|
25
|
-
|