add epm — El Package Manager
Introduces epm/, a new component written entirely in native El.
epm manages vessels (El's deployable package format): publish to Engram,
install with full dependency resolution, list registry contents, and
inspect vessel metadata.
- epm/manifest.el — package manifest
- epm/src/manifest.el — vessel/package manifest parser (line-by-line,
same approach as elb.el)
- epm/src/registry.el — Engram-backed vessel registry (POST /api/nodes,
GET /api/search); vessels stored as Entity nodes
with label "vessel:<name>:<version>"
- epm/src/install.el — topological dependency resolver with cycle
detection; installs to .epm/vessels/<name>/
- epm/src/epm.el — main entry point: publish / install / list / info
This commit is contained in:
+213
@@ -0,0 +1,213 @@
|
||||
// epm/src/epm.el — El Package Manager entry point
|
||||
//
|
||||
// epm manages vessels: the deployable, versioned units of El code.
|
||||
// Vessels are stored in Engram (the graph database) and installed locally
|
||||
// under .epm/vessels/.
|
||||
//
|
||||
// Usage:
|
||||
// epm publish # publish current project to registry
|
||||
// epm install # install all dependencies from manifest.el
|
||||
// epm install <vessel> # install a specific vessel
|
||||
// epm list # list all vessels in the registry
|
||||
// epm info <vessel> # show metadata for a vessel
|
||||
// epm info <vessel> <version> # show metadata for a specific version
|
||||
//
|
||||
// Configuration (environment):
|
||||
// ENGRAM_URL — Engram base URL (default: http://localhost:8742)
|
||||
//
|
||||
// Import order: manifest.el, registry.el, install.el must be compiled first.
|
||||
// This file imports all three and is the build entry point.
|
||||
|
||||
import "manifest.el"
|
||||
import "registry.el"
|
||||
import "install.el"
|
||||
|
||||
// ── Subcommand handlers ───────────────────────────────────────────────────────
|
||||
|
||||
// cmd_publish reads manifest.el from the current directory and publishes
|
||||
// the vessel/package to the Engram registry.
|
||||
fn cmd_publish() -> Void {
|
||||
let src: String = fs_read("manifest.el")
|
||||
if str_eq(src, "") {
|
||||
println("epm: no manifest.el found in current directory")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let name: String = manifest_name(src)
|
||||
if str_eq(name, "") {
|
||||
println("epm: manifest.el has no 'vessel' or 'package' declaration")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let version: String = manifest_version(src)
|
||||
if str_eq(version, "") {
|
||||
println("epm: manifest.el has no 'version' declaration")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let description: String = manifest_description(src)
|
||||
let entry: String = manifest_entry(src)
|
||||
let deps_json: String = manifest_deps(src)
|
||||
|
||||
println("epm: publishing " + name + " " + version + " ...")
|
||||
|
||||
let node_id: String = registry_publish(name, version, description, entry, deps_json)
|
||||
if str_eq(node_id, "") {
|
||||
println("epm: publish failed")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
println("epm: published " + name + " " + version + " (node: " + node_id + ")")
|
||||
}
|
||||
|
||||
// cmd_install_named installs a specific vessel by name (with optional version).
|
||||
// Expects: install <name> or install <name>@<version>
|
||||
fn cmd_install_named(spec: String) -> Void {
|
||||
// spec may be "el-auth" or "el-auth@0.1.0"
|
||||
let at: Int = str_index_of(spec, "@")
|
||||
let vname: String = spec
|
||||
let vver: String = ""
|
||||
if at > 0 {
|
||||
let vname = str_slice(spec, 0, at)
|
||||
let vver = str_slice(spec, at + 1, str_len(spec))
|
||||
}
|
||||
|
||||
println("epm: installing " + vname + " ...")
|
||||
|
||||
let mk1: Int = exec_command("mkdir -p .epm/vessels")
|
||||
let ok: Bool = install_vessel(vname, vver)
|
||||
if !ok {
|
||||
println("epm: install failed")
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// cmd_list prints all vessels registered in Engram.
|
||||
fn cmd_list() -> Void {
|
||||
println("epm: fetching vessel list from registry ...")
|
||||
let raw: String = registry_list()
|
||||
let n: Int = json_array_len(raw)
|
||||
|
||||
if n == 0 {
|
||||
println("epm: no vessels found in registry")
|
||||
return
|
||||
}
|
||||
|
||||
println("epm: " + native_int_to_str(n) + " vessel(s) in registry:")
|
||||
println("")
|
||||
|
||||
let i: Int = 0
|
||||
while i < n {
|
||||
// Each element is a quoted+escaped content JSON blob
|
||||
let elem: String = json_array_get_string(raw, i)
|
||||
let vname: String = json_get_string(elem, "name")
|
||||
let vver: String = json_get_string(elem, "version")
|
||||
let vdesc: String = json_get_string(elem, "description")
|
||||
println(" " + vname + " " + vver + " — " + vdesc)
|
||||
let i = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
// cmd_info prints detailed metadata for a specific vessel.
|
||||
// argv is the full args list; idx is the position of the vessel name.
|
||||
fn cmd_info(argv: [String], idx: Int) -> Void {
|
||||
let argc: Int = native_list_len(argv)
|
||||
if idx >= argc {
|
||||
println("epm: usage: epm info <vessel> [version]")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let vname: String = native_list_get(argv, idx)
|
||||
let vver: String = ""
|
||||
if idx + 1 < argc {
|
||||
let vver = native_list_get(argv, idx + 1)
|
||||
}
|
||||
|
||||
let content: String = registry_find(vname, vver)
|
||||
if str_eq(content, "") {
|
||||
println("epm: vessel '" + vname + "' not found in registry")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let name: String = json_get_string(content, "name")
|
||||
let ver: String = json_get_string(content, "version")
|
||||
let desc: String = json_get_string(content, "description")
|
||||
let entry: String = json_get_string(content, "entry")
|
||||
let deps_raw: String = json_get_raw(content, "deps")
|
||||
|
||||
println("name: " + name)
|
||||
println("version: " + ver)
|
||||
println("description: " + desc)
|
||||
println("entry: " + entry)
|
||||
|
||||
let dep_n: Int = json_array_len(deps_raw)
|
||||
if dep_n == 0 {
|
||||
println("dependencies: (none)")
|
||||
} else {
|
||||
println("dependencies:")
|
||||
let di: Int = 0
|
||||
while di < dep_n {
|
||||
let dep: String = json_array_get(deps_raw, di)
|
||||
let dep_name: String = json_get_string(dep, "name")
|
||||
let dep_ver: String = json_get_string(dep, "version")
|
||||
println(" " + dep_name + " " + dep_ver)
|
||||
let di = di + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
fn main() -> Void {
|
||||
let argv: [String] = args()
|
||||
let argc: Int = native_list_len(argv)
|
||||
|
||||
// argv[0] is the program name; subcommand is argv[1]
|
||||
if argc < 2 {
|
||||
println("epm — El Package Manager")
|
||||
println("")
|
||||
println("usage:")
|
||||
println(" epm publish publish current project to registry")
|
||||
println(" epm install install all dependencies (from manifest.el)")
|
||||
println(" epm install <vessel> install a specific vessel")
|
||||
println(" epm install <vessel>@<ver> install a specific vessel at a version")
|
||||
println(" epm list list all vessels in the registry")
|
||||
println(" epm info <vessel> show vessel metadata")
|
||||
println(" epm info <vessel> <version> show metadata for a specific version")
|
||||
println("")
|
||||
println("configuration:")
|
||||
println(" ENGRAM_URL Engram base URL (default: http://localhost:8742)")
|
||||
exit(0)
|
||||
}
|
||||
|
||||
let sub: String = native_list_get(argv, 1)
|
||||
|
||||
if str_eq(sub, "publish") {
|
||||
cmd_publish()
|
||||
return
|
||||
}
|
||||
|
||||
if str_eq(sub, "install") {
|
||||
if argc >= 3 {
|
||||
let spec: String = native_list_get(argv, 2)
|
||||
cmd_install_named(spec)
|
||||
} else {
|
||||
cmd_install()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if str_eq(sub, "list") {
|
||||
cmd_list()
|
||||
return
|
||||
}
|
||||
|
||||
if str_eq(sub, "info") {
|
||||
cmd_info(argv, 2)
|
||||
return
|
||||
}
|
||||
|
||||
println("epm: unknown subcommand '" + sub + "'")
|
||||
println("run 'epm' with no arguments for usage")
|
||||
exit(1)
|
||||
}
|
||||
Reference in New Issue
Block a user