This repository has been archived on 2021-03-22. You can view files and clone it, but cannot push or open issues or pull requests.
backend/src/git.cpp

191 lines
5.0 KiB
C++
Raw Normal View History

2020-07-01 03:51:00 +02:00
/* This file is part of FediBlock-backend.
* Copyright © 2020 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "git.hpp"
#include "files.hpp"
2020-07-01 08:48:36 +02:00
#include "fs-compat.hpp"
#include "json.hpp"
2020-07-01 03:51:00 +02:00
#include <cstdint>
2020-07-01 08:48:36 +02:00
#include <fstream>
2020-07-01 08:48:26 +02:00
#include <git2.h>
2020-07-01 03:51:00 +02:00
#include <stdexcept>
#include <string>
#include <string_view>
namespace FediBlock
{
2020-07-01 08:48:36 +02:00
using std::ofstream;
2020-07-01 03:51:00 +02:00
using std::runtime_error;
using std::stoull;
using std::string;
using std::string_view;
2020-07-01 08:48:36 +02:00
using std::to_string;
2020-07-01 03:51:00 +02:00
using std::uint64_t;
2020-07-01 08:48:26 +02:00
git_repository *_repo{nullptr};
2020-07-01 03:51:00 +02:00
2020-07-01 04:38:08 +02:00
void check_git_error(int error)
2020-07-01 03:51:00 +02:00
{
2020-07-01 04:38:08 +02:00
if (error != 0)
2020-07-01 03:51:00 +02:00
{
const git_error *e = git_error_last();
throw runtime_error{e->message};
}
}
2020-07-01 04:38:08 +02:00
void clone_repo()
{
int error = git_clone(&_repo, "https://schlomp.space/FediBlock/data.git",
(get_tmpdir() / "repo").c_str(), nullptr);
check_git_error(error);
}
2020-07-01 03:51:00 +02:00
uint64_t get_last_id()
{
constexpr string_view branch_prefix{"from-web-"};
uint64_t id{0};
git_branch_iterator *it;
if (git_branch_iterator_new(&it, _repo, GIT_BRANCH_ALL) == 0)
{
git_reference *ref;
git_branch_t type;
while (git_branch_next(&ref, &type, it) == 0)
{
const char *out{nullptr};
git_branch_name(&out, ref);
if (type == GIT_BRANCH_REMOTE)
{
const string branch_name{out};
size_t pos{branch_name.find(branch_prefix)};
if (pos != string::npos)
{
pos += branch_prefix.size();
uint64_t newid{stoull(branch_name.substr(pos))};
if (newid > id)
{
id = newid;
}
}
}
git_reference_free(ref);
}
git_branch_iterator_free(it);
}
return id;
}
2020-07-01 04:38:08 +02:00
void make_new_branch()
{
2020-07-01 08:48:26 +02:00
const auto id{get_last_id() + 1};
const string branch_name = "web-" + std::to_string(id);
2020-07-01 04:38:08 +02:00
git_oid oid_parent;
git_commit *commit;
// Get SHA1 of HEAD.
int error{git_reference_name_to_id(&oid_parent, _repo, "HEAD")};
check_git_error(error);
// Translate SHA-1 to git_commit.
error = git_commit_lookup(&commit, _repo, &oid_parent);
check_git_error(error);
git_reference *branch;
// Create new branch.
2020-07-01 08:48:26 +02:00
error = git_branch_create(&branch, _repo, branch_name.c_str(), commit, 0);
2020-07-01 04:38:08 +02:00
check_git_error(error);
}
2020-07-01 08:48:36 +02:00
void make_commit(const entry_type &entry)
{
// Write files.
const auto id{get_last_id() + 1};
const string basename{get_tmpdir() / "repo" / ("web-" + to_string(id))};
ofstream file(basename + ".json");
if (!file.good())
{
throw; // FIXME
}
file << to_json(entry);
file.close();
if (!entry.screenshot_filepath.empty())
{
// TODO: Add real file extension.
fs::copy(entry.screenshot_filepath, basename + ".image");
}
// Add files.
int error{0};
git_index *index{nullptr};
error = git_repository_index(&index, _repo);
check_git_error(error);
error = git_index_add_all(index, nullptr, 0, nullptr, nullptr);
check_git_error(error);
error = git_index_write(index);
check_git_error(error);
// Create commit.
git_signature *sig;
git_oid oid_commit;
git_oid oid_tree;
git_oid oid_parent;
git_tree *tree;
git_object *parent{nullptr};
git_reference *ref{nullptr};
error = git_signature_now(&sig, "Web", "Don't @ me");
check_git_error(error);
error = git_revparse_ext(&parent, &ref, _repo, "HEAD");
check_git_error(error);
error = git_repository_index(&index, _repo);
check_git_error(error);
error = git_index_write_tree(&oid_tree, index);
check_git_error(error);
error = git_index_write(index);
check_git_error(error);
error = git_tree_lookup(&tree, _repo, &oid_tree);
check_git_error(error);
error = git_reference_name_to_id(&oid_parent, _repo, "HEAD");
check_git_error(error);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
error = git_commit_create_v(&oid_commit, _repo, "HEAD", sig, sig, nullptr,
("New entry: " + entry.instance).c_str(), tree,
parent != nullptr ? 1 : 0, parent);
check_git_error(error);
git_index_free(index);
git_signature_free(sig);
git_tree_free(tree);
}
2020-07-01 03:51:00 +02:00
} // namespace FediBlock