-#include <cstdlib>
-#include <msp/fs/dir.h>
-#include <msp/fs/stat.h>
-#include <msp/fs/utils.h>
-#include <msp/io/print.h>
-#include <msp/strings/format.h>
-#include <msp/strings/utils.h>
-#include <msp/time/units.h>
-#include <msp/time/utils.h>
-#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),
- main_pkg(0),
- env_set(false)
-{ }
-
-PackageManager::~PackageManager()
-{
- for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
- delete i->second;
-}
-
-void PackageManager::append_package_path(const FS::Path &p)
-{
- pkg_path.push_back(p);
-}
-
-void PackageManager::append_binary_package_path(const FS::Path &p)
-{
- binpkg_path.push_back(p);
-}
-
-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");
- }
-
- if(packages.empty())
- main_pkg = pkg;
-
- packages.insert(PackageMap::value_type(pkg->get_name(), pkg));
-}
-
-Package *PackageManager::get_package(const string &name) const
-{
- PackageMap::const_iterator i = packages.find(name);
- if(i!=packages.end())
- return i->second;
-
- return 0;
-}
-
-Package &PackageManager::get_main_package() const
-{
- if(!main_pkg)
- throw logic_error("No packages");
- return *main_pkg;
-}
-
-Package *PackageManager::find_package(const string &name)
-{
- if(not_found.count(name))
- return 0;
-
- if(Package *pkg = get_package(name))
- return pkg;
-
- if(!no_externals)
- {
- FS::Path path = get_package_location(name);
- if(!path.empty())
- {
- builder.load_build_file(path/"Build");
- PackageMap::iterator i = packages.find(name);
- if(i!=packages.end())
- return i->second;
- }
- }
-
- FS::Path path = get_binary_package_file(name);
- if(!path.empty())
- {
- builder.load_build_file(path);
- if(Package *pkg = get_package(name))
- return pkg;
- }
-
- try
- {
- // Package source not found - create a binary package
- string flags_str = run_pkgconfig(name, "flags");
- BinaryPackage::Flags flags = split(flags_str);
- flags_str = run_pkgconfig(name, "staticflags");
- BinaryPackage::Flags static_flags = split(flags_str);
- Package *pkg = BinaryPackage::from_flags(builder, name, flags, static_flags);
- packages.insert(PackageMap::value_type(name, pkg));
- return pkg;
- }
- catch(...)
- {
- not_found.insert(name);
- return 0;
- }
-}
-
-string PackageManager::run_pkgconfig(const string &pkg, const string &what)
-{
- if(!env_set)
- {
- const FS::Path &prefix = builder.get_prefix();
- if(prefix.str()!="/usr")
- {
- FS::Path pcdir = prefix/"lib/pkgconfig";
- if(const char *pcp = getenv("PKG_CONFIG_PATH"))
- {
- vector<string> path = split(pcp, ':');
- bool found = false;
- for(vector<string>::const_iterator i=path.begin(); (!found && i!=path.end()); ++i)
- found = (*i==pcdir.str());
- if(!found)
- {
- path.push_back(pcdir.str());
- setenv("PKG_CONFIG_PATH", join(path.begin(), path.end(), ":").c_str(), true);
- }
- }
- else
- setenv("PKG_CONFIG_PATH", pcdir.str().c_str(), true);
- }
- }
-
- ExternalTask::Arguments argv;
- argv.push_back("pkg-config");
- if(what=="cflags" || what=="libs")
- argv.push_back("--"+what);
- else if(what=="flags" || what=="staticflags")
- {
- argv.push_back("--cflags");
- argv.push_back("--libs");
- if(what=="staticflags")
- argv.push_back("--static");
- }
- else
- argv.push_back("--variable="+what);
- argv.push_back(pkg);
-
- builder.get_logger().log("auxcommands", format("Running %s", join(argv.begin(), argv.end())));
-
- return ExternalTask::run_and_capture_output(argv);
-}
-
-FS::Path PackageManager::get_package_location(const string &name)
-{
- builder.get_logger().log("packagemgr", format("Looking for source package %s", name));
-
- try
- {
- // Try to get source directory with pkgconfig
- string srcdir = strip(run_pkgconfig(name, "source"));
- if(!srcdir.empty() && FS::exists(FS::Path(srcdir)/"Build"))
- return srcdir;
- }
- catch(...)
- { }
-
- if(pkg_dirs.empty())
- {
- for(SearchPath::const_iterator i=pkg_path.begin(); i!=pkg_path.end(); ++i)
- {
- builder.get_logger().log("files", format("Traversing %s", *i));
- list<string> files = list_files(*i);
- unsigned count = 0;
- for(list<string>::const_iterator j=files.begin(); j!=files.end(); ++j)
- {
- FS::Path full = *i / *j;
- if(FS::exists(full/"Build"))
- {
- pkg_dirs.push_back(full);
- ++count;
- }
- }
-
- builder.get_logger().log("packagemgr", format("%d source packages found in %s", count, *i));
- }
-
- builder.get_logger().log("packagemgr", format("%d source packages found", pkg_dirs.size()));
- }
-
- bool msp = !name.compare(0, 3, "msp");
- for(SearchPath::const_iterator i=pkg_dirs.begin(); i!=pkg_dirs.end(); ++i)
- {
- string base = FS::basename(*i);
- unsigned dash = base.rfind('-');
-
- if(!base.compare(0, dash, name))
- return *i;
- else if(msp && !base.compare(0, dash, name, 3, string::npos))
- return *i;
- }
-
- return FS::Path();
-}
-
-FS::Path PackageManager::get_binary_package_file(const string &name)
-{
- builder.get_logger().log("packagemgr", format("Looking for binary package %s", name));
-
- if(binpkg_files.empty())
- {
- for(list<FS::Path>::const_iterator i=binpkg_path.begin(); i!=binpkg_path.end(); ++i)
- {
- builder.get_logger().log("files", format("Traversing %s", *i));
- list<string> files = list_filtered(*i, "\\.bpk$");
- for(list<string>::const_iterator j=files.begin(); j!=files.end(); ++j)
- binpkg_files.push_back(*i / *j);
- builder.get_logger().log("packagemgr", format("%d binary packages found in %s", files.size(), *i));
- }
-
- builder.get_logger().log("packagemgr", format("%d binary packages found", binpkg_files.size()));
- }
-
- for(SearchPath::const_iterator i=binpkg_files.begin(); i!=binpkg_files.end(); ++i)
- {
- string base = FS::basepart(FS::basename(*i));
- if(base==name)
- return *i;
- }
-
- return FS::Path();
-}
-
-void PackageManager::save_all_caches() const
-{
- for(PackageMap::const_iterator i=packages.begin(); i!=packages.end(); ++i)
- i->second->save_caches();
-}