mirror of
https://github.com/sbrow/envr.git
synced 2026-06-27 10:38:33 -04:00
feat: Config can be loaded from any path with --config-file (-c) flag.
This commit is contained in:
14
TEST_PLAN.md
14
TEST_PLAN.md
@@ -2,22 +2,17 @@
|
||||
|
||||
## Current State
|
||||
|
||||
- 101 tests, all passing
|
||||
- Strong coverage: crypto (100%), ssh (90%), db CRUD + env_file + update_dir, config save/load + paths, scan, features, cant_scan, parse_args
|
||||
- 104 tests, all passing
|
||||
- Strong coverage: crypto, ssh, db CRUD + env_file + update_dir, config save/load + paths, scan, features, cant_scan, parse_args, `-c`/`--config-file` flag
|
||||
- Misleading test files: `cmd_check_test`, `cmd_list_test`, `cmd_nushell_completion_test` don't test their namesake procs
|
||||
- Biggest remaining gap: all `cmd_*` handlers untested
|
||||
|
||||
## Next: `load_config` / `save_config` path param + `-c`/`--config-file` flag
|
||||
- Refactor `load_config(path: string = "")` and `save_config(cfg, force, path: string = "")` — empty string defaults to `~/.envr/config.json`
|
||||
- Add `-c`/`--config-file` to `parse_args` (now testable)
|
||||
- Wire through `main.odin` so commands receive the config path
|
||||
- Unblocks command handler tests with fixture configs
|
||||
## Command handler tests
|
||||
|
||||
## Command handlers (need DB + filesystem fixtures)
|
||||
Stdout will be captured by redirecting `os.stdout` to a pipe.
|
||||
|
||||
### `cmd_version` (cmd_version.odin)
|
||||
- Test default output (prints VERSION)
|
||||
- Capture stdout, assert content
|
||||
|
||||
### `cmd_list` (cmd_list.odin)
|
||||
- Test TTY path: fixture DB with rows, capture table output
|
||||
@@ -69,7 +64,6 @@
|
||||
|
||||
## Notes
|
||||
|
||||
- All command handler tests will need stdout capture. Consider extracting a helper or using `io.Writer` injection.
|
||||
- DB integration tests should use in-memory SQLite (`:memory:`) where possible.
|
||||
- Temp dir fixtures should follow the pattern in `scan_test.odin`.
|
||||
- External dependency tests (`fd`, `git`) should use `#assert` to ensure the dependency is present rather than silently skipping (TODO 28).
|
||||
|
||||
22
cli.odin
22
cli.odin
@@ -8,10 +8,11 @@ import "core:os"
|
||||
import "core:strings"
|
||||
|
||||
Command :: struct {
|
||||
name: string,
|
||||
args: [dynamic]string,
|
||||
flags: map[string]string,
|
||||
bool_set: map[string]bool,
|
||||
name: string,
|
||||
args: [dynamic]string,
|
||||
flags: map[string]string,
|
||||
bool_set: map[string]bool,
|
||||
config_path: string,
|
||||
}
|
||||
|
||||
CommandInfo :: struct {
|
||||
@@ -94,6 +95,16 @@ parse_args :: proc(args: []string) -> (cmd: Command, ok: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := cmd.flags["config-file"]; ok {
|
||||
cmd.config_path = val
|
||||
} else if val, ok := cmd.flags["c"]; ok {
|
||||
cmd.config_path = val
|
||||
} else {
|
||||
// FIXME: Handle err
|
||||
home, _ := os.user_home_dir(context.allocator)
|
||||
cmd.config_path = default_config_path(home)
|
||||
}
|
||||
|
||||
if has_flag(&cmd, "help") {
|
||||
print_command_help(cmd.name)
|
||||
return Command{}, false
|
||||
@@ -146,7 +157,7 @@ write_command_help :: proc(name: string, w: io.Writer) -> bool {
|
||||
fmt.wprintf(w, "\n%s\n", info.long, flush = false)
|
||||
}
|
||||
|
||||
fmt.wprintf(w, "\nFlags:\n -h, --help help for %s\n", info.name, flush = false)
|
||||
fmt.wprintf(w, "\nFlags:\n -h, --help help for %s\n -c, --config-file <path> config file (default \"~/.envr/config.json\")\n", info.name, flush = false)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -227,6 +238,7 @@ Available Commands:
|
||||
`
|
||||
Flags:
|
||||
-h, --help help for envr
|
||||
-c, --config-file <path> config file (default "~/.envr/config.json")
|
||||
|
||||
Use "envr [command] --help" for more information about a command.
|
||||
`,
|
||||
|
||||
@@ -315,3 +315,44 @@ test_parse_args_flag_then_positional_then_flag :: proc(t: ^testing.T) {
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_parse_args_config_file_long_flag :: proc(t: ^testing.T) {
|
||||
cmd, ok := parse_args([]string{"envr", "list", "--config-file", "/custom/config.json"})
|
||||
testing.expect(t, ok, "should succeed")
|
||||
if !ok do return
|
||||
defer delete(cmd.args)
|
||||
defer delete(cmd.flags)
|
||||
defer delete(cmd.bool_set)
|
||||
|
||||
testing.expect(t, cmd.config_path == "/custom/config.json", "config_path should be set from --config-file")
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_parse_args_config_file_short_flag :: proc(t: ^testing.T) {
|
||||
cmd, ok := parse_args([]string{"envr", "list", "-c", "/custom/config.json"})
|
||||
testing.expect(t, ok, "should succeed")
|
||||
if !ok do return
|
||||
defer delete(cmd.args)
|
||||
defer delete(cmd.flags)
|
||||
defer delete(cmd.bool_set)
|
||||
|
||||
testing.expect(t, cmd.config_path == "/custom/config.json", "config_path should be set from -c")
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_parse_args_config_file_defaults :: proc(t: ^testing.T) {
|
||||
cmd, ok := parse_args([]string{"envr", "list"})
|
||||
testing.expect(t, ok, "should succeed")
|
||||
if !ok do return
|
||||
defer delete(cmd.args)
|
||||
defer delete(cmd.flags)
|
||||
defer delete(cmd.bool_set)
|
||||
|
||||
testing.expect(t, len(cmd.config_path) > 0, "config_path should default to non-empty path")
|
||||
testing.expect(
|
||||
t,
|
||||
strings.contains(cmd.config_path, ".envr"),
|
||||
"default config_path should contain .envr dir, got %s",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ cmd_backup :: proc(cmd: ^Command) {
|
||||
return
|
||||
}
|
||||
|
||||
db, db_ok := db_open()
|
||||
db, db_ok := db_open(cmd.config_path)
|
||||
if !db_ok {
|
||||
// TODO: log a message
|
||||
return
|
||||
|
||||
@@ -31,7 +31,7 @@ cmd_check :: proc(cmd: ^Command) {
|
||||
abs_path = resolved
|
||||
}
|
||||
|
||||
db, db_ok := db_open()
|
||||
db, db_ok := db_open(cmd.config_path)
|
||||
if !db_ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:path/filepath"
|
||||
|
||||
cmd_edit_config :: proc(cmd: ^Command) {
|
||||
editor := os.get_env("EDITOR", context.allocator)
|
||||
@@ -11,11 +10,7 @@ cmd_edit_config :: proc(cmd: ^Command) {
|
||||
return
|
||||
}
|
||||
|
||||
config_path, join_err := filepath.join([]string{envr_dir(), "config.json"})
|
||||
if join_err != nil {
|
||||
fmt.printf("Error building config path: %v\n", join_err)
|
||||
return
|
||||
}
|
||||
config_path := cmd.config_path
|
||||
|
||||
_, stat_err := os.stat(config_path, context.allocator)
|
||||
if stat_err != nil {
|
||||
|
||||
@@ -5,7 +5,7 @@ import "core:fmt"
|
||||
cmd_init :: proc(cmd: ^Command) {
|
||||
force := has_flag(cmd, "force") || has_flag(cmd, "f")
|
||||
|
||||
_, cfg_exists := load_config()
|
||||
_, cfg_exists := load_config(cmd.config_path)
|
||||
if cfg_exists && !force {
|
||||
fmt.println("You have already initialized envr.")
|
||||
fmt.println("Run again with the --force flag if you want to reinitialize.")
|
||||
@@ -41,7 +41,7 @@ cmd_init :: proc(cmd: ^Command) {
|
||||
return
|
||||
}
|
||||
|
||||
cfg := new_config(selected_paths[:])
|
||||
cfg := new_config(selected_paths[:], cmd.config_path)
|
||||
if !save_config(cfg, force = force) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ ListEntry :: struct {
|
||||
}
|
||||
|
||||
cmd_list :: proc(cmd: ^Command) {
|
||||
db, db_ok := db_open()
|
||||
db, db_ok := db_open(cmd.config_path)
|
||||
if !db_ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ cmd_remove :: proc(cmd: ^Command) {
|
||||
abs_path = resolved
|
||||
}
|
||||
|
||||
db, db_ok := db_open()
|
||||
db, db_ok := db_open(cmd.config_path)
|
||||
if !db_ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ cmd_restore :: proc(cmd: ^Command) {
|
||||
abs_path = resolved
|
||||
}
|
||||
|
||||
db, db_ok := db_open()
|
||||
db, db_ok := db_open(cmd.config_path)
|
||||
if !db_ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ cmd_scan :: proc(cmd: ^Command) {
|
||||
return
|
||||
}
|
||||
|
||||
db, db_ok := db_open()
|
||||
db, db_ok := db_open(cmd.config_path)
|
||||
if !db_ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ SyncEntry :: struct {
|
||||
|
||||
// TODO: Check for quiet failures.
|
||||
cmd_sync :: proc(cmd: ^Command) {
|
||||
db, db_ok := db_open()
|
||||
db, db_ok := db_open(cmd.config_path)
|
||||
if !db_ok {
|
||||
return
|
||||
}
|
||||
|
||||
58
config.odin
58
config.odin
@@ -18,21 +18,18 @@ ScanConfig :: struct {
|
||||
}
|
||||
|
||||
Config :: struct {
|
||||
Keys: [dynamic]SshKeyPair `json:"keys"`,
|
||||
ScanConfig: ScanConfig `json:"scan"`,
|
||||
Keys: [dynamic]SshKeyPair `json:"keys"`,
|
||||
ScanConfig: ScanConfig `json:"scan"`,
|
||||
config_path: string `json:"-"`,
|
||||
}
|
||||
|
||||
load_config :: proc() -> (Config, bool) {
|
||||
home, home_err := os.user_home_dir(context.temp_allocator)
|
||||
if home_err != nil {
|
||||
fmt.printf("Error getting home dir: %v\n", home_err)
|
||||
return Config{}, false
|
||||
}
|
||||
config_path, join_err := filepath.join([]string{home, ".envr", "config.json"})
|
||||
if join_err != nil {
|
||||
return Config{}, false
|
||||
}
|
||||
default_config_path :: proc(home: string) -> string {
|
||||
// FIXME: catch error
|
||||
path, _ := filepath.join([]string{home, ".envr", "config.json"})
|
||||
return path
|
||||
}
|
||||
|
||||
load_config :: proc(config_path: string) -> (Config, bool) {
|
||||
data, read_err := os.read_entire_file_from_path(config_path, context.allocator)
|
||||
if read_err != nil {
|
||||
fmt.println("No config file found. Please run `envr init` to generate one.")
|
||||
@@ -45,6 +42,7 @@ load_config :: proc() -> (Config, bool) {
|
||||
fmt.printf("Error parsing config: %v\n", err)
|
||||
return Config{}, false
|
||||
}
|
||||
cfg.config_path = config_path
|
||||
|
||||
return cfg, true
|
||||
}
|
||||
@@ -55,15 +53,12 @@ delete_config :: proc(cfg: Config) {
|
||||
delete(cfg.ScanConfig.Include)
|
||||
}
|
||||
|
||||
envr_dir :: proc() -> string {
|
||||
home, _ := os.user_home_dir(context.allocator)
|
||||
dir, _ := filepath.join([]string{home, ".envr"})
|
||||
return dir
|
||||
envr_dir :: proc(config_path: string) -> string {
|
||||
return filepath.dir(config_path)
|
||||
}
|
||||
|
||||
data_encrypted_path :: proc() -> string {
|
||||
dir := envr_dir()
|
||||
path, _ := filepath.join([]string{dir, "data.envr"})
|
||||
data_encrypted_path :: proc(config_path: string) -> string {
|
||||
path, _ := filepath.join([]string{envr_dir(config_path), "data.envr"})
|
||||
return path
|
||||
}
|
||||
|
||||
@@ -113,7 +108,10 @@ find_ssh_private_keys :: proc() -> (keys: [dynamic]string, ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
new_config :: proc(private_key_paths: []string) -> Config {
|
||||
new_config :: proc(
|
||||
private_key_paths: []string,
|
||||
cfg_path: string = "~/.envr/config.json",
|
||||
) -> Config {
|
||||
keys := make([dynamic]SshKeyPair, 0, len(private_key_paths))
|
||||
for priv in private_key_paths {
|
||||
// TODO: Is this bad?
|
||||
@@ -136,30 +134,22 @@ new_config :: proc(private_key_paths: []string) -> Config {
|
||||
Include = include,
|
||||
}
|
||||
|
||||
return Config{Keys = keys, ScanConfig = scan_cfg}
|
||||
return Config{Keys = keys, ScanConfig = scan_cfg, config_path = cfg_path}
|
||||
}
|
||||
|
||||
save_config :: proc(cfg: Config, force: bool = false) -> bool {
|
||||
home, home_err := os.user_home_dir(context.allocator)
|
||||
if home_err != nil {
|
||||
fmt.printf("Error getting home dir: %v\n", home_err)
|
||||
return false
|
||||
}
|
||||
|
||||
config_dir, _ := filepath.join([]string{home, ".envr"})
|
||||
config_dir := envr_dir(cfg.config_path)
|
||||
|
||||
if !os.exists(config_dir) {
|
||||
mkdir_err := os.make_directory(config_dir)
|
||||
if mkdir_err != nil {
|
||||
fmt.printf("Error creating ~/.envr directory: %v\n", mkdir_err)
|
||||
fmt.printf("Error creating %s directory: %v\n", config_dir, mkdir_err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
config_path, _ := filepath.join([]string{config_dir, "config.json"})
|
||||
|
||||
if os.exists(config_path) && !force {
|
||||
info, stat_err := os.stat(config_path, context.allocator)
|
||||
if os.exists(cfg.config_path) && !force {
|
||||
info, stat_err := os.stat(cfg.config_path, context.allocator)
|
||||
if stat_err == nil {
|
||||
defer os.file_info_delete(info, context.allocator)
|
||||
if info.size > 0 {
|
||||
@@ -175,7 +165,7 @@ save_config :: proc(cfg: Config, force: bool = false) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
write_err := os.write_entire_file(config_path, data)
|
||||
write_err := os.write_entire_file(cfg.config_path, data)
|
||||
if write_err != nil {
|
||||
fmt.printf("Error writing config: %v\n", write_err)
|
||||
return false
|
||||
|
||||
127
config_test.odin
127
config_test.odin
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:path/filepath"
|
||||
import "core:strings"
|
||||
import "core:sync"
|
||||
import "core:testing"
|
||||
@@ -69,27 +70,19 @@ test_new_config_exclude_patterns :: proc(t: ^testing.T) {
|
||||
|
||||
@(test)
|
||||
test_save_load_config_roundtrip :: proc(t: ^testing.T) {
|
||||
sync.mutex_lock(&home_mutex)
|
||||
defer sync.mutex_unlock(&home_mutex)
|
||||
|
||||
old_home := os.get_env("HOME", context.temp_allocator)
|
||||
defer {
|
||||
if old_home != "" {
|
||||
os.set_env("HOME", old_home)
|
||||
}
|
||||
}
|
||||
|
||||
base := fmt.tprintf("/tmp/envr-test-cfg-rt-%d", os.get_pid())
|
||||
os.mkdir_all(base)
|
||||
defer os.remove_all(base)
|
||||
os.set_env("HOME", base)
|
||||
|
||||
cfg := new_config([]string{"/home/user/.ssh/id_ed25519"})
|
||||
cfgPath, err := filepath.join([]string{base, "config.json"}, context.temp_allocator)
|
||||
testing.expect(t, err == nil, "cfgPath should build successfully")
|
||||
|
||||
cfg := new_config([]string{"/home/user/.ssh/id_ed25519"}, cfgPath)
|
||||
defer delete_config(cfg)
|
||||
|
||||
testing.expect(t, save_config(cfg, force=true), "save should succeed")
|
||||
testing.expect(t, save_config(cfg, force = true), "save should succeed")
|
||||
|
||||
loaded, ok := load_config()
|
||||
loaded, ok := load_config(cfg.config_path)
|
||||
testing.expect(t, ok, "load should succeed")
|
||||
if !ok do return
|
||||
defer delete_config(loaded)
|
||||
@@ -105,106 +98,62 @@ test_save_load_config_roundtrip :: proc(t: ^testing.T) {
|
||||
|
||||
@(test)
|
||||
test_load_config_missing :: proc(t: ^testing.T) {
|
||||
sync.mutex_lock(&home_mutex)
|
||||
defer sync.mutex_unlock(&home_mutex)
|
||||
|
||||
old_home := os.get_env("HOME", context.temp_allocator)
|
||||
defer {
|
||||
if old_home != "" {
|
||||
os.set_env("HOME", old_home)
|
||||
}
|
||||
}
|
||||
|
||||
base := fmt.tprintf("/tmp/envr-test-cfg-missing-%d", os.get_pid())
|
||||
os.mkdir_all(base)
|
||||
defer os.remove_all(base)
|
||||
os.set_env("HOME", base)
|
||||
|
||||
_, ok := load_config()
|
||||
_, ok := load_config("/tmp/envr-test-cfg-nonexistent/config.json")
|
||||
testing.expect(t, !ok, "missing config should return false")
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_save_config_no_clobber :: proc(t: ^testing.T) {
|
||||
sync.mutex_lock(&home_mutex)
|
||||
defer sync.mutex_unlock(&home_mutex)
|
||||
|
||||
old_home := os.get_env("HOME", context.temp_allocator)
|
||||
defer {
|
||||
if old_home != "" {
|
||||
os.set_env("HOME", old_home)
|
||||
}
|
||||
}
|
||||
|
||||
base := fmt.tprintf("/tmp/envr-test-cfg-noclobber-%d", os.get_pid())
|
||||
os.mkdir_all(base)
|
||||
defer os.remove_all(base)
|
||||
os.set_env("HOME", base)
|
||||
|
||||
cfg := new_config([]string{"/home/user/.ssh/key1"})
|
||||
cfgPath, err := filepath.join([]string{base, "config.json"}, context.temp_allocator)
|
||||
testing.expect(t, err == nil, "cfgPath should build successfully")
|
||||
|
||||
cfg := new_config([]string{"/home/user/.ssh/key1"}, cfgPath)
|
||||
defer delete_config(cfg)
|
||||
testing.expect(t, save_config(cfg, force=true), "first save should succeed")
|
||||
testing.expect(t, save_config(cfg, force = true), "first save should succeed")
|
||||
|
||||
cfg2 := new_config([]string{"/home/user/.ssh/key2"})
|
||||
cfg2 := new_config([]string{"/home/user/.ssh/key2"}, cfgPath)
|
||||
defer delete_config(cfg2)
|
||||
testing.expect(t, !save_config(cfg2), "second save without force should fail")
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_save_config_force_overwrites :: proc(t: ^testing.T) {
|
||||
sync.mutex_lock(&home_mutex)
|
||||
defer sync.mutex_unlock(&home_mutex)
|
||||
|
||||
old_home := os.get_env("HOME", context.temp_allocator)
|
||||
defer {
|
||||
if old_home != "" {
|
||||
os.set_env("HOME", old_home)
|
||||
}
|
||||
}
|
||||
|
||||
base := fmt.tprintf("/tmp/envr-test-cfg-force-%d", os.get_pid())
|
||||
os.mkdir_all(base)
|
||||
defer os.remove_all(base)
|
||||
os.set_env("HOME", base)
|
||||
|
||||
cfg := new_config([]string{"/home/user/.ssh/key1"})
|
||||
cfgPath, err := filepath.join([]string{base, "config.json"}, context.temp_allocator)
|
||||
testing.expect(t, err == nil, "cfgPath should build successfully")
|
||||
|
||||
cfg := new_config([]string{"/home/user/.ssh/key1"}, cfgPath)
|
||||
defer delete_config(cfg)
|
||||
testing.expect(t, save_config(cfg, force=true), "first save should succeed")
|
||||
testing.expect(t, save_config(cfg, force = true), "first save should succeed")
|
||||
|
||||
cfg2 := new_config([]string{"/home/user/.ssh/key2"})
|
||||
cfg2 := new_config([]string{"/home/user/.ssh/key2"}, cfgPath)
|
||||
defer delete_config(cfg2)
|
||||
testing.expect(t, save_config(cfg2, force=true), "force save should overwrite")
|
||||
testing.expect(t, save_config(cfg2, force = true), "force save should overwrite")
|
||||
|
||||
loaded, ok := load_config()
|
||||
loaded, ok := load_config(cfgPath)
|
||||
testing.expect(t, ok, "load should succeed")
|
||||
if !ok do return
|
||||
defer delete_config(loaded)
|
||||
|
||||
testing.expect(t, len(loaded.Keys) == 1, "should have 1 key")
|
||||
testing.expect(t, loaded.Keys[0].Private == "/home/user/.ssh/key2", "should be the overwritten key")
|
||||
testing.expect(
|
||||
t,
|
||||
loaded.Keys[0].Private == "/home/user/.ssh/key2",
|
||||
"should be the overwritten key",
|
||||
)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_envr_dir :: proc(t: ^testing.T) {
|
||||
sync.mutex_lock(&home_mutex)
|
||||
defer sync.mutex_unlock(&home_mutex)
|
||||
|
||||
old_home := os.get_env("HOME", context.temp_allocator)
|
||||
defer {
|
||||
if old_home != "" {
|
||||
os.set_env("HOME", old_home)
|
||||
}
|
||||
}
|
||||
|
||||
os.set_env("HOME", "/tmp/envr-fake-home-envrdir")
|
||||
|
||||
dir := envr_dir()
|
||||
testing.expectf(
|
||||
t,
|
||||
strings.has_suffix(dir, ".envr"),
|
||||
"dir should end with .envr, got %s",
|
||||
dir,
|
||||
)
|
||||
dir := envr_dir("/tmp/envr-fake-home-envrdir/.envr/config.json")
|
||||
testing.expectf(t, strings.has_suffix(dir, ".envr"), "dir should end with .envr, got %s", dir)
|
||||
testing.expectf(
|
||||
t,
|
||||
strings.contains(dir, "envr-fake-home-envrdir"),
|
||||
@@ -215,19 +164,7 @@ test_envr_dir :: proc(t: ^testing.T) {
|
||||
|
||||
@(test)
|
||||
test_data_encrypted_path :: proc(t: ^testing.T) {
|
||||
sync.mutex_lock(&home_mutex)
|
||||
defer sync.mutex_unlock(&home_mutex)
|
||||
|
||||
old_home := os.get_env("HOME", context.temp_allocator)
|
||||
defer {
|
||||
if old_home != "" {
|
||||
os.set_env("HOME", old_home)
|
||||
}
|
||||
}
|
||||
|
||||
os.set_env("HOME", "/tmp/envr-fake-home-datapath")
|
||||
|
||||
p := data_encrypted_path()
|
||||
p := data_encrypted_path("/tmp/envr-fake-home-datapath/config.json")
|
||||
testing.expectf(t, strings.has_suffix(p, "data.envr"), "should end with data.envr, got %s", p)
|
||||
testing.expectf(t, strings.contains(p, ".envr"), "should contain .envr dir, got %s", p)
|
||||
}
|
||||
@@ -247,9 +184,7 @@ test_search_paths_expands_tilde :: proc(t: ^testing.T) {
|
||||
os.set_env("HOME", "/tmp/envr-fake-home-search")
|
||||
|
||||
cfg := Config {
|
||||
ScanConfig = ScanConfig {
|
||||
Include = make([dynamic]string, 0, 1),
|
||||
},
|
||||
ScanConfig = ScanConfig{Include = make([dynamic]string, 0, 1)},
|
||||
}
|
||||
defer delete(cfg.ScanConfig.Include)
|
||||
append(&cfg.ScanConfig.Include, "~")
|
||||
|
||||
12
db.odin
12
db.odin
@@ -48,13 +48,13 @@ make_temp_path :: proc() -> string {
|
||||
return strings.to_string(b)
|
||||
}
|
||||
|
||||
db_open :: proc() -> (Db, bool) {
|
||||
cfg, ok := load_config()
|
||||
db_open :: proc(cfg_path: string) -> (Db, bool) {
|
||||
cfg, ok := load_config(cfg_path)
|
||||
if !ok {
|
||||
return Db{}, false
|
||||
}
|
||||
|
||||
data_path := data_encrypted_path()
|
||||
data_path := data_encrypted_path(cfg.config_path)
|
||||
_, stat_err := os.stat(data_path, context.allocator)
|
||||
|
||||
db: ^rawptr
|
||||
@@ -108,8 +108,8 @@ db_close :: proc(d: ^Db) {
|
||||
return
|
||||
}
|
||||
|
||||
data_path := data_encrypted_path()
|
||||
envr_d := envr_dir()
|
||||
data_path := data_encrypted_path(d.cfg.config_path)
|
||||
envr_d := envr_dir(d.cfg.config_path)
|
||||
os.mkdir_all(envr_d)
|
||||
|
||||
write_err := os.write_entire_file(data_path, encrypted)
|
||||
@@ -186,7 +186,7 @@ db_vacuum_to_file :: proc(db: ^rawptr, path: string) -> bool {
|
||||
}
|
||||
|
||||
db_restore_from_encrypted :: proc(db: ^rawptr, cfg: Config) -> bool {
|
||||
data_path := data_encrypted_path()
|
||||
data_path := data_encrypted_path(cfg.config_path)
|
||||
encrypted_data, read_err := os.read_entire_file_from_path(data_path, context.temp_allocator)
|
||||
if read_err != nil {
|
||||
fmt.printf("Error reading encrypted database: %v\n", read_err)
|
||||
|
||||
Reference in New Issue
Block a user