2 #include <msp/core/algorithm.h>
3 #include <msp/fs/dir.h>
4 #include <msp/fs/stat.h>
5 #include <msp/fs/utils.h>
6 #include <msp/io/print.h>
7 #include <msp/strings/format.h>
8 #include <msp/strings/utils.h>
9 #include <msp/time/timedelta.h>
10 #include <msp/time/utils.h>
11 #include "binarypackage.h"
13 #include "externaltask.h"
15 #include "packagemanager.h"
20 PackageManager::PackageManager(Builder &b):
27 PackageManager::~PackageManager()
29 for(const auto &kvp: packages)
33 void PackageManager::append_package_path(const FS::Path &p)
35 pkg_path.push_back(p);
38 void PackageManager::append_binary_package_path(const FS::Path &p)
40 binpkg_path.push_back(p);
43 void PackageManager::set_no_externals(bool x)
48 void PackageManager::add_package(Package *pkg)
50 PackageMap::iterator i = packages.find(pkg->get_name());
54 throw invalid_argument("Package name conflict");
56 throw logic_error("Package is already managed");
62 packages.insert(PackageMap::value_type(pkg->get_name(), pkg));
65 Package *PackageManager::get_package(const string &name) const
67 PackageMap::const_iterator i = packages.find(name);
74 Package &PackageManager::get_main_package() const
77 throw logic_error("No packages");
81 Package *PackageManager::find_package(const string &name)
83 if(not_found.count(name))
86 if(Package *pkg = get_package(name))
91 FS::Path path = get_package_location(name);
94 builder.load_build_file(path/"Build");
95 PackageMap::iterator i = packages.find(name);
101 FS::Path path = get_binary_package_file(name);
104 builder.load_build_file(path);
105 if(Package *pkg = get_package(name))
111 // Package source not found - create a binary package
112 string flags_str = run_pkgconfig(name, "flags");
113 BinaryPackage::Flags flags = split(flags_str);
114 flags_str = run_pkgconfig(name, "staticflags");
115 BinaryPackage::Flags static_flags = split(flags_str);
116 Package *pkg = BinaryPackage::from_flags(builder, name, flags, static_flags);
117 packages.insert(PackageMap::value_type(name, pkg));
122 not_found.insert(name);
127 string PackageManager::run_pkgconfig(const string &pkg, const string &what)
132 const FS::Path &prefix = builder.get_prefix();
133 if(prefix.str()!="/usr")
135 FS::Path pcdir = prefix/"lib/pkgconfig";
136 if(const char *pcp = getenv("PKG_CONFIG_PATH"))
138 vector<string> path = split(pcp, ':');
139 if(!any_equals(path, pcdir.str()))
141 path.push_back(pcdir.str());
142 setenv("PKG_CONFIG_PATH", join(path.begin(), path.end(), ":").c_str(), true);
146 setenv("PKG_CONFIG_PATH", pcdir.str().c_str(), true);
150 ExternalTask::Arguments argv;
151 argv.push_back("pkg-config");
152 if(what=="cflags" || what=="libs")
153 argv.push_back("--"+what);
154 else if(what=="flags" || what=="staticflags")
156 argv.push_back("--cflags");
157 argv.push_back("--libs");
158 if(what=="staticflags")
159 argv.push_back("--static");
162 argv.push_back("--variable="+what);
165 builder.get_logger().log("auxcommands", format("Running %s", join(argv.begin(), argv.end())));
167 return ExternalTask::run_and_capture_output(argv);
175 FS::Path PackageManager::get_package_location(const string &name)
177 builder.get_logger().log("packagemgr", format("Looking for source package %s", name));
181 // Try to get source directory with pkgconfig
182 string srcdir = strip(run_pkgconfig(name, "source"));
183 if(!srcdir.empty() && FS::exists(FS::Path(srcdir)/"Build"))
191 for(const FS::Path &p: pkg_path)
193 builder.get_logger().log("files", format("Traversing %s", p));
195 for(const string &f: list_files(p))
198 if(FS::exists(full/"Build"))
200 pkg_dirs.push_back(full);
205 builder.get_logger().log("packagemgr", format("%d source packages found in %s", count, p));
208 builder.get_logger().log("packagemgr", format("%d source packages found", pkg_dirs.size()));
211 bool msp = !name.compare(0, 3, "msp");
212 for(const FS::Path &p: pkg_dirs)
214 string base = FS::basename(p);
215 unsigned dash = base.rfind('-');
217 if(!base.compare(0, dash, name))
219 else if(msp && !base.compare(0, dash, name, 3, string::npos))
226 FS::Path PackageManager::get_binary_package_file(const string &name)
228 builder.get_logger().log("packagemgr", format("Looking for binary package %s", name));
230 if(binpkg_files.empty())
232 for(const FS::Path &p: binpkg_path)
234 builder.get_logger().log("files", format("Traversing %s", p));
235 vector<string> files = list_filtered(p, "\\.bpk$");
236 for(const string &f: files)
237 binpkg_files.push_back(p/f);
238 builder.get_logger().log("packagemgr", format("%d binary packages found in %s", files.size(), p));
241 builder.get_logger().log("packagemgr", format("%d binary packages found", binpkg_files.size()));
244 auto i = find_if(binpkg_files, [&name](const FS::Path &p){ return FS::basepart(FS::basename(p))==name; });
245 if(i!=binpkg_files.end())
251 void PackageManager::save_all_caches() const
253 for(const auto &kvp: packages)
254 kvp.second->save_caches();