Merge branch 'claude/dependency-notes': a library's AGENTS.consumer.md in its consumers' AGENTS.md
All checks were successful
Flatpak / flatpak (push) Successful in 12m18s
All checks were successful
Flatpak / flatpak (push) Successful in 12m18s
Brings in dependency notes: a crafter-build project that ships an AGENTS.consumer.md beside its project.cpp has it kept in a marked section of each consumer's AGENTS.md, refreshed by `crafter-build` and `crafter-build test`, chosen by cfg.dependencyNotes (Transitive, Direct, None). The new partition is Crafter.Build:Agents; the loader records where each GitProject and LocalProject came from and what a project file's pragmas resolved to. The branch started before master's four external-fetch commits. Both touch External.cpp, the Clang partition, project.cpp, README.md and AGENTS.md, but in different places, so the merge needed no hand reconciliation; the merged tree passes build.sh, the self-host build, format --check and the test suite. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
cc0a6aed8c
29 changed files with 1238 additions and 19 deletions
|
|
@ -324,6 +324,10 @@ ExternalBuildResult Crafter::ExternalOutputs(const ExternalDependency& dep, std:
|
|||
namespace {
|
||||
std::mutex ProjectCacheMutex;
|
||||
std::unordered_map<std::string, std::unique_ptr<Configuration>> ProjectCache;
|
||||
// Keyed by the Configurations ProjectCache owns, which live as long as
|
||||
// the process does, so the pointers never dangle. Guarded by
|
||||
// ProjectCacheMutex as well.
|
||||
std::unordered_map<const Configuration*, LoadedProject> LoadedProjects;
|
||||
|
||||
// Run the dep's project.cpp from its own directory so its relative paths
|
||||
// (cfg.path = "./", interfaces/, lib/, ...) resolve against the dep
|
||||
|
|
@ -353,6 +357,36 @@ namespace {
|
|||
for (Shader& s : cfg.shaders) s.path = abs(s.path);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
// Into ProjectCache under `fullHash`, with `loaded` recorded beside it.
|
||||
// When another thread stored the same spec first, its Configuration
|
||||
// wins and `cfg` is dropped.
|
||||
Configuration* StoreProject(std::string fullHash, Configuration cfg, LoadedProject loaded) {
|
||||
std::lock_guard lock(ProjectCacheMutex);
|
||||
if (auto it = ProjectCache.find(fullHash); it != ProjectCache.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
auto stored = std::make_unique<Configuration>(std::move(cfg));
|
||||
Configuration* ptr = stored.get();
|
||||
ProjectCache.emplace(std::move(fullHash), std::move(stored));
|
||||
LoadedProjects.emplace(ptr, std::move(loaded));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// `url` as it names a repository: without user info, which is where a
|
||||
// token goes, and without trailing slashes or ".git", so specs that only
|
||||
// spell the repository differently name the same one.
|
||||
std::string RepositoryKey(std::string_view url) {
|
||||
std::string key(url);
|
||||
if (const std::size_t scheme = key.find("://"); scheme != std::string::npos) {
|
||||
const std::size_t host = scheme + 3;
|
||||
const std::size_t at = key.rfind('@', key.find('/', host));
|
||||
if (at != std::string::npos && at >= host) key.erase(host, at + 1 - host);
|
||||
}
|
||||
while (key.ends_with('/')) key.pop_back();
|
||||
if (key.ends_with(".git")) key.resize(key.size() - 4);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
Configuration* Crafter::GitProject(const GitProjectSpec& spec) {
|
||||
|
|
@ -405,14 +439,13 @@ Configuration* Crafter::GitProject(const GitProjectSpec& spec) {
|
|||
std::vector<std::string_view> argViews(spec.args.begin(), spec.args.end());
|
||||
Configuration cfg = LoadProjectFromRoot(projectPath, cloneDir, argViews);
|
||||
|
||||
std::lock_guard lock(ProjectCacheMutex);
|
||||
if (auto it = ProjectCache.find(fullHash); it != ProjectCache.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
auto stored = std::make_unique<Configuration>(std::move(cfg));
|
||||
Configuration* ptr = stored.get();
|
||||
ProjectCache.emplace(std::move(fullHash), std::move(stored));
|
||||
return ptr;
|
||||
const fs::path projectInRepo = spec.projectFile.lexically_normal();
|
||||
const fs::path below = projectInRepo.parent_path();
|
||||
return StoreProject(std::move(fullHash), std::move(cfg), {
|
||||
.projectFile = projectPath.lexically_normal(),
|
||||
.name = below.empty() ? name : std::format("{}/{}", name, below.generic_string()),
|
||||
.identity = std::format("git|{}|{}", RepositoryKey(spec.source.url), projectInRepo.generic_string()),
|
||||
});
|
||||
}
|
||||
|
||||
fs::path Crafter::GitFetch(const GitSource& source) {
|
||||
|
|
@ -467,12 +500,15 @@ Configuration* Crafter::LocalProject(const LocalProjectSpec& spec) {
|
|||
std::vector<std::string_view> argViews(spec.args.begin(), spec.args.end());
|
||||
Configuration cfg = LoadProjectFromRoot(canonical, depRoot, argViews);
|
||||
|
||||
std::lock_guard lock(ProjectCacheMutex);
|
||||
if (auto it = ProjectCache.find(fullHash); it != ProjectCache.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
auto stored = std::make_unique<Configuration>(std::move(cfg));
|
||||
Configuration* ptr = stored.get();
|
||||
ProjectCache.emplace(std::move(fullHash), std::move(stored));
|
||||
return ptr;
|
||||
return StoreProject(std::move(fullHash), std::move(cfg), {
|
||||
.projectFile = canonical,
|
||||
.name = depRoot.filename().string(),
|
||||
.identity = std::format("local|{}", canonical.string()),
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<LoadedProject> Crafter::LoadedProjectOf(const Configuration& cfg) {
|
||||
std::lock_guard lock(ProjectCacheMutex);
|
||||
if (auto it = LoadedProjects.find(&cfg); it != LoadedProjects.end()) return it->second;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue