#ifndef Manifest_h
#define Manifest_h
#include <map>
#include <set>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <assert.h>
struct MachOProxy;
extern void terminate(const char* format, ...) __printflike(1, 2) __attribute__((noreturn));
extern std::string toolDir();
struct SharedCache;
struct Manifest;
struct Manifest {
struct Project {
std::vector<std::string> sources;
};
struct File {
MachOProxy* proxy;
File( MachOProxy* P ) : proxy( P ) {}
};
struct Anchor {
ImageIdentifier identifier;
bool required;
Anchor( const ImageIdentifier& I ) : identifier( I ) {}
};
struct SegmentInfo {
std::string name;
uint64_t startAddr;
uint64_t endAddr;
};
struct SegmentInfoHasher {
std::size_t operator()(const SegmentInfo &x) const {
return std::hash<std::string>()(x.name) ^ std::hash<uint64_t>()(x.startAddr) ^ std::hash<uint64_t>()(x.endAddr);
}
};
struct CacheInfo {
std::vector<SegmentInfo> regions;
std::string cdHash;
};
struct DylibInfo {
bool included;
std::string exclusionInfo;
UUID uuid;
std::string installname;
std::vector<SegmentInfo> segments;
DylibInfo(void) : included(true) {}
};
struct Results {
std::string failure;
std::map<ImageIdentifier, DylibInfo> dylibs;
std::vector<std::string> warnings;
CacheInfo developmentCache;
CacheInfo productionCache;
DylibInfo& dylibForInstallname(const std::string& installname)
{
auto i = find_if(dylibs.begin(), dylibs.end(), [&installname](std::pair<ImageIdentifier, DylibInfo> d) { return d.second.installname == installname; });
assert(i != dylibs.end());
return i->second;
}
void exclude(MachOProxy* proxy, const std::string& reason);
};
struct Architecture {
std::vector<Anchor> anchors;
mutable Results results;
bool operator==(const Architecture& O) const
{
for (auto& dylib : results.dylibs) {
if (dylib.second.included) {
auto Odylib = O.results.dylibs.find(dylib.first);
if (Odylib == O.results.dylibs.end()
|| Odylib->second.included == false
|| Odylib->second.uuid != dylib.second.uuid)
return false;
}
}
for (const auto& Odylib : O.results.dylibs) {
if (Odylib.second.included) {
auto dylib = results.dylibs.find(Odylib.first);
if (dylib == results.dylibs.end()
|| dylib->second.included == false
|| dylib->second.uuid != Odylib.second.uuid)
return false;
}
}
return true;
}
bool operator!=(const Architecture& other) const { return !(*this == other); }
};
struct Configuration {
std::string platformName;
std::string metabomTag;
std::set<std::string> metabomExcludeTags;
std::set<std::string> metabomRestrictTags;
std::set<std::string> restrictedInstallnames;
std::map<std::string, Architecture> architectures;
bool operator==(const Configuration& O) const
{
return architectures == O.architectures;
}
bool operator!=(const Configuration& other) const { return !(*this == other); }
const Architecture& architecture(const std::string& architecture) const
{
assert(architectures.find(architecture) != architectures.end());
return architectures.find(architecture)->second;
}
void forEachArchitecture(std::function<void(const std::string& archName)> lambda)
{
for (const auto& architecutre : architectures) {
lambda(architecutre.first);
}
}
};
const std::map<std::string, Project>& projects()
{
return _projects;
}
const Configuration& configuration(const std::string& configuration) const
{
assert(_configurations.find(configuration) != _configurations.end());
return _configurations.find(configuration)->second;
}
void forEachConfiguration(std::function<void(const std::string& configName)> lambda)
{
for (const auto& configuration : _configurations) {
lambda(configuration.first);
}
}
void addProjectSource(const std::string& project, const std::string& source, bool first = false)
{
auto& sources = _projects[project].sources;
if (std::find(sources.begin(), sources.end(), source) == sources.end()) {
if (first) {
sources.insert(sources.begin(), source);
} else {
sources.push_back(source);
}
}
}
const std::string projectPath(const std::string& projectName)
{
auto project = _projects.find(projectName);
if (project == _projects.end())
return "";
if (project->second.sources.size() == 0)
return "";
return project->second.sources[0];
}
const bool empty(void) {
for (const auto& configuration : _configurations) {
if (configuration.second.architectures.size() != 0)
return false;
}
return true;
}
const std::string dylibOrderFile() const { return _dylibOrderFile; };
void setDylibOrderFile(const std::string& dylibOrderFile) { _dylibOrderFile = dylibOrderFile; };
const std::string dirtyDataOrderFile() const { return _dirtyDataOrderFile; };
void setDirtyDataOrderFile(const std::string& dirtyDataOrderFile) { _dirtyDataOrderFile = dirtyDataOrderFile; };
const std::string metabomFile() const { return _metabomFile; };
void setMetabomFile(const std::string& metabomFile) { _metabomFile = metabomFile; };
const std::string platform() const { return _platform; };
void setPlatform(const std::string& platform) { _platform = platform; };
const std::string& build() const { return _build; };
void setBuild(const std::string& build) { _build = build; };
const uint32_t version() const { return _manifestVersion; };
void setVersion(const uint32_t manifestVersion) { _manifestVersion = manifestVersion; };
bool normalized;
Manifest(void) {}
Manifest(const std::set<std::string>& archs, const std::string& overlayPath, const std::string& rootPath, const std::set<std::string>& paths);
#if BOM_SUPPORT
Manifest(const std::string& path);
Manifest(const std::string& path, const std::set<std::string>& overlays);
#endif
void write(const std::string& path);
void canonicalize(void);
void calculateClosure(bool enforeceRootless);
bool sameContentsAsCacheAtPath(const std::string& configuration, const std::string& architecture,
const std::string& path) const;
void remove(const std::string& config, const std::string& arch);
MachOProxy* removeLargestLeafDylib(const std::string& configuration, const std::string& architecture);
bool checkLinks();
void runConcurrently(dispatch_queue_t queue, dispatch_semaphore_t concurrencyLimitingSemaphore, std::function<void(const std::string configuration, const std::string architecture)> lambda);
bool filterForConfig(const std::string& configName);
private:
uint32_t _manifestVersion;
std::string _build;
std::string _dylibOrderFile;
std::string _dirtyDataOrderFile;
std::string _metabomFile;
std::string _platform;
std::map<std::string, Project> _projects;
std::map<std::string, Configuration> _configurations;
void removeDylib(MachOProxy* proxy, const std::string& reason, const std::string& configuration, const std::string& architecture,
std::unordered_set<ImageIdentifier>& processedIdentifiers);
void calculateClosure(const std::string& configuration, const std::string& architecture);
void canonicalizeDylib(const std::string& installname);
template <typename P>
void canonicalizeDylib(const std::string& installname, const uint8_t* p);
void addImplicitAliases(void);
MachOProxy* dylibProxy(const std::string& installname, const std::string& arch);
};
#endif