Packages are now considered broken if any required packages are broken,
and problems are reported for required packages as well.
vector<string> Builder::collect_problems() const
{
vector<string> Builder::collect_problems() const
{
+ vector<string> target_problems;
- set<const Package *> broken_packages;
- set<const Component *> broken_components;
- set<const Tool *> broken_tools;
+ vector<const Package *> broken_packages;
+ vector<const Component *> broken_components;
+ vector<const Tool *> broken_tools;
for(const auto &kvp: build_graph.get_targets())
if(kvp.second->is_broken())
{
for(const auto &kvp: build_graph.get_targets())
if(kvp.second->is_broken())
{
- for(const string &p: kvp.second->get_problems())
- problems.push_back(format("%s: %s", kvp.second->get_name(), p));
-
const Package *package = kvp.second->get_package();
const Package *package = kvp.second->get_package();
- if(package && !package->get_problems().empty())
- broken_packages.insert(package);
+ if(package && package->is_broken())
+ collect_broken_packages(*package, broken_packages);
const Component *component = kvp.second->get_component();
const Component *component = kvp.second->get_component();
- if(component && !component->get_problems().empty())
- broken_components.insert(component);
+ if(component && component->is_broken() && !any_equals(broken_components, component))
+ {
+ broken_components.push_back(component);
+ collect_broken_packages(component->get_package(), broken_packages);
+ for(const Package *r: component->get_required_packages())
+ if(r->is_broken())
+ collect_broken_packages(*r, broken_packages);
+ }
const Tool *tool = kvp.second->get_tool();
const Tool *tool = kvp.second->get_tool();
- if(tool && !tool->get_problems().empty())
- broken_tools.insert(tool);
+ if(tool && tool->is_broken() && !any_equals(broken_tools, tool))
+ {
+ broken_tools.push_back(tool);
+ for(const string &p: tool->get_problems())
+ problems.push_back(format("%s: %s", tool->get_tag(), p));
+ }
+
+ for(const string &p: kvp.second->get_problems())
+ target_problems.push_back(format("%s: %s", kvp.second->get_name(), p));
- // TODO Sort components after their packages, and targets last
for(const Package *p: broken_packages)
for(const Package *p: broken_packages)
for(const string &b: p->get_problems())
problems.push_back(format("%s: %s", p->get_name(), b));
for(const string &b: p->get_problems())
problems.push_back(format("%s: %s", p->get_name(), b));
- for(const Component *c: broken_components)
- for(const string &b: c->get_problems())
- problems.push_back(format("%s/%s: %s", c->get_package().get_name(), c->get_name(), b));
+ for(const Component *c: broken_components)
+ if(&c->get_package()==p)
+ {
+ for(const string &b: c->get_problems())
+ problems.push_back(format("%s/%s: %s", p->get_name(), c->get_name(), b));
+ }
+ }
- for(const Tool *t: broken_tools)
- for(const string &b: t->get_problems())
- problems.push_back(format("%s: %s", t->get_tag(), b));
+ problems.insert(problems.end(), make_move_iterator(target_problems.begin()), make_move_iterator(target_problems.end()));
+void Builder::collect_broken_packages(const Package &pkg, vector<const Package *> &broken) const
+{
+ if(any_equals(broken, &pkg))
+ return;
+
+ broken.push_back(&pkg);
+
+ for(const Package *r: pkg.get_required_packages())
+ if(r->is_broken())
+ collect_broken_packages(*r, broken);
+}
+
void Builder::load_build_file(const FS::Path &fn, const Config::InputOptions *opts, bool all)
{
IO::BufferedFile in(fn.str());
void Builder::load_build_file(const FS::Path &fn, const Config::InputOptions *opts, bool all)
{
IO::BufferedFile in(fn.str());
const Logger &get_logger() const { return *logger; }
std::vector<std::string> collect_problems() const;
const Logger &get_logger() const { return *logger; }
std::vector<std::string> collect_problems() const;
+private:
+ void collect_broken_packages(const Package &, std::vector<const Package *> &) const;
/** Loads a build file. If opts is not null, it is used to configure any
packages loaded from this file. If all is true, external packages are also
configured. */
/** Loads a build file. If opts is not null, it is used to configure any
packages loaded from this file. If all is true, external packages are also
configured. */
void Component::prepare()
{
for(Package *r: requires)
void Component::prepare()
{
for(Package *r: requires)
+ broken |= r->is_broken();
+ }
+
+ if(!problems.empty())
+ broken = true;
}
void Component::create_build_info()
}
void Component::create_build_info()
Package::Requirements requires;
bool deflt = true;
InstallMap install_map;
Package::Requirements requires;
bool deflt = true;
InstallMap install_map;
std::vector<std::string> problems;
Component(SourcePackage &p, const std::string &n): package(p), name(n) { }
std::vector<std::string> problems;
Component(SourcePackage &p, const std::string &n): package(p), name(n) { }
const InstallMap &get_install_map() const { return install_map; }
const Package::Requirements &get_required_packages() const { return requires; }
bool is_default() const { return deflt; }
const InstallMap &get_install_map() const { return install_map; }
const Package::Requirements &get_required_packages() const { return requires; }
bool is_default() const { return deflt; }
+ bool is_broken() const { return broken; }
const std::vector<std::string> &get_problems() const { return problems; }
/** Prepares any required packages. */
const std::vector<std::string> &get_problems() const { return problems; }
/** Prepares any required packages. */
prepared = true;
for(Package *r: requires)
prepared = true;
for(Package *r: requires)
+ broken |= r->is_broken();
+ }
+ broken |= !problems.empty();
Requirements requires;
BuildInfo export_binfo;
bool prepared = false;
Requirements requires;
BuildInfo export_binfo;
bool prepared = false;
std::vector<std::string> problems;
bool use_pkgconfig = true;
std::vector<std::string> problems;
bool use_pkgconfig = true;
public:
bool is_prepared() const { return prepared; }
public:
bool is_prepared() const { return prepared; }
+ bool is_broken() const { return broken; }
const std::vector<std::string> &get_problems() const { return problems; }
virtual void save_caches() { }
const std::vector<std::string> &get_problems() const { return problems; }
virtual void save_caches() { }
{
if(FileTarget *tool_exe = tool->get_executable())
add_dependency(*tool_exe);
{
if(FileTarget *tool_exe = tool->get_executable())
add_dependency(*tool_exe);
- broken |= !tool->get_problems().empty();
+ broken |= tool->is_broken();
- // Only check package and component problems for buildable targets
- // XXX How to propagate nested package problems?
- broken |= (package && !package->get_problems().empty());
- broken |= (component && !component->get_problems().empty());
+ // Only check package and component brokenness for buildable targets
+ broken |= (package && package->is_broken());
+ broken |= (component && component->is_broken());
}
/* Now that all dependencies are known, prepare them again. This will do
}
/* Now that all dependencies are known, prepare them again. This will do
virtual void do_prepare(ToolData &) const { }
public:
virtual void do_prepare(ToolData &) const { }
public:
+ bool is_broken() const { return !problems.empty(); }
const std::vector<std::string> &get_problems() const { return problems; }
/** Invokes the tool to build a target. This should not be called directly;
const std::vector<std::string> &get_problems() const { return problems; }
/** Invokes the tool to build a target. This should not be called directly;