This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
H4X0RZ's profile picture

[WIP] Helium - My (semi-)developer-friendly OS

Started by H4X0RZ, 14 October 2016 - 08:48 PM
H4X0RZ #1
Posted 14 October 2016 - 10:48 PM
First of all, I'm not here to announce the next "BEST OS EVERYONE SHOULD USE".
I'm trying to get input on the code I wrote the last few days weeks.

For everyone who want's to install it before reading anything:
Either download the last release

pastebin run VuBNx3va -u TheFreakLord -r HeliumRW /
or download the repo directly (ONLY DO THIS IF YOU KNOW WHAT YOU ARE DOING)

pastebin run 2KQvJ8fn
The code is here.

Okay, now… Here's everything noteworthy, I guess:
  • this uses a TLCO so don't try to terminate the shell you boot into. It won't happen what you might expect
  • there are NO users for now. I maybe add them later on though
  • It contains a lot of libraries, some are self-made, others third-party. Maybe you someday need one of them :P/>
  • most/some of the code is based on the OOP paradigm. That means that the code contains a class system
  • the shell is "okay". It works, but many crucial commands are still missing.
  • the file system is sandboxed and stored in the RAM. Although, after the shell exists, parts of it will be mirrored into a folder
  • you can easily write your own implementation of a filesystem (by extending BaseFS) and make everything run inside of that of course
  • it uses i18n so you could add custom languages etc.
  • the filesystem is OOP, although you can turn the filesystem into a "legacy" one (so it behaves like the original fs API) by calling "legacy = fs:makeLegacy()". You will loose some functionality though
  • I added something I like to call "Filesystem Middleware". It basically allows you to perform actions on the stuff written and read to/from files before the user get's the stuff. I implemented a basic example middleware: it encodes/decodes every file into Base64
  • everything inside /bin/sym will be "imported" into /bin in the emulated filesystem so the shell can access it
  • probably more stuff I forgot to mention
Every kind of critique is appreciated. Thanks for your time.

~H40RZ
Edited on 04 November 2016 - 08:48 PM
Lupus590 #2
Posted 15 October 2016 - 12:14 AM
Sounds cool, particularly the file system changes. I'd be interested in having that as a separate API.
Piorjade #3
Posted 15 October 2016 - 12:54 AM
Ayy here comes dat squad

It looks very nice ! :)/>
But I was kinda bored so I'll apologize for that:


--[[
					   Fixed /bin/shell.lua
]]
term.clear()
term.setCursorPos(1,1)

local new = false

local conf = Config:new("shell", function() new = true end)
local currentDir = "/"
local path = "/bin"

local commands = {}
local running = true

_G.shell = {}

function shell.getPath()
  return path
end

function shell.setPath(pat)
  path = pat
end

function shell.getCurrentDir()
  return currentDir
end

function shell.setCurrentDir(newDir)
  currentDir = newDir
end

local function split(str,pat)
  local fields = {}
  local pat = pat or "%s"
  str:gsub("[^"..pat.."]+", function(c) fields[#fields+1] = c end)
  return fields
end

if(new) then
  conf:set("useColors",true)
  conf:set("colors.arrow", colors.orange)
  conf:set("colors.user", colors.green)
  conf:set("colors.text", colors.white)
  conf:set("colors.error", colors.red)
  conf:set("colors.hostname.color", colors.lime)
  conf:set("colors.hostname.divider.char", "@")
  conf:set("colors.hostname.divider.color", colors.lightGray)
  conf:save()
end

if(not fs.exists("lang")) then fs.makeDir("lang") end
if(not fs.exists("lang/en.lua")) then
  local handle = fs.open("lang/en.lua","w")
  handle.write("return ")
  handle.write[[
  { en = {
	shell = {
		welcome = "Welcome to %{name}",
		error   = {
		  command_not_found = "Command not found!"
		}
	  }
	}
  }
  ]]
  handle.close()
end

i18n.loadFile "lang/en.lua"

term.setTextColor(colors.gray)
print(i18n("shell.welcome", {name = os.getFullName()}))

local function checkFile(name)

  local cur = fs.combine(currentDir,name)
  if(fs.exists(cur) and (not fs.isDir(cur))) then
	return cur
  end

  local entries = split(path,";")
  for _,folder in pairs(entries) do
	local list = fs.list(folder)
	for k,v in pairs(list) do
	  if(v == name) then
		return fs.combine(folder,v)
	  end
	end
  end
  return nil
end


local function shell()
  while running do
	term.setTextColor(conf:get "colors.user")
	term.write "root"
	term.setTextColor(conf:get "colors.hostname.divider.color")
	term.write(conf:get "colors.hostname.divider.char")
	term.setTextColor(conf:get "colors.hostname.color")
	term.write("host")
	term.setTextColor(conf:get "colors.arrow")
	term.write((currentDir == "/" and "" or " "..currentDir))
	term.write ">"
	term.setTextColor(conf:get "colors.text")
	local content = read()

	if #content > 0 then
		term.setTextColor(colors.lightGray)

		local command = split(content," \t")

		local file = checkFile(command[1])

		if(not file) then
		  term.setTextColor(conf:get "colors.error")
		  print(i18n "shell.error.command_not_found" )
		else
			local handle = fs.open(file,"r")
			local cont = handle.readAll()
			handle.close()
			local ok, err = load(cont,"",nil,getfenv())
			ok(select(2,unpack(command)))
		end
	end

	
  end
end

parallel.waitForAny(shell)


Dayum I was so bored of downloading Black Desert that I fixed your loop crashing out if you enter a non-existend command (or nothing) :/
Edited on 14 October 2016 - 10:55 PM
minebuild02 #4
Posted 15 October 2016 - 04:53 PM
Well let me try it…
AlexDevs #5
Posted 15 October 2016 - 05:24 PM
Type something, press enter: *CRASH*
This "OS" is a joke
Piorjade #6
Posted 15 October 2016 - 07:23 PM
Type something, press enter: *CRASH*
This "OS" is a joke

I posted a fix for that.
H4X0RZ #7
Posted 15 October 2016 - 07:24 PM
Type something, press enter: *CRASH*
This "OS" is a joke

Technically it doesn't "crash" IIRC. I just added a useless return statement (and were too bored to remove it) which "breaks" the loop, making the shell stop.

But thanks for your critique. I really appreciate it :)/>
H4X0RZ #8
Posted 21 October 2016 - 12:26 AM
#UPDATE:

After some time I got some new stuff for you to check out!
  • removed the useless return statement from shell.lua, which made it exit if you entered something "wrong"
  • the shell should be completely sandboxed now (so it can't access anything at all outside it's env). Before it was able to access the /config folder by (ab-)using the Config class
  • I moved the sandboxing from being some "proprietary code chunk" to a proper class so now I could sandbox a sandbox inside a sandbox etc.
  • some internal changes
It's still the same command to install it. Note that it DOESN'T have an update function built-in right now. Maybe I'll add that later.


Also, I got some big-ish plans:
  • fs middleware should be able to modify filenames
  • implement metadata with fs middleware
  • make the shell useful
  • maybe add the ability to "mount" one filesystem inside another one
  • a framework for commandline programs
Edited on 20 October 2016 - 10:31 PM
H4X0RZ #9
Posted 04 November 2016 - 06:44 PM
#UPDATE:

I'm back again with another update!
  • I wrote a simple transpiler for classes! Now it's easier to define classes, and it looks much better (IMO) (the transpiler also comes with an "import" feature, but none of my libs are usable with it for now)
  • cd (and, more importantly, the rest of the shell) now support relative paths
  • added "rm" command
  • there is a new class called "Container", which basically wraps around a RamFS and let's you add files to it. Then you can save that container and later load it again. I might intend to use this to distribute classes more easily
  • I added the "Resource" class. The class itself can't do "anything", but if you extend it and add some stuff to self.lookup it will magically add getters and setters for these values. I intend to make a generic class<->file storage this way by serializing the content of a "Resource" into JSON and back
  • config.lua now detects if you create an instance inside of a sandbox and acts accordingly (=> create the config in "persistent/config" instead of "config")
Small update for the update:
The transpiler now allows you to import/require other files "easily", as long as the place they import from is "made for it". You can do stuff like this now:

import {RamFS,WrapperFS} from lib.fs.types
@class someClass {

  initialize() |
	local wrapper = WrapperFS:new(fs)
	self._ram = RamFS:new(wrapper)
  |

  doSomething() |
	self._ram:export "somewhereElse"
  |

}

in order to make a directory supported by this, either make the init.lua inside the folder return a table where the keys are the names you use to import, and the value is the (already loaded/required) stuff that should be imported, or you use my ImportProxy like this:

local ImportProxy = require "lib.import_proxy"
local proxy = ImportProxy:new()
proxy:add("BaseFS", "lib.fs.types.base")
proxy:add("RamFS", "lib.fs.types.ram")
proxy:add("WrapperFS", "lib.fs.types.wrapper")
return proxy:convert()
I encourage you to use the ImportProxy because it uses metatables to only require what's requested. This "bypasses" problems where some code requires something else while both are in the same "parent" directory making it require itself over and over again.
Edited on 04 November 2016 - 08:26 PM
EveryOS #10
Posted 05 November 2016 - 12:21 AM
Piorjade said:
I was so bored
You've found the force that drives us all…
I honestly wouldn't be browsing the forums if I wasn't bored
H4X0RZ #11
Posted 05 November 2016 - 07:31 PM
Here's a small teaser showing you a few new features I added:

"lip" means "list processes" and that's exactly what it does. "proc" allows you to manage your processes (enable/disable them and start new ones. Probably going to allow killing them too)

#EDIT:

WOOT! 1200th post!
Edited on 05 November 2016 - 07:26 PM
Piorjade #12
Posted 05 November 2016 - 09:54 PM
Here's a small teaser showing you a few new features I added:

"lip" means "list processes" and that's exactly what it does. "proc" allows you to manage your processes (enable/disable them and start new ones. Probably going to allow killing them too)

#EDIT:

WOOT! 1200th post!

Interesting, kinda similar to the proc manager I had in the commandline (except that I had 2 layers)…. Well I'm supposed to be rewriting the security in my OS buuuuut I'm currently starting with Unity3D heheh

Anyways, looks awesome and congrats kek
H4X0RZ #13
Posted 09 November 2016 - 07:35 PM
Here's another small update: I decided to write a documentation now. It's almost completely empty right now, but the "Code Style" part already contains some stuff (which should probably go somewhere else. I suck at documenting)

If anyone is interested in helping with the docs feel free to fork the gh-pages branch!
Edited on 09 November 2016 - 06:35 PM
Cross_Sans #14
Posted 08 January 2017 - 08:34 AM
Looks great. Good job !
Edited on 12 January 2017 - 05:56 PM