|

Migrate to Reef 0.7.5 Result/Option stdlib

Migrate to Reef 0.7.5 Result/Option stdlib

Reef 0.7.5 replaced in-band failure sentinels with Result/Option across the
stdlib. Repoint core.result_generic -> core.result (removed module; keeps the
rg alias and repoman's own Result[T, string] convention) and bind+branch on
the newly Result-returning stdlib calls:

- iofile.readFile/writeFile/appendFile/deleteFile/rename/fsync -> Result
- iodir.create_dir_all -> Result; iodir.list_dir -> Result[[string]]
  (rewrote profile.list_all from buffer-fill to returned arrays)
- toml.toml_parse_doc -> Result; drop removed TomlDoc.truncated checks

error.Error is converted to repoman's string errors at the stdlib boundary via
error.error_message. Tests repointed likewise. Build clean, all suites pass.
Author: Chris Tusa <chris.tusa@leafscale.com>
Date: Jul 15, 2026 11:31
Changeset: c792cbf72723b8f8b43125113f6f8374af21db7a
Branch: default

Diff

diff -r 69a21bb79b71 -r c792cbf72723 src/cli.reef
--- a/src/cli.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/cli.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -18,7 +18,8 @@
 module cli
 
 import core.str
-import core.result_generic as rg
+import core.result as rg
+import core.error as error
 import core.convert as convert
 import time.time as time
 import io.console as console
@@ -138,7 +139,12 @@
         env_keys: new [string](0), env_values: new [string](0)
     }
     if iofile.fileExists(override_path)
-        let ov_r = config.parse_override(iofile.readFile(override_path))
+        let ov_read = iofile.readFile(override_path)
+        if rg.is_err(ov_read)
+            log.write("repoman: error: cannot read override " + override_path + ": " + error.error_message(rg.unwrap_err(ov_read)))
+            return 3
+        end if
+        let ov_r = config.parse_override(rg.unwrap_ok(ov_read))
         if rg.is_err(ov_r)
             log.write("repoman: error: bad override " + override_path + ": " + rg.unwrap_err(ov_r))
             return 3
diff -r 69a21bb79b71 -r c792cbf72723 src/config.reef
--- a/src/config.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/config.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -18,7 +18,8 @@
 module config
 
 import core.str
-import core.result_generic as rg
+import core.result as rg
+import core.error as error
 import encoding.toml as toml
 import io.file as iofile
 import io.dir as iodir
@@ -171,10 +172,11 @@
 end parse_string_array
 
 fn parse_registry(toml_text: string): rg.Result[Registry, string]
-    let doc: toml.TomlDoc = toml.toml_parse_doc(toml_text)
-    if doc.truncated
-        return @Result[Registry, string].Err("registry too large (>1024 entries)")
+    let doc_r = toml.toml_parse_doc(toml_text)
+    if rg.is_err(doc_r)
+        return @Result[Registry, string].Err("registry parse error: " + error.error_message(rg.unwrap_err(doc_r)))
     end if
+    let doc: toml.TomlDoc = rg.unwrap_ok(doc_r)
 
     let schema: int = toml.toml_get_int_doc(doc, "repoman.schema")
     if schema != 1 and schema != 2 and schema != 3
@@ -283,10 +285,11 @@
 end serialize_registry
 
 fn parse_override(toml_text: string): rg.Result[Override, string]
-    let doc: toml.TomlDoc = toml.toml_parse_doc(toml_text)
-    if doc.truncated
-        return @Result[Override, string].Err("override too large")
+    let doc_r = toml.toml_parse_doc(toml_text)
+    if rg.is_err(doc_r)
+        return @Result[Override, string].Err("override parse error: " + error.error_message(rg.unwrap_err(doc_r)))
     end if
+    let doc: toml.TomlDoc = rg.unwrap_ok(doc_r)
 
     let image: string = toml.toml_get_doc(doc, "container.image")
     let profiles_raw: string = toml.toml_get_doc(doc, "container.profiles")
@@ -515,14 +518,17 @@
 
     // Ensure ~/.config/repoman/ exists
     if not iodir.dir_exists(cfg_dir)
-        if not iodir.create_dir_all(cfg_dir)
+        if rg.is_err(iodir.create_dir_all(cfg_dir))
             return @Result[Registry, string].Err("cannot create config dir: " + cfg_dir)
         end if
     end if
 
     if iofile.fileExists(cfg_path)
-        let contents: string = iofile.readFile(cfg_path)
-        return parse_registry(contents)
+        let contents_r = iofile.readFile(cfg_path)
+        if rg.is_err(contents_r)
+            return @Result[Registry, string].Err("cannot read registry: " + error.error_message(rg.unwrap_err(contents_r)))
+        end if
+        return parse_registry(rg.unwrap_ok(contents_r))
     end if
 
     // Init: write default registry.
@@ -540,19 +546,22 @@
     let serialized: string = serialize_registry(reg)
     let tmp_path: string = cfg_path + ".tmp"
 
-    if not iofile.writeFile(tmp_path, serialized)
-        return @Result[bool, string].Err("write failed: " + tmp_path)
+    let write_r = iofile.writeFile(tmp_path, serialized)
+    if rg.is_err(write_r)
+        return @Result[bool, string].Err("write failed: " + tmp_path + ": " + error.error_message(rg.unwrap_err(write_r)))
     end if
 
-    if not iofile.fsync(tmp_path)
+    let fsync_r = iofile.fsync(tmp_path)
+    if rg.is_err(fsync_r)
         // Best effort: clean up tmp
-        let _d: bool = iofile.deleteFile(tmp_path)
-        return @Result[bool, string].Err("fsync failed: " + tmp_path)
+        let _d = iofile.deleteFile(tmp_path)
+        return @Result[bool, string].Err("fsync failed: " + tmp_path + ": " + error.error_message(rg.unwrap_err(fsync_r)))
     end if
 
-    if not iofile.rename(tmp_path, cfg_path)
-        let _d: bool = iofile.deleteFile(tmp_path)
-        return @Result[bool, string].Err("rename failed: " + tmp_path + " → " + cfg_path)
+    let rename_r = iofile.rename(tmp_path, cfg_path)
+    if rg.is_err(rename_r)
+        let _d = iofile.deleteFile(tmp_path)
+        return @Result[bool, string].Err("rename failed: " + tmp_path + " → " + cfg_path + ": " + error.error_message(rg.unwrap_err(rename_r)))
     end if
 
     return @Result[bool, string].Ok(true)
diff -r 69a21bb79b71 -r c792cbf72723 src/hermes.reef
--- a/src/hermes.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/hermes.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -18,7 +18,7 @@
 module hermes
 
 import core.str
-import core.result_generic as rg
+import core.result as rg
 import core.convert as convert
 import io.dir as iodir
 import sys.process as p
@@ -111,7 +111,7 @@
     if not iodir.dir_exists(source)
         return @Result[bool, string].Err("hermes source dir not found: " + source)
     end if
-    if not iodir.create_dir_all(dest)
+    if rg.is_err(iodir.create_dir_all(dest))
         return @Result[bool, string].Err("cannot create dest dir: " + dest)
     end if
 
diff -r 69a21bb79b71 -r c792cbf72723 src/incus.reef
--- a/src/incus.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/incus.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -20,7 +20,7 @@
 import core.str
 import sys.process as p
 import sys.fd as fd
-import core.result_generic as rg
+import core.result as rg
 import core.convert as convert
 
 export
diff -r 69a21bb79b71 -r c792cbf72723 src/log.reef
--- a/src/log.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/log.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -18,6 +18,7 @@
 module log
 
 import core.str
+import core.result as rg
 import io.console as console
 import io.file as iofile
 import io.dir as iodir
@@ -43,7 +44,7 @@
     let expanded: string = paths.expand_home(logdir)
 
     if not iodir.dir_exists(expanded)
-        if not iodir.create_dir_all(expanded)
+        if rg.is_err(iodir.create_dir_all(expanded))
             console.printErr("repoman: warning: cannot create logdir " + expanded + "; file logging disabled")
             log_enabled = false
             return false
@@ -54,7 +55,7 @@
     let path: string = paths.join(expanded, filename)
 
     // Truncate (or create) the file by writing an empty string.
-    if not iofile.writeFile(path, "")
+    if rg.is_err(iofile.writeFile(path, ""))
         console.printErr("repoman: warning: cannot open " + path + " for writing; file logging disabled")
         log_enabled = false
         return false
@@ -71,7 +72,7 @@
 proc write(msg: string)
     console.printErr(msg)
     if log_enabled
-        let _w: bool = iofile.appendFile(log_path, msg + "\n")
+        let _w = iofile.appendFile(log_path, msg + "\n")
     end if
 end write
 
diff -r 69a21bb79b71 -r c792cbf72723 src/profile.reef
--- a/src/profile.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/profile.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -18,7 +18,8 @@
 module profile
 
 import core.str
-import core.result_generic as rg
+import core.result as rg
+import core.error as error
 import core.convert as convert
 import io.file as iofile
 import io.dir as iodir
@@ -89,23 +90,28 @@
 end lookup
 
 fn list_all(home_dir: string): [ProfileEntry]
-    // Buffers for filename lists. Cap at 256 per dir; profile libraries
-    // are not expected to be enormous.
-    let max_files: int = 256
-    mut user_buf: [string] = new [string](max_files)
-    mut vendor_buf: [string] = new [string](max_files)
-
+    // list_dir returns the directory's entries as an array (Result-wrapped);
+    // a missing/unreadable dir is treated as empty. Profile libraries are
+    // not expected to be enormous.
     let u_dir: string = user_dir(home_dir)
-    mut user_count: int = 0
+    mut user_buf: [string] = new [string](0)
     if iodir.dir_exists(u_dir)
-        user_count = iodir.list_dir(u_dir, user_buf, max_files)
+        let ur = iodir.list_dir(u_dir)
+        if rg.is_ok(ur)
+            user_buf = rg.unwrap_ok(ur)
+        end if
     end if
+    let user_count: int = user_buf.length()
 
     let v_dir: string = vendor_dir()
-    mut vendor_count: int = 0
+    mut vendor_buf: [string] = new [string](0)
     if iodir.dir_exists(v_dir)
-        vendor_count = iodir.list_dir(v_dir, vendor_buf, max_files)
+        let vr = iodir.list_dir(v_dir)
+        if rg.is_ok(vr)
+            vendor_buf = rg.unwrap_ok(vr)
+        end if
     end if
+    let vendor_count: int = vendor_buf.length()
 
     // Pre-allocate result buffer at worst-case size.
     let cap: int = user_count + vendor_count
@@ -195,9 +201,13 @@
     let path: string = rg.unwrap_ok(path_r)
 
     // Read the file
-    let yaml: string = iofile.readFile(path)
+    let yaml_r = iofile.readFile(path)
+    if rg.is_err(yaml_r)
+        return @Result[bool, string].Err("unreadable profile file: " + path + ": " + error.error_message(rg.unwrap_err(yaml_r)))
+    end if
+    let yaml: string = rg.unwrap_ok(yaml_r)
     if str.length(yaml) == 0
-        return @Result[bool, string].Err("empty or unreadable profile file: " + path)
+        return @Result[bool, string].Err("empty profile file: " + path)
     end if
 
     // Render — but if HOST_LAN_IP is needed and host.lan_ip is empty, fail with a hint
@@ -220,8 +230,11 @@
         return @Result[string, string].Err(rg.unwrap_err(path_r))
     end if
     let path: string = rg.unwrap_ok(path_r)
-    let yaml: string = iofile.readFile(path)
-    let rendered: string = render(yaml, host)
+    let yaml_r = iofile.readFile(path)
+    if rg.is_err(yaml_r)
+        return @Result[string, string].Err("cannot read profile file: " + path + ": " + error.error_message(rg.unwrap_err(yaml_r)))
+    end if
+    let rendered: string = render(rg.unwrap_ok(yaml_r), host)
     return @Result[string, string].Ok(rendered)
 end show
 
@@ -232,8 +245,11 @@
         return @Result[string, string].Err(rg.unwrap_err(path_r))
     end if
     let path: string = rg.unwrap_ok(path_r)
-    let yaml: string = iofile.readFile(path)
-    let rendered: string = render(yaml, host)
+    let yaml_r = iofile.readFile(path)
+    if rg.is_err(yaml_r)
+        return @Result[string, string].Err("cannot read profile file: " + path + ": " + error.error_message(rg.unwrap_err(yaml_r)))
+    end if
+    let rendered: string = render(rg.unwrap_ok(yaml_r), host)
 
     // Fetch incus state
     let incus_r = incus.profile_get("default", name)
diff -r 69a21bb79b71 -r c792cbf72723 src/setup.reef
--- a/src/setup.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/setup.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -18,7 +18,7 @@
 module setup
 
 import core.str
-import core.result_generic as rg
+import core.result as rg
 import io.console as console
 import io.dir as iodir
 import sys.env
@@ -150,7 +150,7 @@
         // Ensure the user-profile-shadow dir exists so users can drop overrides
         // there without mkdir ceremony. iodir.create_dir_all is idempotent.
         let profiles_d: string = profile.user_dir(env.home_dir)
-        let _md: bool = iodir.create_dir_all(profiles_d)
+        let _md = iodir.create_dir_all(profiles_d)
         return @Result[config.Registry, string].Ok(new_reg)
     end if
 
diff -r 69a21bb79b71 -r c792cbf72723 src/sync.reef
--- a/src/sync.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/src/sync.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -18,7 +18,7 @@
 module sync
 
 import core.str
-import core.result_generic as rg
+import core.result as rg
 import sys.process as p
 import sys.fd as fd
 
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_io.reef
--- a/tests/test_config_io.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_io.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 import io.dir as iodir
 import io.file as iofile
 import sys.process as pr
@@ -29,7 +29,7 @@
     let tmp: string = "/tmp/repoman-test-load-init"
     // Wipe and recreate
     let _w: int = pr.process_wait(pr.process_spawn("rm", ["-rf", tmp]))
-    let _c: bool = iodir.create_dir_all(tmp)
+    let _c = iodir.create_dir_all(tmp)
 
     // First call: no .config/repoman/repoman.toml exists → init writes default
     let r1 = config.load_or_init(tmp)
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_migrate.reef
--- a/tests/test_config_migrate.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_migrate.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 
 proc main()
     let runner = new framework.TestRunner()
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_mutate.reef
--- a/tests/test_config_mutate.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_mutate.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 
 fn empty_defaults(): config.Defaults
     return config.Defaults {
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_override.reef
--- a/tests/test_config_override.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_override.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 
 proc main()
     let runner = new framework.TestRunner()
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_parse.reef
--- a/tests/test_config_parse.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_parse.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 
 proc main()
     let runner = new framework.TestRunner()
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_roundtrip.reef
--- a/tests/test_config_roundtrip.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_roundtrip.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 
 proc main()
     let runner = new framework.TestRunner()
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_save.reef
--- a/tests/test_config_save.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_save.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 import io.dir as iodir
 import io.file as iofile
 import sys.process as pr
@@ -27,7 +27,7 @@
 
     let tmp: string = "/tmp/repoman-test-save"
     let _w: int = pr.process_wait(pr.process_spawn("rm", ["-rf", tmp]))
-    let _c: bool = iodir.create_dir_all(tmp)
+    let _c = iodir.create_dir_all(tmp)
     let cfg_path: string = tmp + "/repoman.toml"
 
     let reg: config.Registry = config.default_registry("/home/u")
@@ -37,8 +37,9 @@
     runner.assert_eq_bool(iofile.fileExists(cfg_path + ".tmp"), false, "tmp removed after rename")
 
     // Round-trip: read what we wrote
-    let contents: string = iofile.readFile(cfg_path)
-    let r2 = config.parse_registry(contents)
+    let read_r = iofile.readFile(cfg_path)
+    runner.assert_eq_bool(rg.is_ok(read_r), true, "saved file readable")
+    let r2 = config.parse_registry(rg.unwrap_ok(read_r))
     runner.assert_eq_bool(rg.is_ok(r2), true, "saved file parses")
     if rg.is_ok(r2)
         let reg2 = rg.unwrap_ok(r2)
diff -r 69a21bb79b71 -r c792cbf72723 tests/test_config_schema_v3.reef
--- a/tests/test_config_schema_v3.reef	Tue Jun 02 15:58:49 2026 -0500
+++ b/tests/test_config_schema_v3.reef	Wed Jul 15 11:31:03 2026 -0500
@@ -17,7 +17,7 @@
 
 import config
 import test.framework
-import core.result_generic as rg
+import core.result as rg
 import core.str
 
 proc main()