Eco = Object clone do: { -- all packages OK for loading -- name -> [package] packages = [] -- versions loaded by @use: -- name -> package loaded = [] } Eco Package = Object clone Eco Package new := Eco Package clone do: { version = 0 . 1 dependencies = [] include = [] executables = [] contexts = [] environment = Lobby } (e: Eco) initialize := e initialize: (Eco Package load-from: "package.eco") (e: Eco) initialize: pkg := { pkg dependencies each: { c | e packages (find: c from) match: { @none -> raise: @(package-unavailable: c from needed: c to) -- filter out versions not satisfying our dependency @(ok: d) -> { safe = d to (filter: { p | p version join: c to }) safe match: { [] -> raise: @(no-versions-of: d satisfy: c to for: pkg name) -- initialize the first safe version of the package (p . _) -> { -- remove unsafe versions from the ecosystem d to = safe e initialize: p } call } } call } } @ok } call (e: Eco) load := { eco = Directory home ".eco" "lib" when: Directory (exists?: eco) do: { e packages = Directory (contents: eco) map: { c | versions = Directory (contents: (eco c)) pkgs = versions map: { v | Eco Package load-from: (eco c v "package.eco") } c -> pkgs (sort-by: { a b | a version < b version }) } } @ok } call Eco path-to: (c: Eco Package) := Eco path-to: c name version: c version Eco path-to: (name: String) := Directory home ".eco" "lib" name Eco path-to: pkg version: (v: Version) := (Eco path-to: pkg) (v as: String) Eco executable: (name: String) := Directory home ".eco" "bin" name Eco which-main: (path: String) := if: File (exists?: (path "main.hs")) then: { "main.hs" } else: { "main.atomo" } Eco install: (path: String) := { pkg = Eco Package load-from: (path "package.eco") target = Eco path-to: pkg contents = (Eco which-main: path) . ("package.eco" . pkg include) Directory create-tree-if-missing: target contents each: { c | if: Directory (exists?: (path c)) then: { Directory copy: (path c) to: (target c) } else: { File copy: (path c) to: (target c) } } pkg executables each: { e | exe = [ "#!/usr/bin/env atomo" "load: " .. (path e to) show ] unlines with-output-to: (Eco executable: e from) do: { exe print } File set-executable: (Eco executable: e from) to: True } @ok } call Eco uninstall: (name: String) version: (version: Version) := { path = Eco path-to: name version: version pkg = Eco Package load-from: (path "package.eco") Directory remove-recursive: path pkg executables each: { e | File remove: (Eco executable: e from) } @ok } call Eco uninstall: (name: String) := { Directory (contents: (Eco path-to: name)) each: { v | Eco uninstall: name version: (v as: Version) } @ok } call Eco Package load-from: (file: String) := Eco Package new do: { load: file } (p: Eco Package) name: (n: String) := p name = n (p: Eco Package) description: (d: String) := p description = d (p: Eco Package) version: (v: Version) := p version = v (p: Eco Package) author: (a: String) := p author = a (p: Eco Package) include: (l: List) := p include = l (p: Eco Package) depends-on: (ds: List) := p dependencies = ds map: { d | if: (d is-a?: Association) then: { d } else: { d -> { True } } } (p: Eco Package) executables: (es: List) := p executables = es Eco load: name version: check in: env := Eco packages (lookup: name) match: { @none -> raise: @(package-unavailable: name) @(ok: []) -> raise: @(no-package-versions: name) @(ok: pkgs) -> { pkg = pkgs (filter: { p | p version join: check }) match: { [] -> raise: @(no-versions-of: name satisfy: check) (p . _) -> p } path = Eco path-to: pkg pkg contexts = pkg contexts << env super env load: (path (Eco which-main: path)) pkg environment = env when: name (in?: Eco loaded (map: @from)) not do: { Eco loaded = Eco loaded << (name -> pkg) } env } call } context use: (name: String) := context use: name version: { True } context use: (name: String) version: (v: Version) := context use: name version: { == v } context use: (name: String) version: (check: Block) := Eco loaded (lookup: name) match: { @none -> (Eco load: name version: check in: context clone) @(ok: p) -> condition: { p version (join: check) not -> raise: @(incompatible-version-loaded: name needed: check) (context in?: p contexts) -> p environment otherwise -> (Eco load: name version: check in: context clone) } }