Commit debcfffc authored by Denis Zalevskiy's avatar Denis Zalevskiy

Merge pull request #20 from nemomobile/api-increase-granularity

Increase vault API granularity
parents 95aef761 1d441356
......@@ -28,7 +28,7 @@ class Snapshot
{
public:
explicit Snapshot(const Gittin::Tag &commit);
explicit Snapshot(Gittin::Repo *repo, const QString &name);
inline Gittin::Tag tag() const { return m_tag; }
QString name() const;
......@@ -73,6 +73,7 @@ public:
bool clear(const QVariantMap &options);
QList<Snapshot> snapshots() const;
QList<QString> units(QString const & snapshotName) const;
Snapshot snapshot(const QByteArray &tag) const;
QString notes(const QString &snapshotName);
......@@ -93,11 +94,19 @@ public:
Lock lock() const;
void resetLastSnapshot();
std::tuple<QString, bool, QString> backupUnit(const QString &, const QString &);
QString tagSnapshot(const QString &message);
std::tuple<QString, bool, QString> restoreUnit
(const QString &, const QString &, const QString &);
private:
bool setState(const QString &state);
bool backupUnit(const QString &home, const QString &unit, const ProgressCallback &callback);
bool restoreUnit(const QString &home, const QString &unit, const ProgressCallback &callback);
void tagSnapshot(const QString &msg);
void checkout(const QString &);
void resetMaster();
void setup(const QVariantMap *config);
......
......@@ -17,6 +17,7 @@ public:
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("NemoMobile.Vault"));
qmlRegisterType<Vault>(uri, 1, 0, "Vault");
qmlRegisterType<Vault>(uri, 1, 1, "Vault");
}
void initializeEngine(QQmlEngine *engine, const char *uri)
......
......@@ -18,6 +18,9 @@ static const int _vault_operation_ __attribute__((unused))
Q_DECLARE_METATYPE(Vault::ImportExportAction)
static const int _vault_importexportaction_ __attribute__((unused))
= qRegisterMetaType<Vault::ImportExportAction>();
Q_DECLARE_METATYPE(Vault::DataType)
static const int _vault_datatype__ __attribute__((unused))
= qRegisterMetaType<Vault::DataType>();
class Worker : public QObject
{
......@@ -61,6 +64,36 @@ public:
emit done(Vault::Restore, QVariantMap());
}
Q_INVOKABLE void reset()
{
debug::debug("Reset storage master to the last snapshot");
m_vault->resetLastSnapshot();
emit done(Vault::Maintenance, {{"operation", "reset"}});
}
Q_INVOKABLE void backupUnit(const QString &home, const QString &unit)
{
debug::debug(home, "- backup unit", unit);
auto res = m_vault->backupUnit(home, unit);
emit progress(Vault::Backup, {{"unit", unit}, {"status", std::get<2>(res)}});
}
Q_INVOKABLE void restoreUnit(const QString &snapshot
, const QString &home
, const QString &unit)
{
debug::debug(home, "- restore unit", unit, "snapshot", snapshot);
auto res = m_vault->restoreUnit(snapshot, home, unit);
emit progress(Vault::Restore, {{"unit", unit}, {"status", std::get<2>(res)}});
}
Q_INVOKABLE void tagSnapshot(const QString &message)
{
debug::debug("Tag snapshot, message:", message);
auto tag = m_vault->tagSnapshot(message);
emit done(Vault::Backup, {{"tag", tag}});
}
Q_INVOKABLE void backup(const QString &home, const QStringList &units, const QString &message)
{
debug::debug("Backup: home", home);
......@@ -158,10 +191,44 @@ public:
emit done(Vault::RemoveSnapshot, QVariantMap());
}
QVariantMap units()
{
QVariantMap res;
for (auto &u: m_vault->config().units())
res.insert(u.name(), u.data());
return res;
}
Q_INVOKABLE void requestData(Vault::DataType dataType
, QVariantMap const &context)
{
try {
if (dataType == Vault::SnapshotUnits) {
auto snapshotName = str(context["snapshot"]);
auto reply = context;
auto unitNames = m_vault->units(snapshotName).toSet();
auto allUnits = units();
for (auto it = allUnits.begin(); it != allUnits.end(); ++it) {
auto info = it.value().toMap();
info["snapshot"] = unitNames.contains(it.key()) ? snapshotName : "";
it.value() = info;
}
reply["units"] = allUnits;
emit data(dataType, reply);
}
} catch (error::Error const &e) {
emit error(Vault::Data, e.m);
} catch (...) {
emit error(Vault::Data, map({{"Exception", "unknown"}}));
}
}
signals:
void progress(Vault::Operation op, const QVariantMap &map);
void error(Vault::Operation op, const QVariantMap &error);
void done(Vault::Operation op, const QVariantMap &);
void data(Vault::DataType id, const QVariantMap &data);
public:
vault::Vault *m_vault;
......@@ -223,6 +290,7 @@ void Vault::initWorker(bool reload)
connect(m_worker, &Worker::progress, this, &Vault::progress);
connect(m_worker, &Worker::error, this, &Vault::error);
connect(m_worker, &Worker::done, this, &Vault::done);
connect(m_worker, &Worker::data, this, &Vault::data);
}
try {
m_worker->init(m_root);
......@@ -271,11 +339,7 @@ QStringList Vault::snapshots() const
QVariantMap Vault::units() const
{
QVariantMap units;
for (auto &u: m_worker->m_vault->config().units()) {
units.insert(u.name(), u.data());
}
return units;
return m_worker->units();
}
void Vault::resetHead()
......@@ -322,4 +386,37 @@ void Vault::startGc()
debug::error("Can't start vault-gc.service");
}
void Vault::requestData(DataType dataType, QVariantMap const &context)
{
QMetaObject::invokeMethod(m_worker, "requestData"
, Q_ARG(Vault::DataType, dataType)
, Q_ARG(QVariantMap, context));
}
/// reset storage to the master head, cleanup tree
void Vault::reset()
{
QMetaObject::invokeMethod(m_worker, "reset");
}
Q_INVOKABLE void Vault::backupUnit(const QString &unit)
{
QMetaObject::invokeMethod(m_worker, "backupUnit"
, Q_ARG(QString, m_home)
, Q_ARG(QString, unit));
}
Q_INVOKABLE void Vault::tagSnapshot(const QString &message)
{
QMetaObject::invokeMethod(m_worker, "tagSnapshot", Q_ARG(QString, message));
}
Q_INVOKABLE void Vault::restoreUnit(const QString &snapshot, const QString &unit)
{
QMetaObject::invokeMethod(m_worker, "restoreUnit"
, Q_ARG(QString, snapshot)
, Q_ARG(QString, m_home)
, Q_ARG(QString, unit));
}
#include "vault.moc"
......@@ -27,10 +27,17 @@ public:
Restore,
RemoveSnapshot,
ExportImportPrepare,
ExportImportExecute
ExportImportExecute,
Data,
Maintenance
}
Q_ENUMS(Operation);
enum DataType {
SnapshotUnits
}
Q_ENUMS(DataType);
explicit Vault(QObject *parent = nullptr);
~Vault();
......@@ -53,6 +60,13 @@ public:
Q_INVOKABLE void registerUnit(const QJSValue &unit, bool global);
Q_INVOKABLE void startGc();
Q_INVOKABLE void requestData(DataType, QVariantMap const &);
Q_INVOKABLE void reset();
Q_INVOKABLE void backupUnit(const QString &unit);
Q_INVOKABLE void tagSnapshot(const QString &message);
Q_INVOKABLE void restoreUnit(const QString &, const QString &);
signals:
void rootChanged();
......@@ -62,6 +76,8 @@ signals:
void progress(Operation operation, const QVariantMap &data);
void error(Operation operation, const QVariantMap &error);
void data(DataType id, const QVariantMap &context);
private:
void initWorker(bool reload);
......
This diff is collapsed.
configure_file(vault-gc.service.in vault-gc.service @ONLY)
install(
PROGRAMS git-vault-gc gc-default
PROGRAMS git-vault-gc gc-default git-vault-snapshot-units
DESTINATION ${TOOLS_DIR}
)
install(
FILES git-vault-rebase-generate.awk git-vault-rebase-prepare.awk
FILES git-vault-rebase-generate.awk git-vault-rebase-prepare.awk vault-misc
DESTINATION ${TOOLS_DIR}
)
......@@ -63,6 +63,41 @@ function gen_cmd {
cat $cmd_file | gawk -f $src/git-vault-rebase-generate.awk
}
function git_gc {
echo "GC"
git prune
git gc --aggressive
echo "PRUNE+"
git prune
}
function git_clear_reflog {
echo "CLEAR REFLOG"
git reflog expire --expire=now --all || error "clearing reflog"
}
function git_rm_dangling_blobs {
echo "REMOVING DANGLING BLOBS"
for obj in $(git fsck --unreachable master \
| grep '^unreachable blob' \
| sed 's/unreachable blob //'); do
for blob in $(git show $obj \
| head -n 1 \
| grep '\.\./\.git/blobs' \
| sed 's:^[./]*\.git/blobs:.git/blobs:'); do
echo "Orphan $blob"
(test -f $blob && (rm $blob -f || echo "Can't remove $blob")) \
|| echo "No such blob $blob"
done
done
}
function git_prune_all_unreferenced {
git_clear_reflog
git_rm_dangling_blobs
git_gc
}
if ($dump || $dump_intention); then
$dump_intention && cat $cmd_file
$dump && gen_cmd
......@@ -70,23 +105,17 @@ if ($dump || $dump_intention); then
fi
if ! grep '^\(old_tag\|skip\)' $cmd_file; then
echo "There is no need in gc for the $root"
echo "There is no need in tree clean-up for the $root"
if ! $force; then
echo "Just checking for dangling blobs and doing gc"
git_prune_all_unreferenced
exit 0
fi
echo "Forcing gc"
echo "Forcing tree clean-up and gc"
fi
cmd=$(gen_cmd)
function git_gc {
echo "GC"
git prune
git gc --aggressive
echo "PRUNE+"
git prune
}
function rollback {
echo "ROLLBACK"
git reset --hard
......@@ -111,21 +140,6 @@ echo "REPLACE MASTER"
git branch -m migrated master && \
git branch -D old-master) || error "replacing master"
echo "CLEAR REFLOG"
git reflog expire --expire=now --all || error "clearing reflog"
echo "REMOVING DANGLING BLOBS"
for obj in $(git fsck --unreachable master \
| grep '^unreachable blob' \
| sed 's/unreachable blob //'); do
for blob in $(git show $obj \
| head -n 1 \
| grep '\.\./\.git/blobs' \
| sed 's:^[./]*\.git/blobs:.git/blobs:'); do
echo "Orphan $blob"
(test -f $blob && (rm $blob -f || echo "Can't remove $blob")) \
|| echo "No such blob $blob"
done
done
git_gc
git_prune_all_unreferenced
echo "OK"
......@@ -32,9 +32,9 @@ function prepare_commands() {
split(commits[name], ids, SUBSEP);
push_step("data:" name);
if (length(ids) == 1) {
push_command("git cherry-pick " ids[1]);
push_command("git cherry-pick --allow-empty " ids[1]);
} else {
cmd="git cherry-pick " ids[1];
cmd="git cherry-pick --allow-empty " ids[1];
for (i = 1; i <= length(ids); i++) {
cmd = cmd " && git cherry-pick --no-commit " ids[i] \
" && git commit --no-edit --amend --allow-empty";
......@@ -57,7 +57,7 @@ function prepare_commands() {
push_command("git commit --no-edit --amend --allow-empty");
} else {
push_step("tag:" tag);
push_command("git cherry-pick " id);
push_command("git cherry-pick --allow-empty " id);
}
tmp_tag = "migrate/" tag
push_command(sprintf("git tag -f '%s'", tmp_tag));
......@@ -77,7 +77,7 @@ $1 == "add" {
$1 == "old_tag" {
push_step("old_tag:" $3);
if (length(old_tags) == 0) {
push(old_tags, length(old_tags), "git cherry-pick " $2);
push(old_tags, length(old_tags), "git cherry-pick --allow-empty " $2);
} else {
push(old_tags, length(old_tags), "git cherry-pick --no-commit " $2);
push(old_tags, length(old_tags), "git commit --no-edit --amend --allow-empty");
......@@ -90,7 +90,7 @@ $1 == "tag" {
$1 == "copy" {
push_step("copy:" $2);
push_command("git cherry-pick " $2);
push_command("git cherry-pick --allow-empty " $2);
}
$1 == "start" {
......
#!/bin/bash
src=$(dirname $0)
src=$(cd $src;pwd)
source $src/vault-misc || exit 1
ensure_param_count_exit_usage $# 1 "<tag>"
tag=">$1"
tag_describe() {
git describe --tags "$1" || error 33 "No tag '$1'"
}
tag=$(tag_describe "$tag")
tag_prev=$((tag_describe "$tag^" | sed -e 's|\(.*\)-[0-9]*-g[0-9a-f]*|\1|') || error 44 "No previous tag")
units=
for c in $(git log --format=%s "$tag_prev..$tag" | grep '^>'); do
unit=$(echo $c | sed -e 's|^>||')
if [[ "x$units" != "x" ]]; then
units+=" $unit"
else
units=$unit
fi
done
echo $units | tr " " "\n" | sort -u | grep -v "^$"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment