forked from lix-project/lix
WIP: fix flake file not found for untracked files in git
Still WIP, because the installables code is disasteriously duplicated.
So far this implements for:
- nix build
- nix search
- nix flake show
Change-Id: I3196720c2a458b7dab8d969ae1b04b3a7d29869b
This commit is contained in:
parent
3b43fabe97
commit
22759fa6b2
|
@ -1,6 +1,7 @@
|
|||
#include "globals.hh"
|
||||
#include "installable-flake.hh"
|
||||
#include "installable-derived-path.hh"
|
||||
#include "logging.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "util.hh"
|
||||
#include "command.hh"
|
||||
|
@ -25,6 +26,61 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
[[nodiscard]] FileError handleGitTrackError(
|
||||
FileError && fileError,
|
||||
FlakeRef const & flakeRef,
|
||||
flake::LockedFlake const & lockedFlake
|
||||
)
|
||||
{
|
||||
// TODO(Qyriad): do the same thing for other supported VCSes
|
||||
auto const isGit = flakeRef.input.getType() == "git";
|
||||
bool const isNotFound = fileError.errNo == ENOENT;
|
||||
bool const unhelpfulSource =
|
||||
!flakeRef.input.getSourcePath() || !lockedFlake.flake.sourceInfo;
|
||||
if (!isGit || !isNotFound || unhelpfulSource || fileError.referencedPaths.size() != 1) {
|
||||
// If this flake isn't a Git flake or doesn't have a source path,
|
||||
// or if this error is something other than ENOENT, *or* if ENOENT
|
||||
// is about more than one path (or if we have no path information at all),
|
||||
// then we don't have any helpful hints to add. Rethrow.
|
||||
throw;
|
||||
}
|
||||
|
||||
// Otherwise, get the path of the missing file as relative to the flake source tree,
|
||||
// instead of the Nix store.
|
||||
|
||||
// The full path that got ENOENT'd.
|
||||
auto const missingStorePath = fileError.referencedPaths.front();
|
||||
|
||||
// Directory of the original flake.nix (outside the Nix store).
|
||||
auto const flakeSourceDir = *flakeRef.input.getSourcePath();
|
||||
|
||||
// Nix store directory containing the fetched flake.
|
||||
// to_string() returns the path without the /nix/store part.
|
||||
auto const flakeStoreDir = lockedFlake.flake.sourceInfo->storePath.to_string();
|
||||
|
||||
if (missingStorePath.find(flakeStoreDir) == missingStorePath.npos) {
|
||||
// The mising path isn't in the flake source tree. We have no helpful
|
||||
// information to offer.
|
||||
throw;
|
||||
}
|
||||
|
||||
// Strip the root path in the store (e.g. c8kjkvxfq9pfwd4832ishyl2mpw4l58y-source).
|
||||
auto const amountToStrip = missingStorePath.find(flakeStoreDir) + flakeStoreDir.size();
|
||||
auto const origSrcPath = flakeSourceDir + missingStorePath.substr(amountToStrip);
|
||||
if (!pathExists(origSrcPath)) {
|
||||
throw;
|
||||
}
|
||||
ErrorInfo existingInfo(std::move(fileError.info()));
|
||||
existingInfo.msg = HintFmt(
|
||||
"%1%\nnote: '%2%' found in original source; did you run git add?",
|
||||
Uncolored(existingInfo.msg),
|
||||
origSrcPath
|
||||
);
|
||||
auto withTip = FileError(fileError.errNo, std::move(fileError.referencedPaths), "");
|
||||
withTip.err = existingInfo;
|
||||
return withTip;
|
||||
}
|
||||
|
||||
std::vector<std::string> InstallableFlake::getActualAttrPaths()
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
@ -94,6 +150,15 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
|||
|
||||
auto attrPath = attr->getAttrPathStr();
|
||||
|
||||
try {
|
||||
// Evaluate here, instead of as a side effect of isDerivation(),
|
||||
// for clarity of error handling.
|
||||
attr->forceValue();
|
||||
} catch (FileError & e) {
|
||||
e.addTrace({}, "in source tree referenced by flake %s", flakeRef);
|
||||
throw handleGitTrackError(std::move(e), flakeRef, *_lockedFlake);
|
||||
}
|
||||
|
||||
if (!attr->isDerivation()) {
|
||||
|
||||
// FIXME: use eval cache?
|
||||
|
@ -162,7 +227,12 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
|
|||
|
||||
std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
|
||||
{
|
||||
return {&getCursor(state)->forceValue(), noPos};
|
||||
try {
|
||||
return {&getCursor(state)->forceValue(), noPos};
|
||||
} catch (FileError & e) {
|
||||
e.addTrace({}, "in source tree referenced by flake %s", flakeRef);
|
||||
throw handleGitTrackError(std::move(e), flakeRef, *_lockedFlake);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ref<eval_cache::AttrCursor>>
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
[[nodiscard]] FileError handleGitTrackError(
|
||||
FileError && fileError,
|
||||
FlakeRef const & flakeRef,
|
||||
flake::LockedFlake const & lockedFlake
|
||||
);
|
||||
|
||||
/**
|
||||
* Extra info about a \ref DerivedPath "derived path" that ultimately
|
||||
* come from a Flake.
|
||||
|
|
|
@ -1357,9 +1357,14 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
|
|||
|
||||
auto cache = openEvalCache(*state, flake);
|
||||
|
||||
auto j = visit(*cache->getRoot(), {}, fmt(ANSI_BOLD "%s" ANSI_NORMAL, flake->flake.lockedRef), "");
|
||||
if (json)
|
||||
logger->cout("%s", j.dump());
|
||||
try {
|
||||
auto j = visit(*cache->getRoot(), {}, fmt(ANSI_BOLD "%s" ANSI_NORMAL, flake->flake.lockedRef), "");
|
||||
if (json) {
|
||||
logger->cout("%s", j.dump());
|
||||
}
|
||||
} catch (FileError & e) {
|
||||
throw handleGitTrackError(std::move(e), flake->flake.originalRef, *flake);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "eval.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "eval-settings.hh"
|
||||
#include "installable-flake.hh"
|
||||
#include "names.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "common-args.hh"
|
||||
|
@ -108,6 +109,22 @@ struct CmdSearch : InstallableValueCommand, MixJSON
|
|||
}
|
||||
};
|
||||
|
||||
// If this is a flake, let's try to be helpful and add a tip if eval
|
||||
// ends up tripping over an untracked file in git.
|
||||
if (auto instFlake = installable.dynamic_pointer_cast<InstallableFlake>()) {
|
||||
try {
|
||||
// nb: isDerivation() below also does this as a side effect.
|
||||
cursor.forceValue();
|
||||
} catch (FileError & e) {
|
||||
e.addTrace({}, "in source tree referenced by flake %s", instFlake->flakeRef);
|
||||
throw handleGitTrackError(
|
||||
std::move(e),
|
||||
instFlake->flakeRef,
|
||||
*instFlake->_lockedFlake
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor.isDerivation()) {
|
||||
DrvName name(cursor.getAttr(state->sName)->getString());
|
||||
|
||||
|
|
Loading…
Reference in a new issue