From 41d0fe2ebe7926dcd239c68ec5f14becb019f569 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 29 Dec 2025 19:08:20 -0300 Subject: [PATCH] add all the other programs --- cp.yarn | 1 + echo.yarn | 1 + env.yarn | 1 + info.yarn | 1 + loader.yarn | 1 + ls.yarn | 1 + miss.yarn | 1 + mkdir.yarn | 1 + mrrp.yarn | 1 + mv.yarn | 1 + programs.yarn | 1 + repo.json | 18 +++++++++++++++++- rm.yarn | 1 + shutdown.yarn | 1 + slog.yarn | 1 + touch.yarn | 1 + yarn.yarn | 1 + 17 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 cp.yarn create mode 100644 echo.yarn create mode 100644 env.yarn create mode 100644 info.yarn create mode 100644 loader.yarn create mode 100644 ls.yarn create mode 100644 miss.yarn create mode 100644 mkdir.yarn create mode 100644 mrrp.yarn create mode 100644 mv.yarn create mode 100644 programs.yarn create mode 100644 rm.yarn create mode 100644 shutdown.yarn create mode 100644 slog.yarn create mode 100644 touch.yarn create mode 100644 yarn.yarn diff --git a/cp.yarn b/cp.yarn new file mode 100644 index 0000000..799eac1 --- /dev/null +++ b/cp.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"clear","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"clear.js":"%B/clear.js"}},"content":"{\"cp.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"if (!args[0] && !args[1]) {\\n itty.display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n itty.fs.copyNode(args[0], args[1])\\n} catch (e) {\\n itty.display.print(e[1] || \\\"Error copying node\\\", 0x9000)\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/echo.yarn b/echo.yarn new file mode 100644 index 0000000..2e380c0 --- /dev/null +++ b/echo.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"echo","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"echo.js":"%B/echo.js"}},"content":"{\"echo.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"let echo = pipe\\nif (!pipe)\\n echo = args.join(\\\" \\\")\\n\\ndisplay.print(echo, itty.baseStyle, false)\\nquit()\"}}"} \ No newline at end of file diff --git a/env.yarn b/env.yarn new file mode 100644 index 0000000..3b6723b --- /dev/null +++ b/env.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"env","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"env.js":"%B/env.js"}},"content":"{\"env.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"const subcommand = args[0]\\nconst env = args[1]\\n\\nconst envtype = typeof itty.env[env]\\nlet value\\n\\nlet listing = false\\nlet listIndex = 0\\n\\nswitch(subcommand) {\\n case \\\"get\\\":\\n if (!env) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n display.print(JSON.stringify(itty.env[env]), getEnvStyle(envtype))\\n quit()\\n break\\n case \\\"set\\\":\\n if (!env) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n await parseValue()\\n if (itty.env[env] && typeof itty.env[env] !== typeof value) {\\n let r = await io.read(\\\"Mismatch between env type and provided value type. Continue? [y/N]: \\\")\\n if (r.length === 0 || r[0].toLowerCase() !== \\\"y\\\") {\\n display.print(\\\"Aborting...\\\")\\n quit()\\n }\\n }\\n itty.env[env] = value\\n quit()\\n break\\n case \\\"list\\\":\\n if (Object.keys(itty.env).length < itty.height - 4) {\\n for (let e in itty.env) {\\n display.buffer(e, getEnvStyle(typeof itty.env[e]))\\n display.buffer(\\\" = \\\", 0xe000)\\n display.print(JSON.stringify(itty.env[e]).replaceAll(\\\"%\\\", \\\"%%\\\"))\\n }\\n display.render()\\n quit()\\n } else {\\n program.enterFullscreen()\\n listing = true\\n onInput(\\\"\\\", {})\\n }\\n}\\n\\nfunction onInput(k) {\\n if (!listing)\\n return\\n\\n switch (k) {\\n case \\\"%^\\\":\\n listIndex = Math.max(listIndex - 1, 0)\\n break\\n case \\\"%v\\\":\\n listIndex = Math.min(listIndex + 1, Object.keys(itty.env).length - 1)\\n break\\n case \\\"%e\\\":\\n display.clear()\\n quit()\\n }\\n\\n display.clear()\\n for (let i = listIndex; i < itty.height - 1 + listIndex; i++) {\\n const e = Object.keys(itty.env)[i]\\n if (!e)\\n break\\n\\n display.buffer(e, getEnvStyle(typeof itty.env[e]))\\n display.buffer(\\\" = \\\", 0xe000)\\n display.buffer(JSON.stringify(itty.env[e]) + \\\"%n\\\")\\n }\\n itty.cursorY = itty.height - 1\\n display.write(\\\"Arrow Up/Down to scroll, Escape to quit\\\")\\n}\\n\\nasync function parseValue() {\\n let v = await io.read([[\\\"Value: \\\", 0xe000]])\\n v = v.replaceAll(\\\"%%\\\", \\\"%\\\")\\n\\n try {\\n v = JSON.parse(v)\\n } catch (e) {\\n try {\\n v = JSON.parse('\\\"' + v + '\\\"')\\n } catch (e) {\\n throw [1, \\\"Cannot parse value\\\"]\\n }\\n }\\n value = v\\n}\\n \\nfunction getEnvStyle(type) {\\n let style = 0xf000\\n switch(type) {\\n case \\\"object\\\":\\n style = 0x4000\\n break\\n case \\\"string\\\":\\n style = 0x6000\\n break\\n case \\\"number\\\":\\n style = 0x5000\\n break\\n case \\\"boolean\\\":\\n style = 0xa000\\n break\\n }\\n return style\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/info.yarn b/info.yarn new file mode 100644 index 0000000..ff7672b --- /dev/null +++ b/info.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"info","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"info.js":"%B/info.js"}},"content":"{\"info.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"display.buffer(`Itty version: v${itty.version[0]}.${itty.version[1]}${itty.version[2] ? \\\".\\\" + itty.version[2] : \\\"\\\"} ${itty.version[3] || \\\"\\\"}%nRoot FS: ${itty.disk.version}`, 0x4000)\\ndisplay.buffer(\\\"%n%nDisplay dimensions: \\\", 0x7000)\\ndisplay.buffer(itty.width + \\\"x\\\" + itty.height + \\\"%n%n\\\", 0x6000)\\nfor (let i=0; i < 8; i++) {\\n display.buffer(\\\" \\\", 0x0100 * i)\\n}\\nitty.cursorY++\\nitty.cursorX = 0\\nfor (let i=8; i < 16; i++) {\\n display.buffer(\\\" \\\", 0x0100 * i)\\n}\\n\\ndisplay.buffer(\\\"%n%nITTY: Incredibly Tiny Terminal, Yay!\\\", 0x4041)\\ndisplay.buffer(\\\" by \\\", 0x7041)\\ndisplay.buffer(\\\"Magdalunaa\\\", 0x6051)\\nstyle.setAttribute(1, {_link: \\\"https://codeberg.org/Magdalunaa/itty\\\", style: \\\"cursor: pointer; text-decoration-color: var(--itty-c-4)\\\"})\\ndisplay.render()\\nquit()\"}}"} \ No newline at end of file diff --git a/loader.yarn b/loader.yarn new file mode 100644 index 0000000..3c64172 --- /dev/null +++ b/loader.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"loader","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"loader.js":"%B/loader.js"}},"content":"{\"loader.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"if (!args[1]) {\\n display.print(\\\"Not enough arguments\\\")\\n quit()\\n}\\n\\nconst command = args[0]\\nargs.splice(0, 1)\\nconst mountpoint = args.join(\\\" \\\")\\nconst node = fs.getNode(mountpoint)\\nlet content\\n\\nswitch(command) {\\n case \\\"save\\\":\\n case \\\"download\\\":\\n content = fs.export(node)\\n\\n const blob = new Blob([content], { type: \\\"text/plain\\\" })\\n const url = URL.createObjectURL(blob)\\n\\n const a = document.createElement(\\\"a\\\")\\n a.href = url\\n a.download = node.name\\n a.style.display = \\\"none\\\"\\n\\n document.body.appendChild(a)\\n a.click()\\n document.body.removeChild(a)\\n\\n URL.revokeObjectURL(url)\\n break\\n case \\\"load\\\":\\n case \\\"upload\\\":\\n content = await getFile()\\n await fs.import(content.text, mountpoint)\\n display.print(\\\"Disk loaded successfully\\\", 0x3000)\\n}\\n\\nquit()\\n\\nfunction getFile() {\\n return new Promise(resolve => {\\n const input = document.createElement(\\\"input\\\")\\n input.type = \\\"file\\\"\\n input.accept = \\\"*/*\\\"\\n input.style.display = \\\"none\\\"\\n\\n document.body.appendChild(input)\\n\\n input.onchange = async () => {\\n const file = input.files[0]\\n const text = await file.text();\\n document.body.removeChild(input)\\n resolve({ file, text })\\n }\\n\\n input.click()\\n })\\n}\"}}"} \ No newline at end of file diff --git a/ls.yarn b/ls.yarn new file mode 100644 index 0000000..ad63a72 --- /dev/null +++ b/ls.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"ls","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"ls.js":"%B/ls.js"}},"content":"{\"ls.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"// get flags\\nlet flags = {}\\nlet dir = \\\".\\\"\\nfor (let i=0; i < args.length; i++) {\\n if (args[i][0] === \\\"-\\\") {\\n if (args[i].indexOf(\\\"l\\\") !== -1)\\n flags.l = true\\n if (args[i].indexOf(\\\"a\\\") !== -1)\\n flags.a = true\\n } else {\\n dir = args[i]\\n break\\n }\\n}\\n\\n// get node\\nlet node\\ntry {\\n node = fs.getNode(dir)\\n} catch (e) {\\n display.print(\\\"Not a directory\\\")\\n quit()\\n}\\n\\nif (!node || node.mode !== \\\"d\\\") {\\n display.print(\\\"Not a directory\\\")\\n quit()\\n}\\n\\nlet empty = true\\nfor (let n of fs.listDir(node)) {\\n if (n.name[0] === \\\".\\\" && !flags.a)\\n continue\\n\\n empty = false\\n\\n let style = 0x7000\\n if (n.mode === \\\"d\\\")\\n style = 0x5000\\n\\n if (n.protected)\\n style += 0x0020\\n\\n if (itty.cursorX + n.name.length >= itty.width) {\\n itty.cursorX = 0\\n itty.cursorY++\\n }\\n\\n while (itty.cursorY >= itty.height)\\n display.lift()\\n\\n if (!flags.l) {\\n display.buffer(n.name + \\\" \\\", style)\\n } else {\\n display.buffer(n.mode + \\\" \\\", 0xc000)\\n display.buffer(n.name, style)\\n display.buffer(n.protected ? \\\" (protected)%n\\\" : \\\"%n\\\", 0xf000)\\n }\\n}\\n\\nif (empty)\\n display.print(\\\"Directory is empty\\\", 0xf000)\\n\\ndisplay.render()\\nquit()\"}}"} \ No newline at end of file diff --git a/miss.yarn b/miss.yarn new file mode 100644 index 0000000..399012f --- /dev/null +++ b/miss.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"miss","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"miss.js":"%B/miss.js"}},"content":"{\"miss.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\" // check if there is a config file\\nlet config = {}\\n\\nif (fs.getNode(fs.resolve(itty.env.dir_conf || \\\"/conf/\\\") + \\\"miss.conf\\\")) {\\n try {\\n const configFile = io.open(fs.resolve(itty.env.dir_conf || \\\"/conf/\\\") + \\\"miss.conf\\\")\\n config = configFile.read()\\n config = JSON.parse(config)\\n } catch (e) {\\n io.error([1, \\\"Error parsing config\\\"])\\n config = {}\\n }\\n}\\n\\nlet history = []\\nlet historyIndex = 0\\n\\nfunction onInput(key) {\\n switch (key) {\\n case \\\"%^\\\":\\n historyIndex = Math.max(historyIndex - 1, 0)\\n if (history[historyIndex]) {\\n program.read.input = history[historyIndex]\\n program.read.cursor = program.read.input.length\\n }\\n break\\n case \\\"%v\\\":\\n historyIndex = Math.min(historyIndex + 1, history.length)\\n if (history[historyIndex]) {\\n program.read.input = history[historyIndex]\\n program.read.cursor = program.read.input.length\\n } else if (historyIndex === history.length) {\\n program.read.input = \\\"\\\"\\n program.read.cursor = 0\\n }\\n break\\n }\\n}\\n\\nlet running = false\\n// this runs on every new line\\nasync function line() {\\n // promt! %D gets replaced by the active dir\\n const prompt = config.prompt || [[\\\"%D\\\", 0xc000], [\\\" > \\\", 0xd000]]\\n\\n for (let p of prompt)\\n p[0] = p[0].replace(/%D/g, program.currentDir)\\n\\n // parse arguments\\n let command = await io.read(prompt)\\n if (command !== \\\"\\\" && command !== history[history.length - 1]) {\\n history.push(command)\\n historyIndex = history.length\\n }\\n command = command.replace(/%%/g, \\\"%\\\")\\n let args = command.match(/\\\"([^\\\"%]*(%.[^\\\"%]*)*)\\\"|'([^'%]*(%.[^'%]*)*)'|\\\\S+/g)\\n\\n if (args) {\\n for (let i=0; i < args.length; i++) {\\n args[i] = args[i].replace(/^'(.*)'$|^\\\"(.*)\\\"$/, \\\"$1$2\\\")\\n args[i] = args[i].replace(/%(['\\\"])/g, \\\"$1\\\")\\n }\\n\\n // split into multiple commands\\n const commands = []\\n let redir\\n let c = []\\n for (let a of args) {\\n if (a !== \\\"|\\\") {\\n c.push(a)\\n } else {\\n commands.push(c.slice())\\n c = []\\n }\\n }\\n commands.push(c)\\n\\n let redirIndex = commands[commands.length - 1].indexOf(\\\">\\\")\\n if (redirIndex !== -1) {\\n redir = commands[commands.length - 1][redirIndex + 1]\\n commands[commands.length - 1] = commands[commands.length - 1].slice(0, redirIndex)\\n }\\n\\n running = true\\n let output = \\\"\\\"\\n for (let c = 0; c < commands.length; c++) {\\n const hidden = (c < commands.length - 1 || redir ? true : false)\\n output = await run(commands[c], output, hidden)\\n }\\n \\n if (redir) {\\n let file\\n try {\\n file = io.open(redir, \\\"a\\\")\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000) \\n }\\n if (file) {\\n file.write(output)\\n try {\\n file.writeOut()\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000) \\n }\\n }\\n }\\n\\n running = false\\n \\n if (itty.cursorX !== 0)\\n itty.cursorY++\\n\\n line()\\n } else {\\n line()\\n }\\n}\\n\\n// attempt to run autorun functions!\\nif (program.uid === 0) {\\n for (let a of [\\\"/autorun\\\", \\\"/autorun.js\\\", \\\"/.autorun\\\", \\\"/.autorun.js\\\"]) {\\n try {\\n exec.runProgram(a, [], \\\"\\\", false)\\n } catch {}\\n }\\n}\\n\\nline()\\n\\nasync function run(arg, input, hidden) {\\n const program = arg[0]\\n if (arg.length > 1)\\n arg.splice(0, 1)\\n else\\n arg = []\\n let file = null\\n\\n switch (program) {\\n // built in \\\"programs\\\"\\n case \\\"cd\\\":\\n try {\\n fs.changeDir(arg[0] || itty.env.home)\\n } catch (e) {\\n display.print(\\\"Not a directory\\\")\\n }\\n break\\n case \\\"exit\\\":\\n quit()\\n display.print(\\\"Cannot quit init process\\\", 0xf000)\\n return\\n break\\n // otherwise, call\\n default:\\n let output\\n try {\\n output = await exec.runProgram(program, arg, input, hidden)\\n } catch (e) {\\n if (e[0] !== 0) {\\n if (e[0] === -1 && e[1] === \\\"Cannot find program file\\\") {\\n display.print(`${program}: command not found.`, 0x2000)\\n return\\n } else\\n display.print(\\\"Error running program\\\", 0x9000)\\n }\\n }\\n\\n return output\\n }\\n}\\n\\nfunction onReturn() {\\n if (running)\\n return\\n\\n program.visible = true\\n program.focused = true\\n historyIndex = history.length\\n if (itty.cursorX !== 0)\\n itty.cursorY++\\n onError()\\n}\\n\\nfunction onError() {\\n if (program.visible) {\\n for (let e of io.getErrors()) {\\n display.write(`[${e[0]}] `, 0x9010)\\n display.print(e[1] || \\\"\\\")\\n }\\n }\\n}\\n\\nfunction onResize() {\\n if (program.focused) {\\n program.read.line = 0\\n display.clear()\\n }\\n}\"}}"} \ No newline at end of file diff --git a/mkdir.yarn b/mkdir.yarn new file mode 100644 index 0000000..c140c66 --- /dev/null +++ b/mkdir.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"mkdir","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"mkdir.js":"%B/mkdir.js"}},"content":"{\"mkdir.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.makeDir(args[0])\\n} catch (e) {\\n display.print(\\\"Error creating directory\\\", 0x1000)\\n}\\nquit()\"}}"} \ No newline at end of file diff --git a/mrrp.yarn b/mrrp.yarn new file mode 100644 index 0000000..ba05e21 --- /dev/null +++ b/mrrp.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"mrrp","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"mrrp.js":"%B/mrrp.js"}},"content":"{\"mrrp.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"let yarnball\\nlet repoNode = fs.getNode(\\\"/itty/repos.json\\\")\\nlet repoList = JSON.parse(repoNode.content)\\nlet pkgList\\nlet updateList = []\\nlet world = io.flines(fs.getNode(\\\"/itty/world\\\")).filter(Boolean)\\nlet unwantedPkgs\\n\\n// we use some env vars, parse them\\nconst dirs = {\\n bin: fs.resolve(itty.env.dir_bin).slice(0, -1) || \\\"/itty/bin\\\",\\n docs: fs.resolve(itty.env.dir_docs).slice(0, -1) || \\\"/itty/docs\\\",\\n conf: fs.resolve(itty.env.dir_conf) + \\\"examples\\\" || \\\"/conf/examples\\\"\\n}\\n\\n// cache repo indexes, so querying and updating is faster\\nlet repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\nif (!repoCache) {\\n fs.makeDir(\\\"/.tmp/mrrp/\\\")\\n fs.makeNode(\\\"/.tmp/mrrp/repocache\\\", \\\"f\\\")\\n await refreshCache()\\n} else {\\n repoCache = JSON.parse(repoCache.content) \\n}\\n\\n// refresh the repo cache!\\nasync function refreshCache() {\\n repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\n const list = {}\\n for (let r of Object.entries(repoList)) {\\n let rj\\n try {\\n rj = await fetch(r[1].url + \\\"repo.json\\\")\\n rj = await rj.json()\\n } catch {\\n display.print(\\\"Cannot fetch repository info for \\\" + r[0], 0x9000)\\n continue\\n }\\n rj.url = r[1].url\\n list[r[0]] = rj\\n }\\n repoCache.content = JSON.stringify(list)\\n repoCache = list\\n}\\n\\n// confirmation as to whether to do things\\nasync function ask(message) {\\n const res = await io.read([[message + \\\" [y/N]: \\\"]])\\n\\n if (res.toLowerCase() !== \\\"y\\\" && res.toLowerCase() !== \\\"yes\\\") {\\n display.print(\\\"Aborting...\\\", 0x9000)\\n return false\\n }\\n\\n display.print(\\\"Proceeding...\\\", 0x3000)\\n return true\\n}\\n\\n// install a program\\nasync function install(yarnball, reponame, interactive = true, wanted) {\\n wanted = wanted || world.includes(yarnball.metadata.name)\\n\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n // substitute %B, %C and %D in paths with env vars\\n for (let path of Object.keys(yarnball.metadata.paths)) {\\n let p = yarnball.metadata.paths[path]\\n p = p.replaceAll(\\\"%B\\\", dirs.bin)\\n p = p.replaceAll(\\\"%D\\\", dirs.docs)\\n p = p.replaceAll(\\\"%C\\\", dirs.conf)\\n yarnball.metadata.paths[path] = p\\n }\\n\\n // ask the user!\\n if (interactive) {\\n const v = yarnball.metadata.version\\n display.print(\\\"Installing \\\" + yarnball.metadata.name + \\\" version \\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" from \\\" + reponame, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path in yarnball.metadata.paths) {\\n display.print(yarnball.metadata.paths[path], 0x2000)\\n }\\n if (yarnball.metadata.dependencies.length)\\n display.print(\\\"The following dependencies also need to be installed:\\\", 0x6000)\\n for (let d of yarnball.metadata.dependencies) {\\n if (!list[d])\\n display.print(d, 0x6000)\\n }\\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // uninstall if already installed\\n if (list[yarnball.metadata.name])\\n await uninstall(yarnball.metadata.name, false)\\n\\n // unspool the yarnball\\n fs.removeNode(\\\"/.tmp/mrrp/x\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/x\\\")\\n const node = fs.getNode(\\\"/.tmp/mrrp/x\\\")\\n let content\\n\\n try {\\n content = JSON.parse(yarnball.content)\\n } catch {\\n io.error([5, \\\"Cannot parse yarnball\\\"])\\n }\\n\\n for (let file of Object.keys(content)) {\\n if (node.content[file])\\n continue\\n const obj = content[file]\\n node.content[file] = obj\\n }\\n fs.refreshPathAttributes(node)\\n\\n // move files accordingly\\n for (let path of Object.entries(yarnball.metadata.paths)) {\\n const paths = fs.splitPath(path[1])\\n makeDir(paths[0])\\n const parent = fs.getNode(paths[0])\\n parent.content[paths[1]] = fs.getNode(\\\"/.tmp/mrrp/x/\\\" + path[0])\\n fs.refreshPathAttributes(parent)\\n }\\n\\n // keep track!\\n list[yarnball.metadata.name] = {\\n name: yarnball.metadata.name,\\n repo: reponame,\\n version: yarnball.metadata.version,\\n paths: [],\\n dependencies: yarnball.metadata.dependencies\\n }\\n\\n for (let path of Object.entries(yarnball.metadata.paths))\\n list[yarnball.metadata.name].paths.push(path[1])\\n\\n listNode.content = JSON.stringify(list)\\n\\n if (wanted && !world.includes[yarnball.metadata.name])\\n world.push(yarnball.metadata.name)\\n\\n if (interactive)\\n display.print(\\\"Package \\\" + yarnball.metadata.name + \\\" installed\\\", 0x6000)\\n\\n // handle dependencies but after install because we only keep one package in the cache hehe this is awful i'm sorry\\n for (let d of yarnball.metadata.dependencies) {\\n if (list[d])\\n continue\\n const reponame = await fetchPkg(d)\\n if (!reponame) {\\n display.print(\\\"Could not install dependency \\\" + d, 0x9000)\\n continue\\n }\\n const yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, interactive)\\n }\\n}\\n\\nasync function uninstall(package, interactive = true) {\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n const pkginfo = list[package]\\n if (!pkginfo) {\\n if (interactive)\\n display.print(\\\"Package is not installed\\\", 0x6000)\\n return\\n }\\n \\n // ask the user!\\n if (interactive) {\\n display.print(\\\"Removing \\\" + pkginfo.name, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path of pkginfo.paths)\\n display.print(path, 0x2000)\\n \\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // actually remove\\n for (let path of pkginfo.paths) {\\n const paths = fs.splitPath(path)\\n delete fs.getNode(paths[0]).content[paths[1]]\\n }\\n\\n delete list[pkginfo.name]\\n list = JSON.stringify(list)\\n listNode.content = list\\n\\n const i = world.indexOf(pkginfo.name)\\n if (i > -1)\\n world.splice(i)\\n\\n if (interactive)\\n display.print(\\\"Package removed\\\", 0x6000)\\n}\\n\\nasync function fetchPkg(package, repo, reponame, interactive = true) {\\n let repojson\\n let rlist = []\\n if (repo) {\\n repojson = repo\\n \\n if (!repojson) {\\n display.print(\\\"Cannot find repository info for \\\" + reponame, 0x2000)\\n io.error([1, \\\"Cannot find repository info\\\"])\\n }\\n } else {\\n // look for package in repos\\n for (let r of Object.entries(repoCache)) {\\n let rj = r[1]\\n \\n if (rj.packages[package])\\n rlist.push([r[0], r[1], rj])\\n }\\n \\n switch (rlist.length) {\\n case 0:\\n display.print(\\\"Cannot find package \\\" + package, 0x9000)\\n return false\\n case 1:\\n repojson = rlist[0][2]\\n repo = rlist[0][1]\\n reponame = rlist[0][0]\\n break\\n case 2:\\n display.print(\\\"Package \\\" + package + \\\" is available in the following repositories:\\\", 0x5000)\\n for (let i=0; i < rlist.length; i++) {\\n const v = rlist[i][2].packages[package].version\\n display.buffer(\\\"[\\\" + (i + 1) + \\\"] \\\")\\n display.buffer(rlist[i][0], 0x2000)\\n display.print(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n }\\n const sel = await io.read([[\\\"Selection: \\\"]])\\n if (!sel)\\n return false\\n else {\\n repojson = rlist[sel-1][2]\\n repo = rlist[sel-1][1]\\n reponame = rlist[sel-1][0]\\n }\\n }\\n }\\n\\n // download\\n\\n let pkg\\n try {\\n pkg = await fetch(repojson.packages[package].url.replace(/^~/, repo.url))\\n pkg = await pkg.json()\\n } catch {\\n display.print(\\\"Cannot fetch package \\\" + package + \\\" from repository \\\" + reponame, 0x9000)\\n throw [2, \\\"Cannot fetch package\\\"]\\n }\\n\\n fs.removeNode(\\\"/.tmp/mrrp/dl\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/dl\\\")\\n const dl = fs.getNode(\\\"/.tmp/mrrp/dl\\\")\\n dl.content.yarn = pkg\\n fs.refreshPathAttributes(dl)\\n\\n return reponame\\n}\\n\\nfunction want(package) {\\n const index = unwantedPkgs.indexOf(package)\\n if (index > -1)\\n unwantedPkgs.splice(index)\\n\\n if (pkgList[pkg])\\n for (let dep of pkgList[package].dependencies)\\n want(dep)\\n}\\n\\nswitch (args[0]) {\\n case \\\"yarn\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n yarnball = fs.getNode(args[1])\\n } catch {\\n io.error([1, \\\"Cannot find yarnball\\\"])\\n }\\n\\n await install(yarnball, \\\"local yarnball\\\", true, true)\\n break\\n case \\\"uninstall\\\":\\n case \\\"remove\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n await uninstall(args[1])\\n break\\n case \\\"list-repos\\\":\\n for (let repo of Object.entries(repoList)) {\\n display.write(repo[0] + \\\" \\\", 0x2000)\\n display.print(repo[1].url)\\n }\\n break\\n case \\\"remove-repo\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n delete repoList[args[1]]\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Removed repo \\\" + args[1], 0x6000)\\n await refreshCache()\\n break\\n case \\\"add-repo\\\":\\n if (args.length < 3) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n \\n args[2] = args[2].replace(/([^\\\\/])$/, \\\"$1/\\\")\\n\\n // fetch repo\\n try {\\n repo = await fetch(args[2] + \\\"repo.json\\\")\\n } catch {\\n display.print(\\\"Cannot fetch repository info\\\", 0x9000)\\n quit()\\n }\\n\\n if (repoList[args[1]]) {\\n display.print(\\\"Repository \\\" + args[1] + \\\" already exists.\\\", 0x2000)\\n if (!await ask(\\\"Overwrite?\\\"))\\n quit()\\n }\\n\\n repoList[args[1]] = {\\n url: args[2]\\n }\\n\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Added repo \\\" + args[1] + \\\" with url \\\" + args[2], 0x6000)\\n await refreshCache()\\n break\\n case \\\"install\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const reponame = await fetchPkg(args[1])\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n break\\n case \\\"refresh-repos\\\":\\n await refreshCache()\\n display.print(\\\"Refreshed repository cache\\\", 0x6000)\\n break\\n case \\\"update\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n if (pkg[1].repo === \\\"local yarnball\\\" || !repoCache[pkg[1].repo])\\n continue\\n\\n const iv = pkg[1].version\\n const rv = repoCache[pkg[1].repo].packages[pkg[0]].version\\n if (rv[0] > iv[0] || rv[0] == iv[0] && rv[1] > iv[1] || rv[0] == iv[0] && rv[1] == iv[1] && rv[2] > iv[2])\\n updateList.push([pkg[0], pkg[1].repo, repoCache[pkg[1].repo]])\\n }\\n\\n if (!updateList.length) {\\n display.print(\\\"No packages need updating\\\", 0x3000)\\n quit()\\n }\\n\\n if (args[1] !== \\\"bg\\\") {\\n display.print(\\\"Packages to update:\\\", 0x6000)\\n for (let pkg of updateList)\\n display.print(pkg[0], 0x2000)\\n if (!await ask(\\\"Proceed?\\\"))\\n quit()\\n }\\n\\n for (let pkg of updateList) {\\n let f\\n try {\\n f = await fetchPkg(pkg[0], pkg[2], pkg[1], false)\\n } catch {\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Could not fetch \\\" + pkg[0] + \\\" from \\\" + pkg[1], 0x1000)\\n continue\\n }\\n if (f) {\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, pkg[1], false)\\n }\\n }\\n\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Updated packages\\\", 0x3000)\\n break\\n case \\\"list\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x4000)\\n display.buffer(\\\"(\\\")\\n display.buffer(pkg[1].repo, 0x2000)\\n display.print(\\\")\\\")\\n }\\n break\\n case \\\"query\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n \\n for (let repo of Object.entries(repoCache)) {\\n for (let pkg of Object.entries(repo[1].packages)) {\\n if (pkg[0].match(args[1])) {\\n display.buffer(\\\"[\\\")\\n display.buffer(repo[0], 0x2000)\\n display.buffer(\\\"] \\\")\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n if (pkgList[pkg[0]] && pkgList[pkg[0]].repo == repo[0]) {\\n display.buffer(\\\" (\\\")\\n const v = pkgList[pkg[0]].version\\n if (pkg[1].version[0] != v[0] || pkg[1].version[1] != v[1] || pkg[1].version[2] != v[2])\\n display.buffer(\\\"v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x5000)\\n display.buffer(\\\"installed\\\", 0x5000)\\n display.buffer(\\\")\\\")\\n }\\n display.write(\\\"%n\\\")\\n }\\n }\\n }\\n break\\n case \\\"prune\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n unwantedPkgs = Object.keys(pkgList)\\n\\n for (let pkg of world)\\n want(pkg)\\n\\n if (unwantedPkgs.length) {\\n display.print(\\\"The following packages will be removed:\\\", 0x6000)\\n for (let pkg of unwantedPkgs)\\n display.print(pkg, 0x2000)\\n\\n if (await ask(\\\"Proceed?\\\"))\\n for (let pkg of unwantedPkgs)\\n uninstall(pkg, false)\\n } else\\n display.print(\\\"No unwanted packages to remove\\\", 0x3000)\\n break\\n case \\\"batch\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const batchList = io.flines(fs.getNode(args[1])).filter(Boolean)\\n if (!batchList) {\\n display.print(\\\"Cannot find file\\\", 0x9000)\\n quit()\\n }\\n for (let pkg of batchList) {\\n const reponame = await fetchPkg(pkg)\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n }\\n}\\n\\nconst worldfile = io.open(\\\"/itty/world\\\", \\\"w\\\")\\nfor (let w of world)\\n worldfile.print(w)\\nworldfile.writeOut()\\n\\nquit()\\n\\n// fs functions but copies that don't care about protectedness\\nfunction makeNode(path, mode) {\\n path = fs.resolve(path)\\n\\n // mode is bad?\\n if (mode != \\\"d\\\" && mode != \\\"f\\\")\\n throw [2, \\\"Invalid mode\\\"]\\n\\n // skip if it exists\\n const node = fs.getNode(path)\\n if (node && node.mode === \\\"d\\\")\\n return\\n else if (node)\\n throw [1, \\\"Node already exists\\\"]\\n\\n const paths = fs.splitPath(path)\\n const parentNode = fs.getNode(paths[0])\\n const pathEnd = paths[1]\\n\\n if (!parentNode)\\n throw [10, \\\"Parent node does not exist\\\"]\\n\\n // make the node\\n parentNode.content[pathEnd] = {\\n mode: mode,\\n protected: parentNode.protected ? true : false,\\n content: mode === \\\"d\\\" ? {} : \\\"\\\",\\n }\\n fs.setPathAttributes(parentNode.content[pathEnd], parentNode, pathEnd)\\n}\\n\\nfunction makeDir(path) {\\n path = fs.resolve(path)\\n const pathArray = path.split(\\\"/\\\").filter(Boolean)\\n let currentPath = \\\"\\\"\\n for (let part of pathArray) {\\n currentPath += \\\"/\\\" + part\\n makeNode(currentPath, \\\"d\\\")\\n }\\n}\"}}"} \ No newline at end of file diff --git a/mv.yarn b/mv.yarn new file mode 100644 index 0000000..cb4d5fd --- /dev/null +++ b/mv.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"mv","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"mv.js":"%B/mv.js"}},"content":"{\"mv.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"if (!args[0] && !args[1]) {\\n display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.moveNode(args[0], args[1])\\n} catch (e) {\\n display.print(e[1] || \\\"Error moving node\\\", 0x9000)\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/programs.yarn b/programs.yarn new file mode 100644 index 0000000..aab89d9 --- /dev/null +++ b/programs.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"programs","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"programs.js":"%B/programs.js"}},"content":"{\"programs.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"for (let path of itty.env.path) {\\n path = fs.listDir(path)\\n for (let p in path) {\\n p = path[p]\\n if (p.ext === \\\"js\\\") {\\n const name = p.name.slice(0, -3)\\n if (itty.cursorX + name.length >= itty.width) {\\n itty.cursorX = 0\\n itty.cursorY++\\n }\\n while (itty.cursorY >= itty.height)\\n display.lift()\\n display.buffer(name + \\\" \\\")\\n }\\n }\\n}\\n \\ndisplay.render()\\nquit()\"}}"} \ No newline at end of file diff --git a/repo.json b/repo.json index e2ad775..6c20155 100644 --- a/repo.json +++ b/repo.json @@ -2,6 +2,22 @@ "name": "itty", "packages": { "cat": {"url": "~cat.yarn", "version": [1]}, - "clear": {"url": "~clear.yarn", "version": [1]} + "clear": {"url": "~clear.yarn", "version": [1]}, + "cp": {"url": "~cp.yarn", "version": [1]}, + "echo": {"url": "~echo.yarn", "version": [1]}, + "env": {"url": "~env.yarn", "version": [1]}, + "info": {"url": "~info.yarn", "version": [1]}, + "loader": {"url": "~loader.yarn", "version": [1]}, + "ls": {"url": "~ls.yarn", "version": [1]}, + "miss": {"url": "~miss.yarn", "version": [1]}, + "mkdir": {"url": "~mkdir.yarn", "version": [1]}, + "mrrp": {"url": "~mrrp.yarn", "version": [1]}, + "mv": {"url": "~mv.yarn", "version": [1]}, + "programs": {"url": "~programs.yarn", "version": [1]}, + "rm": {"url": "~rm.yarn", "version": [1]}, + "shutdown": {"url": "~shutdown.yarn", "version": [1]}, + "slog": {"url": "~slog.yarn", "version": [1]}, + "touch": {"url": "~touch.yarn", "version": [1]}, + "yarn": {"url": "~yarn.yarn", "version": [1]} } } diff --git a/rm.yarn b/rm.yarn new file mode 100644 index 0000000..acd130c --- /dev/null +++ b/rm.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"rm","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"rm.js":"%B/rm.js"}},"content":"{\"rm.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.removeNode(args[0])\\n} catch (e) {\\n display.print(e[1] || \\\"Error removing node\\\", 0x9000)\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/shutdown.yarn b/shutdown.yarn new file mode 100644 index 0000000..1ac0f97 --- /dev/null +++ b/shutdown.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"shutdown","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"shutdown.js":"%B/shutdown.js"}},"content":"{\"shutdown.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"exec.shutdown(); quit()\"}}"} \ No newline at end of file diff --git a/slog.yarn b/slog.yarn new file mode 100644 index 0000000..5d8b483 --- /dev/null +++ b/slog.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"slog","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"slog.js":"%B/slog.js"}},"content":"{\"slog.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"// ensure log file exists\\n\\nlet logfile\\n\\ntry {\\n logfile = io.open(\\\"/itty/slog\\\", \\\"a\\\")\\n} catch {}\\n\\nif (!logfile) {\\n fs.getNode(\\\"/itty/\\\").content[\\\"slog\\\"] = {\\n protected: false,\\n mode: \\\"f\\\",\\n content: \\\"\\\",\\n parent: fs.getNode(\\\"/itty/\\\"),\\n name: \\\"slog\\\",\\n js: \\\"\\\",\\n metadata: {}\\n }\\n logfile = io.open(\\\"/itty/slog\\\", \\\"a\\\")\\n}\\n\\nconst message = JSON.parse(pipe)\\n\\nif (message[1][0] !== 0)\\n console.log(\\\"ERROR\\\", message[1])\\n\\nlogfile.print(`(${message[0].id}/${message[0].uid}) ${message[0].name}: [${message[1][0] || \\\"INFO\\\"}] ${message[1][1]}`)\\nlogfile.writeOut()\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/touch.yarn b/touch.yarn new file mode 100644 index 0000000..56f0275 --- /dev/null +++ b/touch.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"touch","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"touch.js":"%B/touch.js"}},"content":"{\"touch.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.makeNode(args[0], \\\"f\\\")\\n} catch (e) {\\n switch (e[0]) {\\n case 1:\\n display.print(\\\"File already exists\\\", 0xf000)\\n break\\n case 3:\\n display.print(\\\"Parent directory is protected\\\", 0x9000)\\n break\\n case 10:\\n display.print(\\\"Parent directory does not exist\\\", 0x9000)\\n break\\n default:\\n display.print(\\\"Error creating file\\\", 0x9000)\\n }\\n}\\nquit()\"}}"} \ No newline at end of file diff --git a/yarn.yarn b/yarn.yarn new file mode 100644 index 0000000..1f2162d --- /dev/null +++ b/yarn.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"yarn","author":"Luna Magdalena :3","version":[1],"dependencies":[],"runner":[],"paths":{"yarn.js":"%B/yarn.js"}},"content":"{\"yarn.js\":{\"protected\":true,\"metadata\":{},\"mode\":\"f\",\"content\":\"function spool(nodes) {\\n const yarnball = {}\\n\\n for (let node of nodes) {\\n let n\\n try {\\n n = fs.getNode(node)\\n } catch {\\n continue\\n }\\n\\n yarnball[n.name] = n\\n }\\n\\n return JSON.stringify(yarnball, (key, value) => {if (key === \\\"parent\\\" || key === \\\"name\\\" || key === \\\"ext\\\") {return undefined}; return value})\\n}\\n\\nfunction unspool(yarnball, path) {\\n fs.makeDir(path)\\n const node = fs.getNode(path)\\n if (node.protected)\\n io.error([3, \\\"Destination is protected\\\"])\\n\\n try {\\n yarnball = JSON.parse(yarnball)\\n } catch {\\n io.error([5, \\\"Cannot parse yarnball\\\"])\\n }\\n\\n for (let file of Object.keys(yarnball)) {\\n if (node.content[file])\\n continue\\n const obj = yarnball[file]\\n node.content[file] = obj\\n }\\n fs.refreshPathAttributes(node)\\n}\\n\\nlet yarnfile\\nlet meta\\nlet jsonfile\\n\\nswitch (args[0]) {\\n case \\\"spool\\\":\\n yarnfile = io.open(args[1], \\\"w\\\")\\n yarnfile.write(spool(args.slice(2)))\\n yarnfile.writeOut()\\n break\\n case \\\"unspool\\\":\\n yarnfile = io.open(args[1], \\\"r\\\")\\n unspool(yarnfile.read(), args[2])\\n break\\n case \\\"get-metadata\\\":\\n yarnfile = io.open(args[1], \\\"r\\\")\\n if (args[2])\\n display.print(JSON.stringify(fs.getMetadata(yarnfile, args[2])))\\n else\\n for (let m of Object.keys(yarnfile.metadata))\\n display.print(m + \\\": \\\" + JSON.stringify(fs.getMetadata(yarnfile, m)))\\n break\\n case \\\"set-metadata\\\":\\n yarnfile = fs.getNode(args[1])\\n meta = await io.read()\\n fs.setMetadata(yarnfile, args[2], meta)\\n break\\n case \\\"metadata-from-json\\\":\\n try {\\n yarnfile = fs.getNode(args[1])\\n } catch {\\n io.error([1, \\\"Cannot find yarnball\\\"])\\n }\\n if (yarnfile.protected)\\n io.error([2, \\\"Yarnball is protected\\\"])\\n\\n try {\\n jsonfile = fs.getNode(args[2])\\n } catch {\\n io.error([1, \\\"Cannot find JSON file\\\"])\\n }\\n\\n try {\\n meta = JSON.parse(jsonfile.content)\\n } catch {\\n io.error([6, \\\"Cannot parse JSON\\\"])\\n }\\n\\n yarnfile.metadata = meta\\n break\\n}\\nquit()\"}}"} \ No newline at end of file