package infra import ( "fmt" "os" "path/filepath" ) // ResolveRegistryRoot returns the absolute path of the fn_registry root // (the directory that contains registry.db), or an error if not found. // // Resolution order: // 1. FN_REGISTRY_ROOT env var — if set and /registry.db exists, return it. // 2. Walk up from the executable's directory — up to 6 levels; first dir // that contains registry.db wins. Covers binaries at /fn and at // /apps//. // 3. $HOME/fn_registry — if <$HOME>/fn_registry/registry.db exists. // 4. Error — no method found a valid registry root. func ResolveRegistryRoot() (string, error) { // 1. Env var if envDir := os.Getenv("FN_REGISTRY_ROOT"); envDir != "" { if nonEmptyFile(filepath.Join(envDir, "registry.db")) { return filepath.Clean(envDir), nil } } // 2. Walk up from executable if exe, err := os.Executable(); err == nil { dir := filepath.Dir(exe) for i := 0; i < 6; i++ { if nonEmptyFile(filepath.Join(dir, "registry.db")) { return dir, nil } parent := filepath.Dir(dir) if parent == dir { // Reached filesystem root break } dir = parent } } // 3. $HOME/fn_registry if home, err := os.UserHomeDir(); err == nil { candidate := filepath.Join(home, "fn_registry") if nonEmptyFile(filepath.Join(candidate, "registry.db")) { return candidate, nil } } return "", fmt.Errorf("resolve_registry_root: no se encontro registry.db (set FN_REGISTRY_ROOT)") } // nonEmptyFile reports whether path is an existing, non-empty regular file. // A zero-byte registry.db — which sql.Open silently creates when handed a // mis-resolved path — must NOT count as a valid registry root, otherwise such // a shadow file would hijack the walk-up and mask the real database. func nonEmptyFile(path string) bool { fi, err := os.Stat(path) return err == nil && fi.Mode().IsRegular() && fi.Size() > 0 }