metaforce/hecl/lib/database/Project.cpp

329 lines
8.1 KiB
C++
Raw Normal View History

2015-05-21 02:33:05 +00:00
#include <sys/stat.h>
#include <errno.h>
2015-06-09 22:19:59 +00:00
#include <stdio.h>
2015-05-21 02:33:05 +00:00
#include <string.h>
#include <system_error>
2015-06-10 23:34:14 +00:00
#if _WIN32
#else
#include <unistd.h>
#endif
#include "HECL/Database.hpp"
2015-05-21 02:33:05 +00:00
2015-06-10 02:40:03 +00:00
namespace HECL
{
namespace Database
2015-05-21 02:33:05 +00:00
{
LogVisor::LogModule LogModule("HECLDatabase");
2015-06-09 23:21:45 +00:00
/**********************************************
* Project::ConfigFile
**********************************************/
2015-06-09 22:19:59 +00:00
static inline bool CheckNewLineAdvance(std::string::const_iterator& it)
{
2015-06-10 23:34:14 +00:00
if (*it == '\n')
2015-06-09 22:19:59 +00:00
{
it += 1;
return true;
}
else if (*it == '\r')
{
if (*(it+1) == '\n')
{
it += 2;
return true;
}
2015-06-10 23:34:14 +00:00
it += 1;
return true;
2015-06-09 22:19:59 +00:00
}
return false;
}
2015-06-12 09:08:49 +00:00
Project::ConfigFile::ConfigFile(const Project& project, const SystemString& name,
const SystemString& subdir)
2015-05-21 02:33:05 +00:00
{
2015-06-12 09:08:49 +00:00
m_filepath = project.m_rootPath.getAbsolutePath() + subdir + name;
2015-06-09 22:57:21 +00:00
}
2015-06-09 22:19:59 +00:00
2015-06-11 09:41:10 +00:00
std::list<std::string>& Project::ConfigFile::lockAndRead()
2015-06-09 22:57:21 +00:00
{
2015-06-10 23:34:14 +00:00
if (m_lockedFile)
return m_lines;
2015-06-11 09:41:10 +00:00
m_lockedFile = HECL::Fopen(m_filepath.c_str(), _S("a+"), LWRITE);
2015-06-09 22:19:59 +00:00
2015-06-09 22:57:21 +00:00
std::string mainString;
char readBuf[1024];
size_t readSz;
2015-06-10 23:34:14 +00:00
while ((readSz = fread(readBuf, 1, 1024, m_lockedFile)))
2015-06-09 22:57:21 +00:00
mainString += std::string(readBuf, readSz);
2015-06-09 22:19:59 +00:00
2015-06-09 22:57:21 +00:00
std::string::const_iterator begin = mainString.begin();
std::string::const_iterator end = mainString.begin();
2015-06-09 22:19:59 +00:00
2015-06-10 23:34:14 +00:00
m_lines.clear();
2015-06-09 22:57:21 +00:00
while (end != mainString.end())
{
std::string::const_iterator origEnd = end;
if (*end == '\0')
break;
else if (CheckNewLineAdvance(end))
2015-06-09 22:19:59 +00:00
{
2015-06-09 22:57:21 +00:00
if (begin != origEnd)
2015-06-10 23:34:14 +00:00
m_lines.push_back(std::string(begin, origEnd));
2015-06-09 22:57:21 +00:00
begin = end;
continue;
2015-06-09 22:19:59 +00:00
}
2015-06-09 22:57:21 +00:00
++end;
}
if (begin != end)
2015-06-10 23:34:14 +00:00
m_lines.push_back(std::string(begin, end));
2015-06-09 22:19:59 +00:00
2015-06-10 23:34:14 +00:00
return m_lines;
2015-06-09 22:57:21 +00:00
}
2015-06-09 22:19:59 +00:00
2015-06-09 22:57:21 +00:00
void Project::ConfigFile::addLine(const std::string& line)
{
2015-06-10 23:34:14 +00:00
if (!checkForLine(line))
m_lines.push_back(line);
2015-06-09 22:57:21 +00:00
}
2015-05-21 02:33:05 +00:00
2015-06-09 22:57:21 +00:00
void Project::ConfigFile::removeLine(const std::string& refLine)
{
2015-06-10 23:34:14 +00:00
if (!m_lockedFile)
{
LogModule.reportSource(LogVisor::FatalError, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
return;
}
2015-05-21 02:33:05 +00:00
2015-06-11 09:41:10 +00:00
for (auto it = m_lines.begin();
2015-06-13 20:10:37 +00:00
it != m_lines.end();)
2015-05-21 02:33:05 +00:00
{
2015-06-10 23:34:14 +00:00
if (!(*it).compare(refLine))
2015-06-13 20:10:37 +00:00
{
2015-06-10 23:34:14 +00:00
it = m_lines.erase(it);
2015-06-13 20:10:37 +00:00
continue;
}
++it;
2015-05-21 02:33:05 +00:00
}
2015-06-09 22:57:21 +00:00
}
2015-05-21 02:33:05 +00:00
2015-06-09 22:57:21 +00:00
bool Project::ConfigFile::checkForLine(const std::string& refLine)
{
2015-06-10 23:34:14 +00:00
if (!m_lockedFile)
{
LogModule.reportSource(LogVisor::FatalError, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
return false;
}
2015-06-10 23:34:14 +00:00
for (const std::string& line : m_lines)
2015-05-21 02:33:05 +00:00
{
2015-06-09 22:57:21 +00:00
if (!line.compare(refLine))
return true;
2015-05-21 02:33:05 +00:00
}
2015-06-09 22:57:21 +00:00
return false;
}
2015-05-21 02:33:05 +00:00
2015-06-10 23:34:14 +00:00
void Project::ConfigFile::unlockAndDiscard()
{
if (!m_lockedFile)
{
LogModule.reportSource(LogVisor::FatalError, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
return;
}
2015-06-10 23:34:14 +00:00
m_lines.clear();
fclose(m_lockedFile);
m_lockedFile = NULL;
}
2015-06-11 09:41:10 +00:00
bool Project::ConfigFile::unlockAndCommit()
2015-06-10 23:34:14 +00:00
{
if (!m_lockedFile)
{
LogModule.reportSource(LogVisor::FatalError, __FILE__, __LINE__, "Project::ConfigFile::lockAndRead not yet called");
return false;
}
2015-06-10 23:34:14 +00:00
2015-06-11 09:41:10 +00:00
SystemString newPath = m_filepath + _S(".part");
FILE* newFile = HECL::Fopen(newPath.c_str(), _S("w"), LWRITE);
bool fail = false;
2015-06-10 23:34:14 +00:00
for (const std::string& line : m_lines)
{
2015-06-11 09:41:10 +00:00
if (fwrite(line.c_str(), 1, line.size(), newFile) != line.size())
{
fail = true;
break;
}
if (fwrite("\n", 1, 1, newFile) != 1)
{
fail = true;
break;
}
2015-06-10 23:34:14 +00:00
}
m_lines.clear();
2015-06-11 09:41:10 +00:00
fclose(newFile);
2015-06-10 23:34:14 +00:00
fclose(m_lockedFile);
m_lockedFile = NULL;
2015-06-11 09:41:10 +00:00
if (fail)
{
unlink(newPath.c_str());
return false;
}
else
{
rename(newPath.c_str(), m_filepath.c_str());
return true;
}
2015-06-10 23:34:14 +00:00
}
2015-06-09 23:21:45 +00:00
/**********************************************
* Project
**********************************************/
2015-06-10 02:40:03 +00:00
Project::Project(const ProjectRootPath& rootPath)
2015-06-11 04:55:06 +00:00
: m_rootPath(rootPath),
m_specs(*this, _S("specs")),
m_paths(*this, _S("paths")),
2015-06-12 04:02:23 +00:00
m_groups(*this, _S("groups"))
2015-06-09 22:57:21 +00:00
{
/* Stat for existing project directory (must already exist) */
struct stat myStat;
2015-06-10 02:40:03 +00:00
if (HECL::Stat(m_rootPath.getAbsolutePath().c_str(), &myStat))
2015-06-09 22:57:21 +00:00
throw std::error_code(errno, std::system_category());
2015-05-21 02:33:05 +00:00
2015-06-09 22:57:21 +00:00
if (!S_ISDIR(myStat.st_mode))
2015-06-10 02:40:03 +00:00
throw std::invalid_argument("provided path must be a directory; '" +
m_rootPath.getAbsolutePathUTF8() + "' isn't");
2015-05-21 02:33:05 +00:00
2015-06-09 22:57:21 +00:00
/* Create project directory structure */
2015-06-10 02:40:03 +00:00
HECL::MakeDir(m_rootPath.getAbsolutePath() + _S("/.hecl"));
HECL::MakeDir(m_rootPath.getAbsolutePath() + _S("/.hecl/cooked"));
2015-06-11 09:41:10 +00:00
2015-06-12 04:02:23 +00:00
/* Ensure beacon is valid or created */
FILE* bf = HECL::Fopen((m_rootPath.getAbsolutePath() + _S("/.hecl/beacon")).c_str(), _S("a+b"));
struct BeaconStruct
{
2015-07-10 05:28:33 +00:00
uint32_t magic;
2015-06-12 04:02:23 +00:00
uint32_t version;
} beacon;
#define DATA_VERSION 1
if (fread(&beacon, 1, sizeof(beacon), bf) != sizeof(beacon))
{
fseek(bf, 0, SEEK_SET);
2015-07-10 05:28:33 +00:00
beacon.magic = SBig('HECL');
2015-06-12 04:02:23 +00:00
beacon.version = SBig(DATA_VERSION);
fwrite(&beacon, 1, sizeof(beacon), bf);
}
fclose(bf);
2015-07-10 05:28:33 +00:00
if (beacon.magic != SBig('HECL') ||
2015-06-12 04:02:23 +00:00
SBig(beacon.version) != DATA_VERSION)
{
LogModule.report(LogVisor::FatalError, "incompatible project version");
return;
}
2015-06-12 04:02:23 +00:00
/* Compile current dataspec */
rescanDataSpecs();
2015-06-09 22:57:21 +00:00
}
2015-05-21 02:33:05 +00:00
2015-06-10 02:40:03 +00:00
bool Project::addPaths(const std::vector<ProjectPath>& paths)
2015-06-09 22:57:21 +00:00
{
2015-06-11 09:41:10 +00:00
m_paths.lockAndRead();
for (const ProjectPath& path : paths)
m_paths.addLine(path.getRelativePathUTF8());
return m_paths.unlockAndCommit();
2015-06-09 22:57:21 +00:00
}
2015-06-09 22:19:59 +00:00
2015-06-10 02:40:03 +00:00
bool Project::removePaths(const std::vector<ProjectPath>& paths, bool recursive)
2015-06-09 22:57:21 +00:00
{
2015-06-11 09:41:10 +00:00
std::list<std::string>& existingPaths = m_paths.lockAndRead();
if (recursive)
{
for (const ProjectPath& path : paths)
{
std::string recursiveBase = path.getRelativePathUTF8();
for (auto it = existingPaths.begin();
2015-06-13 20:12:55 +00:00
it != existingPaths.end();)
2015-06-11 09:41:10 +00:00
{
if (!(*it).compare(0, recursiveBase.size(), recursiveBase))
2015-06-13 20:10:37 +00:00
{
2015-06-11 09:41:10 +00:00
it = existingPaths.erase(it);
2015-06-13 20:10:37 +00:00
continue;
}
++it;
2015-06-11 09:41:10 +00:00
}
}
}
else
for (const ProjectPath& path : paths)
m_paths.removeLine(path.getRelativePathUTF8());
return m_paths.unlockAndCommit();
2015-06-09 22:57:21 +00:00
}
2015-05-21 02:33:05 +00:00
2015-06-09 22:57:21 +00:00
bool Project::addGroup(const HECL::ProjectPath& path)
{
2015-06-11 09:41:10 +00:00
m_groups.lockAndRead();
m_groups.addLine(path.getRelativePathUTF8());
return m_groups.unlockAndCommit();
2015-06-09 22:57:21 +00:00
}
2015-05-21 02:33:05 +00:00
2015-06-10 02:40:03 +00:00
bool Project::removeGroup(const ProjectPath& path)
2015-06-09 22:57:21 +00:00
{
2015-06-11 09:41:10 +00:00
m_groups.lockAndRead();
m_groups.removeLine(path.getRelativePathUTF8());
return m_groups.unlockAndCommit();
2015-06-09 22:57:21 +00:00
}
2015-05-21 02:33:05 +00:00
2015-06-12 04:02:23 +00:00
void Project::rescanDataSpecs()
{
m_compiledSpecs.clear();
m_specs.lockAndRead();
2015-07-01 23:53:05 +00:00
for (const DataSpecEntry* spec : DATA_SPEC_REGISTRY)
2015-06-12 04:02:23 +00:00
{
2015-07-01 23:53:05 +00:00
SystemUTF8View specUTF8(spec->m_name);
2015-06-12 04:02:23 +00:00
m_compiledSpecs.push_back({*spec, m_specs.checkForLine(specUTF8.utf8_str()) ? true : false});
}
m_specs.unlockAndDiscard();
}
2015-06-11 09:41:10 +00:00
bool Project::enableDataSpecs(const std::vector<SystemString>& specs)
2015-06-09 22:57:21 +00:00
{
2015-06-11 09:41:10 +00:00
m_specs.lockAndRead();
for (const SystemString& spec : specs)
m_specs.addLine(spec);
return m_specs.unlockAndCommit();
2015-06-09 22:57:21 +00:00
}
2015-06-11 09:41:10 +00:00
bool Project::disableDataSpecs(const std::vector<SystemString>& specs)
2015-06-09 22:57:21 +00:00
{
2015-06-11 09:41:10 +00:00
m_specs.lockAndRead();
for (const SystemString& spec : specs)
m_specs.removeLine(spec);
return m_specs.unlockAndCommit();
2015-06-09 22:57:21 +00:00
}
2015-06-10 02:40:03 +00:00
bool Project::cookPath(const ProjectPath& path,
2015-06-09 22:57:21 +00:00
std::function<void(std::string&, Cost, unsigned)> feedbackCb,
bool recursive)
{
}
void Project::interruptCook()
{
}
2015-06-10 02:40:03 +00:00
bool Project::cleanPath(const ProjectPath& path, bool recursive)
2015-06-09 22:57:21 +00:00
{
}
2015-05-21 02:33:05 +00:00
2015-06-11 04:55:06 +00:00
PackageDepsgraph Project::buildPackageDepsgraph(const ProjectPath& path)
2015-05-21 02:33:05 +00:00
{
}
}
2015-06-10 02:40:03 +00:00
}