diff --git a/.omo/evidence/task-26-tofu-core.log b/.omo/evidence/task-26-tofu-core.log index 711553c..0dee1e0 100644 --- a/.omo/evidence/task-26-tofu-core.log +++ b/.omo/evidence/task-26-tofu-core.log @@ -152,3 +152,32 @@ install failed: conflict detectedtestpkg-2.1 is already installed -- use -ReProv Up-to-date toml 1.0.0: target for configuration [library] is up to date. Up-to-date tofu ~main: target for configuration [application] is up to date. Finished To force a rebuild of up-to-date targets, run again with --force + ok build plan: 1 packages +==> generating build plan + - + libfoo (recipe) + - + mypkg (recipe) + ok build plan: 2 packages +23 modules passed unittests +=== Re-verification after crash fix === +--- rm -rf ~/.cache/tofu && ./tofu --help --- +tofu — ZUUR package manager +Usage: tofu [arg] [flags] +Commands: + -S Install package from ZUUR recipes + -Ss Search ZUUR + -Syu Upgrade installed packages + -R Remove package + -Si Show package info + -h, --help Show this help +Flags: + --noconfirm Skip confirmation prompts + --dry-run Show what would happen without doing it + --force Overwrite existing builds + -j Parallel build jobs + +EXIT: 0 +--- ./tofu (no args) --- +error no command given (run 'tofu --help') +EXIT: 0 +--- dub test result --- +23 modules passed unittests diff --git a/src/tofu/errors.d b/src/tofu/errors.d index 7190b13..22d5652 100644 --- a/src/tofu/errors.d +++ b/src/tofu/errors.d @@ -22,7 +22,7 @@ import tofu.config : ConfigException; import tofu.cli : CliException; import std.process : thisProcessID; -import std.file : exists, readText, write, remove; +import std.file : exists, readText, write, remove, mkdirRecurse; import std.path : buildPath; import std.conv : to, ConvException; import std.stdio : stderr; @@ -187,6 +187,22 @@ private @trusted void removeLockFile(string path) catch (Exception) {} } +/// Ensure the cache directory exists, creating it if necessary. +/// Idempotent — `mkdirRecurse` succeeds if the directory already exists. +private @trusted void ensureCacheDir(string cacheDir) +{ + try + { + mkdirRecurse(cacheDir); + } + catch (Exception e) + { + // Permission denied, path isn't a directory, etc. + throw new LockException( + "cannot create cache directory " ~ cacheDir ~ ": " ~ e.msg); + } +} + // ──────────────────────────────────────────────────────────── // PID-liveness check // ──────────────────────────────────────────────────────────── @@ -267,6 +283,10 @@ private @safe string lockPath(string cacheDir) { import tofu.log : logWarn; + // Ensure the cache directory exists before writing the lock file. + // On a fresh system ~/.cache/tofu may not exist yet. + ensureCacheDir(cacheDir); + auto path = lockPath(cacheDir); auto myPid = thisProcessID.to!string;