Mesh OS v0.1 - Ydin ladattu. VFS kytketty.
Kokeile komentoja: ls, mkdir testi, echo "hello" >&2
mesh@local:~$ echo "Tervetuloa, $USER. Kotikansiosi on $HOME"
Tervetuloa, mesh. Kotikansiosi on /home/mesh
mesh@local:~$ env
PATH=/bin:/usr/local/bin
USER=mesh
HOME=/home/mesh
PWD=/
mesh@local:~$ export PATH=$PATH:/mnt/ghost_proxy/bin
mesh@local:~$ echo $PATH
mesh@local:~$ echo '$USER on $USER, mutta " tC$C$llC$ se laajenee: $USER "'
$USER on $USER, mutta " tC$C$llC$ se laajenee: $USER "
mesh@local:~$ echo '$USER on $USER, mutta' "tC$C$llC$ se laajenee: $USER "
$USER on $USER, mutta tC$C$llC$ se laajenee: meshB
mesh@local:~$
==
import { IORouter } from './io.js';
import { parseIntent } from './parser.js';
import { C } from './cmd.js';
export function parsePipeline(str, env) {
return str.split('|').map(x => parseIntent(x, env)).filter(x => x !==
null);
}
export class ShellSession {
constructor(sessionId) {
this.id = sessionId;
this.io = new IORouter();
this.history = [];
// UUSI: UNIX-ympC$ristC6muuttujat oletuksina!
this.env = {
PATH: "/bin:/usr/local/bin",
USER: "mesh",
HOME: "/home/mesh",
PWD: "/"
};
this.io.open(0);
this.io.open(1, (data) => this._defaultOut(data));
this.io.open(2, (data) => this._defaultErr(data));
}
_defaultOut(msg) { console.log(msg); }
_defaultErr(msg) { console.error(msg); }
async executeRaw(inputString) {
// VC$litetC$C$n env parserille laajennusta varten
const pipeline = parsePipeline(inputString, this.env);
if (!pipeline.length) return;
let previousOutput = null;
for (let i = 0; i < pipeline.length; i++) {
const intent = pipeline[i];
this.history.push(intent);
for (const r of intent.redirects) this.io.tee(r.source, r.target);
let cmdKey = intent.cmd;
if (typeof C[cmdKey] === 'string') cmdKey = C[cmdKey];
const cmdFn = C[cmdKey];
if (cmdFn) {
let currentOutput = [];
const isLast = (i === pipeline.length - 1);
const w = (d) => { (intent.fileOut || !isLast) ?
currentOutput.push(d) : this.io.write(1, d); };
const e = (d) => this.io.write(2, d);
try {
// LisC$tC$C$n kuudes parametri: env
await cmdFn(intent.argv, w, e, window.fs, previousOutput,
this.env);
let outStr = currentOutput.join('
');
if (intent.fileOut) {
const f = intent.fileOut.file;
let old = intent.fileOut.append ? await
window.fs.readFile(f).catch(()=>"") : "";
await window.fs.writeFile(f, old ? old + "
" + outStr : outStr);
previousOutput = "";
} else previousOutput = outStr;
} catch (err) {
e("Fatal: " + err.message); break;
}
} else {
// UNIX PATH -lokigikka (placeholder tulevia VFS-skriptejC$
varten)
const paths = this.env.PATH.split(':');
this.io.write(2, `bash: ${intent.cmd}: command not found
(searched in ${paths.length} directories)`);
break;
}
for (const r of intent.redirects) this.io.untee(r.source,
r.target);
}
}
}
==
/ a: argv, w: stdout, e: stderr, v: vfs, i: stdin, n: env
export const C = {
echo: (a,w,e,v,i,n) => w(a.join(' ')),
cat: async(a,w,e,v,i,n) => a.length ? w(await v.readFile(a[0]).catch(x=>e(x
.message))) : w(i||""),
ls: async(a,w,e,v,i,n) => w((await v.readdir(a[0]||'/')).join('
')),
mkdir: async(a,w,e,v,i,n) => v.mkdir(a[0]).then(()=>w('ok')).catch(x=>e(x.m
essage)),
rm: async(a,w,e,v,i,n) => v.unlink(a[0]).then(()=>w('ok')).catch(x=>e(x.mes
sage)),
grep: (a,w,e,v,i,n) => {
if (!i) return;
const result = i.split('
').filter(line => line.includes(a[0]));
if (result.length) w(result.join('
'));
},
tee: async(a,w,e,v,i="",n) => { w(i); for(let f of a) await v.writeFile(f,
i); },
// UUDET: YmpC$ristC6muuttujien hallinta
env: (a,w,e,v,i,n) => w(Object.entries(n).map(([k,val])=>`${k}=${val}`).joi
n('
')),
export: (a,w,e,v,i,n) => {
if (!a.length) return w(Object.entries(n).map(([k,val])=>`declare -x
${k}="${val}"`).join('
'));
let [k, ...val] = a[0].split('=');
if(k) n[k] = val.join('=');
},
ll: "ls", md: "mkdir"
};