Skip to content

Commit

Permalink
Implemented loot_update_masterlist.
Browse files Browse the repository at this point in the history
Also removed dummy Masterlist member functions from API code, and unused
language parameter from Masterlist::Update().

Game condition cache lookup during condition parsing tests was removed
for simplicity, though it should hopefully not have too much effect on
the test speed.
  • Loading branch information
Ortham committed Sep 26, 2014
1 parent 4bea8cf commit 9be2c15
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 80 deletions.
18 changes: 8 additions & 10 deletions CMakeLists.txt
Expand Up @@ -50,7 +50,8 @@ set (LOOT_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/helpers.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/globals.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/generators.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/graph.cpp")
"${CMAKE_SOURCE_DIR}/src/backend/graph.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/git.cpp")

set (LOOT_HEADERS "${CMAKE_SOURCE_DIR}/src/backend/metadata.h"
"${CMAKE_SOURCE_DIR}/src/backend/game.h"
Expand All @@ -63,9 +64,6 @@ set (LOOT_HEADERS "${CMAKE_SOURCE_DIR}/src/backend/metadata.h"
"${CMAKE_SOURCE_DIR}/src/backend/streams.h")

set (LOOT_GUI_SRC ${LOOT_SRC}
# Code the API doesn't need.
"${CMAKE_SOURCE_DIR}/src/backend/git.cpp"
# Actual GUI code.
"${CMAKE_SOURCE_DIR}/src/gui/main_win.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/handler.cpp"
"${CMAKE_SOURCE_DIR}/src/gui/app.cpp"
Expand Down Expand Up @@ -168,13 +166,13 @@ ELSEIF (MSVC)
ENDIF ()

set (CMAKE_EXE_LINKER_FLAGS "/SUBSYSTEM:WINDOWS /LARGEADDRESSAWARE")
set (LOOT_LIBS libyaml-cppmt
version
loadorder${PROJECT_ARCH}
ws2_32
shlwapi)
set (LOOT_LIBS git2
libyaml-cppmt
version
loadorder${PROJECT_ARCH}
ws2_32
shlwapi)
set (LOOT_GUI_LIBS ${LOOT_LIBS}
git2
cef_sandbox
libcef
libcef_dll_wrapper
Expand Down
17 changes: 1 addition & 16 deletions src/api/api.cpp
Expand Up @@ -172,22 +172,6 @@ unsigned int c_error(const unsigned int code, const std::string& what) {
return c_error(loot::error(code, what.c_str()));
}

////////////////////////////////////
// Dummy Masterlist member functions
////////////////////////////////////

// The API doesn't depend on libgit2, by not compiling ".git.cpp", so the member functions are defined
// below as dummies.

namespace loot {
void Masterlist::GetGitInfo(const boost::filesystem::path& path) {}

bool Masterlist::Update(Game& game, const unsigned int language) {
this->MetadataList::Load(game.MasterlistPath());
return false;
}
}

//////////////////////////////
// Error Handling Functions
//////////////////////////////
Expand Down Expand Up @@ -458,6 +442,7 @@ LOOT_API unsigned int loot_update_masterlist(loot_db db,

try {
loot::Masterlist masterlist;
*updated = masterlist.Update(masterlistPath, remoteURL, remoteBranch);
}
catch (loot::error &e) {
return c_error(e);
Expand Down
2 changes: 1 addition & 1 deletion src/backend/game.cpp
Expand Up @@ -252,7 +252,7 @@ namespace loot {

bool Masterlist::Load(Game& game, const unsigned int language) {
try {
return Update(game, language);
return Update(game);
}
catch (error& e) {
if (e.code() != error::ok) {
Expand Down
5 changes: 4 additions & 1 deletion src/backend/game.h
Expand Up @@ -84,7 +84,10 @@ namespace loot {
public:

bool Load(Game& game, const unsigned int language); //Handles update with load fallback.
bool Update(Game& game, const unsigned int language);
bool Update(const Game& game);
bool Update(const boost::filesystem::path& path,
const std::string& repoURL,
const std::string& repoBranch);

std::string GetRevision(const boost::filesystem::path& path, bool shortID);
std::string GetDate(const boost::filesystem::path& path);
Expand Down
45 changes: 24 additions & 21 deletions src/backend/git.cpp
Expand Up @@ -207,10 +207,13 @@ namespace loot {
}
}

bool Masterlist::Update(Game& game, const unsigned int language) {
bool Masterlist::Update(const Game& game) {
return Update(game.MasterlistPath(), game.RepoURL(), game.RepoBranch());
}

bool Masterlist::Update(const boost::filesystem::path& path, const std::string& repoURL, const std::string& repoBranch) {
git_handler git;
fs::path repo_path = game.MasterlistPath().parent_path();
string repo_branch = game.RepoBranch();
fs::path repo_path = path.parent_path();

// First initialise some stuff that isn't specific to a repository.
BOOST_LOG_TRIVIAL(debug) << "Creating a reflog signature to use.";
Expand Down Expand Up @@ -257,15 +260,15 @@ namespace loot {
git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
clone_options.checkout_opts = checkout_opts;
clone_options.bare = 0;
clone_options.checkout_branch = repo_branch.c_str();
clone_options.checkout_branch = repoBranch.c_str();
clone_options.signature = git.sig;
#ifndef _WIN32
//OpenSSL doesn't seem to like GitHub's certificate.
clone_options.ignore_cert_errors = 1;
#endif

//Now perform the clone.
git.call(git_clone(&git.repo, game.RepoURL().c_str(), repo_path.string().c_str(), &clone_options));
git.call(git_clone(&git.repo, repoURL.c_str(), repo_path.string().c_str(), &clone_options));

if (fs::exists(temp_path)) {
//Move contents back in.
Expand Down Expand Up @@ -294,12 +297,12 @@ namespace loot {
git.call(git_remote_load(&git.remote, git.repo, "origin"));
const char * url = git_remote_url(git.remote);

BOOST_LOG_TRIVIAL(info) << "Remote URL given: " << game.RepoURL();
BOOST_LOG_TRIVIAL(info) << "Remote URL given: " << repoURL;
BOOST_LOG_TRIVIAL(info) << "Remote URL in repository settings: " << url;
if (url != game.RepoURL()) {
if (url != repoURL) {
BOOST_LOG_TRIVIAL(info) << "URLs do not match, setting repository URL to URL in settings.";
// The URLs don't match. Change the remote URL to match the one LOOT has.
git.call(git_remote_set_url(git.remote, game.RepoURL().c_str()));
git.call(git_remote_set_url(git.remote, repoURL.c_str()));

// Now save change.
git.call(git_remote_save(git.remote));
Expand All @@ -317,21 +320,21 @@ namespace loot {

// Check that a branch with the correct name exists.
git.ui_message = "An error occurred while trying to access the local masterlist repository. If this error happens again, try deleting the \".git\" folder in " + repo_path.string() + "\".";
int ret = git_branch_lookup(&git.ref, git.repo, repo_branch.c_str(), GIT_BRANCH_LOCAL);
int ret = git_branch_lookup(&git.ref, git.repo, repoBranch.c_str(), GIT_BRANCH_LOCAL);
if (ret == GIT_ENOTFOUND) {
// Branch doesn't exist. Create a new branch using the remote branch's latest commit.

BOOST_LOG_TRIVIAL(trace) << "Looking up commit referred to by the remote branch \"" << repo_branch << "\".";
git.call(git_revparse_single(&git.obj, git.repo, (string("origin/") + repo_branch).c_str()));
BOOST_LOG_TRIVIAL(trace) << "Looking up commit referred to by the remote branch \"" << repoBranch << "\".";
git.call(git_revparse_single(&git.obj, git.repo, (string("origin/") + repoBranch).c_str()));
const git_oid * commit_id = git_object_id(git.obj);

BOOST_LOG_TRIVIAL(trace) << "Creating the new branch.";
// Create a branch.
git.call(git_commit_lookup(&git.commit, git.repo, commit_id));
git.call(git_branch_create(&git.ref, git.repo, repo_branch.c_str(), git.commit, 0, git.sig, NULL));
git.call(git_branch_create(&git.ref, git.repo, repoBranch.c_str(), git.commit, 0, git.sig, NULL));

// Set upstream. Don't really know if this is necessary or not.
git.call(git_branch_set_upstream(git.ref, (string("origin/") + repo_branch).c_str()));
git.call(git_branch_set_upstream(git.ref, (string("origin/") + repoBranch).c_str()));

BOOST_LOG_TRIVIAL(trace) << "Setting the upstream for the new branch.";
// Free tree and commit pointers. Reference pointer is still used below.
Expand All @@ -347,8 +350,8 @@ namespace loot {

// Check if HEAD points to the desired branch and set it to if not.
if (!git_branch_is_head(git.ref)) {
BOOST_LOG_TRIVIAL(trace) << "Setting HEAD to follow branch: " << repo_branch;
git.call(git_repository_set_head(git.repo, (string("refs/heads/") + repo_branch).c_str(), git.sig, (string("Updated HEAD to ") + repo_branch).c_str()));
BOOST_LOG_TRIVIAL(trace) << "Setting HEAD to follow branch: " << repoBranch;
git.call(git_repository_set_head(git.repo, (string("refs/heads/") + repoBranch).c_str(), git.sig, (string("Updated HEAD to ") + repoBranch).c_str()));
}

if (ret == 0) {
Expand All @@ -361,7 +364,7 @@ namespace loot {
BOOST_LOG_TRIVIAL(trace) << "Checking that local and remote branches can be merged by fast-forward.";
git_merge_analysis_t analysis;
git_merge_preference_t pref;
git.call(git_reference_lookup(&git.ref2, git.repo, (string("refs/remotes/origin/") + repo_branch).c_str()));
git.call(git_reference_lookup(&git.ref2, git.repo, (string("refs/remotes/origin/") + repoBranch).c_str()));
git.call(git_merge_head_from_ref(&git.merge_head, git.repo, git.ref2));
git.call(git_merge_analysis(&analysis, &pref, git.repo, (const git_merge_head **)&git.merge_head, 1));

Expand Down Expand Up @@ -429,7 +432,7 @@ namespace loot {
FixRepoPermissions(repo_path / ".git");
git.free();
fs::remove_all(repo_path / ".git");
return this->Update(game, language);
return this->Update(path, repoURL, repoBranch);
//throw error(error::git_error, "Local repository has been edited, an automatic fast-forward merge update is not possible.");
}
}
Expand Down Expand Up @@ -484,16 +487,16 @@ namespace loot {
//Now try parsing the masterlist.
BOOST_LOG_TRIVIAL(debug) << "Testing masterlist parsing.";
try {
this->MetadataList::Load(game.MasterlistPath());
this->MetadataList::Load(path);

for (auto &plugin : plugins) {
plugin.ParseAllConditions(game);
plugin.ParseAllConditions();
}
for (auto &plugin : regexPlugins) {
plugin.ParseAllConditions(game);
plugin.ParseAllConditions();
}
for (auto &message : messages) {
message.ParseCondition(game);
message.ParseCondition();
}

parsingFailed = false;
Expand Down
23 changes: 9 additions & 14 deletions src/backend/metadata.cpp
Expand Up @@ -126,7 +126,7 @@ namespace loot {
if (it != game.conditionCache.end())
return it->second;

condition_grammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar(game, false);
condition_grammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar(&game, false);
boost::spirit::qi::space_type skipper;
std::string::const_iterator begin, end;
bool eval;
Expand All @@ -153,18 +153,13 @@ namespace loot {
return eval;
}

void ConditionStruct::ParseCondition(Game& game) const {
void ConditionStruct::ParseCondition() const {
if (_condition.empty())
return;

BOOST_LOG_TRIVIAL(trace) << "Testing condition syntax: " << _condition;

// If the same condition string has already been evaluated, it must be written correctly.
unordered_map<std::string, bool>::const_iterator it = game.conditionCache.find(boost::locale::to_lower(_condition));
if (it != game.conditionCache.end())
return;

condition_grammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar(game, true);
condition_grammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar(nullptr, true);
boost::spirit::qi::space_type skipper;
std::string::const_iterator begin, end;

Expand Down Expand Up @@ -732,21 +727,21 @@ namespace loot {
return *this;
}

void Plugin::ParseAllConditions(Game& game) const {
void Plugin::ParseAllConditions() const {
for (const File& file : loadAfter) {
file.ParseCondition(game);
file.ParseCondition();
}
for (const File& file : requirements) {
file.ParseCondition(game);
file.ParseCondition();
}
for (const File& file : incompatibilities) {
file.ParseCondition(game);
file.ParseCondition();
}
for (const Message& message : messages) {
message.ParseCondition(game);
message.ParseCondition();
}
for (const Tag& tag : tags) {
tag.ParseCondition(game);
tag.ParseCondition();
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/backend/metadata.h
Expand Up @@ -83,7 +83,7 @@ namespace loot {

bool IsConditional() const;
bool EvalCondition(Game& game) const;
void ParseCondition(Game& game) const; // Throws error on parsing failure.
void ParseCondition() const; // Throws error on parsing failure.

std::string Condition() const;
private:
Expand Down Expand Up @@ -226,7 +226,7 @@ namespace loot {
void Locations(const std::set<Location>& locations);

Plugin& EvalAllConditions(Game& game, const unsigned int language);
void ParseAllConditions(Game& game) const;
void ParseAllConditions() const;
bool HasNameOnly() const;
bool IsRegexPlugin() const;
bool LoadsBSA(const Game& game) const;
Expand Down
33 changes: 18 additions & 15 deletions src/backend/parsers.h
Expand Up @@ -431,7 +431,10 @@ namespace loot {
template<typename Iterator, typename Skipper>
class condition_grammar : public qi::grammar < Iterator, bool(), Skipper > {
public:
condition_grammar(Game& game, bool parseOnly) : condition_grammar::base_type(expression, "condition grammar"), _game(game), _parseOnly(parseOnly) {
condition_grammar(Game * game, bool parseOnly) : condition_grammar::base_type(expression, "condition grammar"), _game(game), _parseOnly(parseOnly) {
if (!_parseOnly && _game == nullptr)
throw error(error::invalid_args, "A valid game pointer was not passed during a condition evaluation.");

expression =
compound[qi::labels::_val = qi::labels::_1]
>> *((qi::lit("or") >> compound)[qi::labels::_val = qi::labels::_val || qi::labels::_1])
Expand Down Expand Up @@ -503,7 +506,7 @@ namespace loot {
qi::rule<Iterator, std::string()> quotedStr, filePath, comparator;
qi::rule<Iterator, char()> invalidPathChars;

Game& _game;
Game * _game;
bool _parseOnly;

//Eval's exact paths. Check for files and ghosted plugins.
Expand All @@ -524,9 +527,9 @@ namespace loot {
}

if (IsPlugin(file))
result = boost::filesystem::exists(_game.DataPath() / file) || boost::filesystem::exists(_game.DataPath() / (file + ".ghost"));
result = boost::filesystem::exists(_game->DataPath() / file) || boost::filesystem::exists(_game->DataPath() / (file + ".ghost"));
else
result = boost::filesystem::exists(_game.DataPath() / file);
result = boost::filesystem::exists(_game->DataPath() / file);

if (result)
BOOST_LOG_TRIVIAL(trace) << "The file does exist.";
Expand Down Expand Up @@ -580,7 +583,7 @@ namespace loot {
//Now we have a valid parent path and a regex filename. Check that
//the parent path exists and is a directory.

boost::filesystem::path parent_path = _game.DataPath() / parent;
boost::filesystem::path parent_path = _game->DataPath() / parent;
if (!boost::filesystem::exists(parent_path) || !boost::filesystem::is_directory(parent_path)) {
BOOST_LOG_TRIVIAL(trace) << "The path \"" << parent_path << "\" does not exist or is not a directory.";
return;
Expand Down Expand Up @@ -616,23 +619,23 @@ namespace loot {
}

uint32_t crc;
unordered_map<std::string, uint32_t>::iterator it = _game.crcCache.find(boost::locale::to_lower(file));
unordered_map<std::string, uint32_t>::iterator it = _game->crcCache.find(boost::locale::to_lower(file));

if (it != _game.crcCache.end())
if (it != _game->crcCache.end())
crc = it->second;
else {
if (file == "LOOT")
crc = GetCrc32(boost::filesystem::absolute("LOOT.exe"));
if (boost::filesystem::exists(_game.DataPath() / file))
crc = GetCrc32(_game.DataPath() / file);
else if (IsPlugin(file) && boost::filesystem::exists(_game.DataPath() / (file + ".ghost")))
crc = GetCrc32(_game.DataPath() / (file + ".ghost"));
if (boost::filesystem::exists(_game->DataPath() / file))
crc = GetCrc32(_game->DataPath() / file);
else if (IsPlugin(file) && boost::filesystem::exists(_game->DataPath() / (file + ".ghost")))
crc = GetCrc32(_game->DataPath() / (file + ".ghost"));
else {
result = false;
return;
}

_game.crcCache.emplace(boost::locale::to_lower(file), crc);
_game->crcCache.emplace(boost::locale::to_lower(file), crc);
}

result = checksum == crc;
Expand All @@ -657,11 +660,11 @@ namespace loot {
if (file == "LOOT")
trueVersion = Version(boost::filesystem::absolute("LOOT.exe"));
else if (IsPlugin(file)) {
Plugin plugin(_game, file, true);
Plugin plugin(*_game, file, true);
trueVersion = Version(plugin.Version());
}
else
trueVersion = Version(_game.DataPath() / file);
trueVersion = Version(_game->DataPath() / file);

BOOST_LOG_TRIVIAL(trace) << "Version extracted: " << trueVersion.AsString();

Expand All @@ -683,7 +686,7 @@ namespace loot {
if (file == "LOOT")
result = false;
else
result = _game.IsActive(file);
result = _game->IsActive(file);

BOOST_LOG_TRIVIAL(trace) << "Active check result: " << result;
}
Expand Down

0 comments on commit 9be2c15

Please sign in to comment.