From: Mikko Rasa Date: Sat, 23 Jun 2012 18:50:13 +0000 (+0300) Subject: Move package management to a separate class X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=1d687970cc35e54c3335f4aa2fdef23424fe0a06;p=builder.git Move package management to a separate class --- diff --git a/source/binarypackage.cpp b/source/binarypackage.cpp index bc3e5c9..8c3571d 100644 --- a/source/binarypackage.cpp +++ b/source/binarypackage.cpp @@ -29,15 +29,12 @@ void BinaryPackage::create_build_info() *i = (path/i->substr(1)).str(); } -BinaryPackage *BinaryPackage::from_pkgconfig(Builder &builder, const string &name) +BinaryPackage *BinaryPackage::from_flags(Builder &builder, const std::string &name, const vector &flags) { - string info = builder.run_pkgconfig(name, "flags"); - BinaryPackage *pkg = new BinaryPackage(builder, name); pkg->use_pkgconfig = true; BuildInfo &binfo = pkg->export_binfo; - vector flags = split(info); for(vector::const_iterator i=flags.begin(); i!=flags.end(); ++i) { if(!i->compare(0, 2, "-I")) diff --git a/source/binarypackage.h b/source/binarypackage.h index ff077f8..8c0d0e9 100644 --- a/source/binarypackage.h +++ b/source/binarypackage.h @@ -34,7 +34,7 @@ public: bool get_need_path() const { return need_path; } - static BinaryPackage *from_pkgconfig(Builder &, const std::string &); + static BinaryPackage *from_flags(Builder &, const std::string &, const std::vector &); private: virtual void create_build_info(); }; diff --git a/source/builder.cpp b/source/builder.cpp index 2c28b79..393cfc5 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -17,7 +17,6 @@ #include "binarypackage.h" #include "builder.h" #include "copy.h" -#include "externaltask.h" #include "gnuarchiver.h" #include "gnuccompiler.h" #include "gnucxxcompiler.h" @@ -35,6 +34,7 @@ using namespace std; using namespace Msp; Builder::Builder(int argc, char **argv): + package_manager(*this), main_pkg(0), native_arch(*this, string()), vfs(*this), @@ -59,6 +59,7 @@ Builder::Builder(int argc, char **argv): StringList cmdline_warn; string prfx; string arch; + bool no_externals = false; GetOpt getopt; getopt.add_option('a', "analyze", analyze_mode, GetOpt::REQUIRED_ARG).set_help("Perform analysis. MODE can be deps, alldeps or rebuild.", "MODE"); @@ -124,6 +125,8 @@ Builder::Builder(int argc, char **argv): cwd = FS::getcwd(); + package_manager.set_no_externals(no_externals); + load_build_file((FS::get_sys_data_dir(argv[0], "builder")/"builderrc").str()); load_build_file((FS::get_user_data_dir("builder")/"rc").str()); @@ -170,15 +173,10 @@ Builder::Builder(int argc, char **argv): vector warns = split(*i, ','); warnings.insert(warnings.end(), warns.begin(), warns.end()); } - - pkg_path.push_back(cwd/"."); - pkg_path.push_back(cwd/".."); } Builder::~Builder() { - for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) - delete i->second; for(TargetMap::iterator i=targets.begin(); i!=targets.end(); ++i) delete i->second; delete analyzer; @@ -244,8 +242,9 @@ int Builder::main() if(verbose>=1) { + const PackageManager::PackageMap &packages = package_manager.get_packages(); unsigned n_packages = 0; - for(PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) + for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) if(i->second && i->second->is_configured()) ++n_packages; IO::print("%d active packages, %d targets\n", n_packages, targets.size()); @@ -253,7 +252,8 @@ int Builder::main() if(verbose>=2) { - for(PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) + const PackageManager::PackageMap &packages = package_manager.get_packages(); + for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) { if(!i->second->is_configured()) continue; @@ -302,72 +302,6 @@ int Builder::main() return exit_code; } -string Builder::run_pkgconfig(const string &pkg, const string &what) -{ - ExternalTask::Arguments argv; - argv.push_back("pkg-config"); - if(what=="cflags" || what=="libs") - argv.push_back("--"+what); - else if(what=="flags") - { - argv.push_back("--cflags"); - argv.push_back("--libs"); - } - else - argv.push_back("--variable="+what); - argv.push_back(pkg); - - if(verbose>=4) - IO::print("Running %s\n", join(argv.begin(), argv.end())); - - ExternalTask task(argv); - task.set_stdout(ExternalTask::CAPTURE); - task.set_stderr(ExternalTask::IGNORE); - task.start(); - Task::Status status; - while((status=task.check())==Task::RUNNING) - Time::sleep(10*Time::msec); - if(status==Task::ERROR) - throw runtime_error(format("pkg-config for package %s failed", pkg)); - - return task.get_output(); -} - -Package *Builder::get_package(const string &name) -{ - PackageMap::iterator i = packages.find(format("%s/%s", name, current_arch->get_system())); - if(i==packages.end()) - i = packages.find(name); - if(i!=packages.end()) - return i->second; - - if(!no_externals) - { - FS::Path path = get_package_location(name); - if(!path.empty() && !load_build_file(path/"Build")) - { - i = packages.find(name); - if(i!=packages.end()) - return i->second; - } - } - - Package *pkg = 0; - try - { - // Package source not found - create a binary package - pkg = BinaryPackage::from_pkgconfig(*this, name); - } - catch(...) - { - problem(name, "not found"); - } - - packages.insert(PackageMap::value_type(name, pkg)); - - return pkg; -} - Target *Builder::get_target(const string &n) const { TargetMap::const_iterator i = targets.find(n); @@ -417,52 +351,6 @@ void Builder::usage(const char *reason, const char *argv0, bool brief) } } -FS::Path Builder::get_package_location(const string &name) -{ - if(verbose>=3) - IO::print("Looking for package %s\n", name); - - try - { - // Try to get source directory with pkgconfig - string srcdir = strip(run_pkgconfig(name, "source")); - if(!srcdir.empty()) - return srcdir; - } - catch(...) - { } - - if(pkg_dirs.empty()) - { - for(list::const_iterator i=pkg_path.begin(); i!=pkg_path.end(); ++i) - { - list files = list_files(*i); - for(list::const_iterator j=files.begin(); j!=files.end(); ++j) - { - FS::Path full = *i / *j; - if(FS::exists(full/"Build")) - pkg_dirs.push_back(full); - } - } - if(verbose>=3) - IO::print("%d packages found in path\n", pkg_dirs.size()); - } - - bool msp = !name.compare(0, 3, "msp"); - for(list::const_iterator i=pkg_dirs.begin(); i!=pkg_dirs.end(); ++i) - { - string base = basename(*i); - unsigned dash = base.rfind('-'); - - if(!base.compare(0, dash, name)) - return *i; - else if(msp && !base.compare(0, dash-3, name, 3, string::npos)) - return *i; - } - - return FS::Path(); -} - int Builder::load_build_file(const FS::Path &fn) { if(!FS::exists(fn)) @@ -493,7 +381,8 @@ int Builder::create_targets() Target *tarballs = new VirtualTarget(*this, "tarballs"); world->add_depend(tarballs); - for(PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) + const PackageManager::PackageMap &packages = package_manager.get_packages(); + for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) if(i->second && i->second->is_configured()) i->second->create_targets(); @@ -536,7 +425,7 @@ int Builder::create_targets() i->second->force_rebuild(); } - for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) + for(PackageManager::PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i) if(SourcePackage *spkg = dynamic_cast(i->second)) spkg->get_deps_cache().save(); @@ -703,7 +592,6 @@ void Builder::Loader::binpkg(const string &n) { BinaryPackage *pkg = new BinaryPackage(bld, n); load_sub(*pkg); - bld.packages.insert(PackageMap::value_type(n, pkg)); } void Builder::Loader::cross_prefix(const string &a, const string &p) @@ -726,7 +614,6 @@ void Builder::Loader::package(const string &n) bld.main_pkg = pkg; load_sub(*pkg); - bld.packages.insert(PackageMap::value_type(n, pkg)); } diff --git a/source/builder.h b/source/builder.h index 7a33ab8..99b3804 100644 --- a/source/builder.h +++ b/source/builder.h @@ -10,6 +10,7 @@ #include "architecture.h" #include "config.h" #include "misc.h" +#include "packagemanager.h" #include "problem.h" #include "target.h" #include "toolchain.h" @@ -59,19 +60,14 @@ public: typedef std::list TargetList; private: - typedef std::list PackageList; - typedef std::map PackageMap; typedef std::map ProfileTemplateMap; StringList cmdline_targets; StringMap cmdline_options; Msp::FS::Path cwd; - PackageMap packages; + PackageManager package_manager; SourcePackage *main_pkg; - PathList pkg_path; - PathList pkg_dirs; - bool no_externals; TargetMap targets; TargetList new_tgts; @@ -111,16 +107,10 @@ public: int main(); unsigned get_verbose() const { return verbose; } bool get_dry_run() const { return dry_run; } - bool get_build_all() const { return build_all; } - - /** Gets a package by name, possibly creating it. Returns 0 if the package - could not be located. */ - Package *get_package(const std::string &); + PackageManager &get_package_manager() { return package_manager; } SourcePackage *get_main_package() const { return main_pkg; } - std::string run_pkgconfig(const std::string &, const std::string &); - /** Looks up a target by name. Returns 0 if no such target exists. */ Target *get_target(const std::string &) const; @@ -145,15 +135,11 @@ public: static void usage(const char *, const char *, bool); -private: - /** Determines the source directory of a package. Pkg-config is consulted - first, and if it fails, the package path is searched for matches. */ - Msp::FS::Path get_package_location(const std::string &); - /** Loads a build file. Returns 0 on success or -1 if the file could not be opened. */ int load_build_file(const Msp::FS::Path &); +private: /** Creates targets for all packages and prepares them for building. Returns 0 if everything went ok, -1 if something bad happened and a build shouldn't be attempted. */ diff --git a/source/component.cpp b/source/component.cpp index c4908c9..5c859f7 100644 --- a/source/component.cpp +++ b/source/component.cpp @@ -273,7 +273,7 @@ void Component::Loader::source(const string &s) void Component::Loader::require(const string &n) { - Package *req = comp.pkg.get_builder().get_package(n); + Package *req = comp.pkg.get_builder().get_package_manager().find_package(n); if(req) comp.requires.push_back(req); } diff --git a/source/package.cpp b/source/package.cpp index c4710bc..8a05ddc 100644 --- a/source/package.cpp +++ b/source/package.cpp @@ -13,7 +13,9 @@ Package::Package(Builder &b, const string &n): name(n), conf_done(false), use_pkgconfig(true) -{ } +{ + builder.get_package_manager().add_package(this); +} void Package::configure(const StringMap &opts, unsigned flag) { @@ -45,7 +47,7 @@ Package::Loader::Loader(Package &p): void Package::Loader::require(const string &n) { - Package *req = pkg.builder.get_package(n); + Package *req = pkg.builder.get_package_manager().find_package(n); if(req) pkg.requires.push_back(req); } diff --git a/source/packagemanager.cpp b/source/packagemanager.cpp new file mode 100644 index 0000000..c3d6939 --- /dev/null +++ b/source/packagemanager.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "binarypackage.h" +#include "builder.h" +#include "externaltask.h" +#include "package.h" +#include "packagemanager.h" + +using namespace std; +using namespace Msp; + +PackageManager::PackageManager(Builder &b): + builder(b), + no_externals(false) +{ + pkg_path.push_back(builder.get_cwd()/"."); + pkg_path.push_back(builder.get_cwd()/".."); +} + +PackageManager::~PackageManager() +{ + for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i) + delete i->second; +} + +void PackageManager::set_no_externals(bool x) +{ + no_externals = x; +} + +void PackageManager::add_package(Package *pkg) +{ + PackageMap::iterator i = packages.find(pkg->get_name()); + if(i!=packages.end()) + { + if(i->second!=pkg) + throw invalid_argument("Package name conflict"); + else + throw logic_error("Package is already managed"); + } + + packages.insert(PackageMap::value_type(pkg->get_name(), pkg)); +} + +Package *PackageManager::find_package(const string &name) +{ + PackageMap::iterator i = packages.find(format("%s/%s", name, builder.get_current_arch().get_system())); + if(i==packages.end()) + i = packages.find(name); + if(i!=packages.end()) + return i->second; + + if(!no_externals) + { + FS::Path path = get_package_location(name); + if(!path.empty() && !builder.load_build_file(path/"Build")) + { + i = packages.find(name); + if(i!=packages.end()) + return i->second; + } + } + + Package *pkg = 0; + try + { + // Package source not found - create a binary package + string flags_str = run_pkgconfig(name, "flags"); + vector flags = split(flags_str); + pkg = BinaryPackage::from_flags(builder, name, flags); + } + catch(...) + { + builder.problem(name, "not found"); + } + + packages.insert(PackageMap::value_type(name, pkg)); + + return pkg; +} + +string PackageManager::run_pkgconfig(const string &pkg, const string &what) +{ + ExternalTask::Arguments argv; + argv.push_back("pkg-config"); + if(what=="cflags" || what=="libs") + argv.push_back("--"+what); + else if(what=="flags") + { + argv.push_back("--cflags"); + argv.push_back("--libs"); + } + else + argv.push_back("--variable="+what); + argv.push_back(pkg); + + if(builder.get_verbose()>=4) + IO::print("Running %s\n", join(argv.begin(), argv.end())); + + ExternalTask task(argv); + task.set_stdout(ExternalTask::CAPTURE); + task.set_stderr(ExternalTask::IGNORE); + task.start(); + Task::Status status; + while((status=task.check())==Task::RUNNING) + Time::sleep(10*Time::msec); + if(status==Task::ERROR) + throw runtime_error(format("pkg-config for package %s failed", pkg)); + + return task.get_output(); +} + +FS::Path PackageManager::get_package_location(const string &name) +{ + if(builder.get_verbose()>=3) + IO::print("Looking for package %s\n", name); + + try + { + // Try to get source directory with pkgconfig + string srcdir = strip(run_pkgconfig(name, "source")); + if(!srcdir.empty()) + return srcdir; + } + catch(...) + { } + + if(pkg_dirs.empty()) + { + for(list::const_iterator i=pkg_path.begin(); i!=pkg_path.end(); ++i) + { + list files = list_files(*i); + for(list::const_iterator j=files.begin(); j!=files.end(); ++j) + { + FS::Path full = *i / *j; + if(FS::exists(full/"Build")) + pkg_dirs.push_back(full); + } + } + if(builder.get_verbose()>=3) + IO::print("%d packages found in path\n", pkg_dirs.size()); + } + + bool msp = !name.compare(0, 3, "msp"); + for(list::const_iterator i=pkg_dirs.begin(); i!=pkg_dirs.end(); ++i) + { + string base = basename(*i); + unsigned dash = base.rfind('-'); + + if(!base.compare(0, dash, name)) + return *i; + else if(msp && !base.compare(0, dash-3, name, 3, string::npos)) + return *i; + } + + return FS::Path(); +} diff --git a/source/packagemanager.h b/source/packagemanager.h new file mode 100644 index 0000000..96c3dca --- /dev/null +++ b/source/packagemanager.h @@ -0,0 +1,55 @@ +#ifndef PACKAGEMANAGER_H_ +#define PACKAGEMANAGER_H_ + +#include +#include +#include +#include + +class Builder; +class Package; + +/** +Keeps track of packages. Also responsible for locating previously unknown +packages by name. +*/ +class PackageManager +{ +public: + typedef std::map PackageMap; + +private: + typedef std::list SearchPath; + + Builder &builder; + SearchPath pkg_path; + SearchPath pkg_dirs; + bool no_externals; + PackageMap packages; + +public: + PackageManager(Builder &); + ~PackageManager(); + + void set_no_externals(bool); + + /** Adds a package to the manager. Called from Package constructor. */ + void add_package(Package *); + + /** Returns a package from the cache. */ + Package *get_package(const std::string &); + + const PackageMap &get_packages() const { return packages; } + + /** Locates a package and creates it if necessary. */ + Package *find_package(const std::string &); + +private: + std::string run_pkgconfig(const std::string &, const std::string &); + + /** Determines the source directory of a package. Pkg-config is consulted + first, and if it fails, the package path is searched for matches. */ + Msp::FS::Path get_package_location(const std::string &); +}; + +#endif diff --git a/source/sourcepackage.cpp b/source/sourcepackage.cpp index 246a6db..d66a36f 100644 --- a/source/sourcepackage.cpp +++ b/source/sourcepackage.cpp @@ -143,7 +143,7 @@ void SourcePackage::do_configure(const StringMap &opts, unsigned flag) { const StringList &reqs = i->get_requires(); for(StringList::const_iterator j=reqs.begin(); j!=reqs.end(); ++j) - if(Package *pkg = builder.get_package(*j)) + if(Package *pkg = builder.get_package_manager().find_package(*j)) requires.push_back(pkg); }