git-documentdb
Version:
Offline-first database that syncs with Git
147 lines (143 loc) • 5.45 kB
JavaScript
;
/**
* GitDocumentDB
* Copyright (c) Hidekazu Kubota
*
* This source code is licensed under the Mozilla Public License Version 2.0
* found in the LICENSE file in the root directory of gitDDB source tree.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.pushWorker = void 0;
const isomorphic_git_1 = __importDefault(require("isomorphic-git"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const worker_utils_1 = require("./worker_utils");
const remote_engine_1 = require("./remote_engine");
/**
* Push and get changes
*
* @throws # Errors from push
* @throws - {@link InvalidGitRemoteError}
* @throws - {@link UnfetchedCommitExistsError}
* @throws - {@link InvalidURLFormatError}
* @throws - {@link NetworkError}
* @throws - {@link HTTPError401AuthorizationRequired}
* @throws - {@link HTTPError404NotFound}
* @throws - {@link HTTPError403Forbidden}
* @throws - {@link CannotConnectError}
* @throws - {@link CannotConnectError}
* @throws - {@link HttpProtocolRequiredError}
* @throws - {@link InvalidRepositoryURLError}
* @throws - {@link InvalidSSHKeyPathError}
* @throws - {@link InvalidAuthenticationTypeError}
*
* @throws # Errors from getChanges
* @throws - {@link Err.InvalidJsonObjectError}
*
* @internal
*/
// eslint-disable-next-line complexity
async function pushWorker(gitDDB, sync, taskMetadata, skipStartEvent = false, afterMerge = false) {
const syncOptions = sync.options;
if (!skipStartEvent) {
sync.eventHandlers.start.forEach(listener => {
listener.func({ ...taskMetadata, collectionPath: listener.collectionPath }, sync.currentRetries());
});
}
/**
a) The first push
--[baseCommit(remoteCommit)]--(...)--[headCommit(localCommit)]
b) Fast forward
--[baseCommit]--(...)--[remoteCommit]--(...)--[headCommit(localCommit)]
c) HEAD is a merge commit
┌--(...)--[localCommit]---┐
--[baseCommit]--+ +--[headCommit]
└--(...)--[remoteCommit]--┘
*/
const headCommitOid = await isomorphic_git_1.default.resolveRef({
fs: fs_extra_1.default,
dir: gitDDB.workingDir,
ref: 'HEAD',
});
const headCommit = await isomorphic_git_1.default.readCommit({
fs: fs_extra_1.default,
dir: gitDDB.workingDir,
oid: headCommitOid,
});
let localCommitOid;
const remoteCommitOid = await isomorphic_git_1.default
.resolveRef({
fs: fs_extra_1.default,
dir: gitDDB.workingDir,
ref: `refs/remotes/${sync.remoteName}/${gitDDB.defaultBranch}`,
})
.catch(() => undefined);
if (headCommit.commit.parent.length === 2) {
// HEAD is a merge commit.
localCommitOid = headCommit.commit.parent[0];
}
else {
localCommitOid = headCommitOid;
}
let baseCommitOid;
if (remoteCommitOid === undefined) {
// This is the first push in this repository.
// Get the first commit.
const logs = await isomorphic_git_1.default.log({ fs: fs_extra_1.default, dir: gitDDB.workingDir });
baseCommitOid = logs[logs.length - 1].oid;
if (baseCommitOid === localCommitOid) {
baseCommitOid = undefined;
}
}
else {
[baseCommitOid] = await isomorphic_git_1.default.findMergeBase({
fs: fs_extra_1.default,
dir: gitDDB.workingDir,
oids: [localCommitOid, remoteCommitOid],
});
}
// Push
const res = await remote_engine_1.RemoteEngine[sync.engine]
.push(gitDDB.workingDir, syncOptions, sync.remoteName, gitDDB.defaultBranch, gitDDB.defaultBranch, gitDDB.tsLogger)
.catch(err => err);
if (res instanceof Error) {
const error = (0, remote_engine_1.wrappingRemoteEngineError)(res);
if (error instanceof remote_engine_1.RemoteErr.UnfetchedCommitExistsError) {
if (localCommitOid === remoteCommitOid) {
return { action: 'nop' };
}
}
throw error;
}
// NodeGit does not throw UnfetchedCommitExistsError when localCommitOid equals remoteCommitOid,
// So check it again here.
if (localCommitOid === remoteCommitOid) {
return { action: 'nop' };
}
let remoteChanges;
if (afterMerge) {
remoteChanges = undefined;
}
else {
remoteChanges = await (0, worker_utils_1.getChanges)(gitDDB.workingDir, remoteCommitOid, headCommitOid, gitDDB.serializeFormat);
}
const syncResult = {
action: 'push',
changes: {
remote: remoteChanges,
},
};
// Get a list of commits which will be pushed to remote.
let commitListRemote;
if (syncOptions.includeCommits) {
commitListRemote = await (0, worker_utils_1.getCommitLogs)(gitDDB.workingDir, headCommitOid, baseCommitOid, remoteCommitOid);
syncResult.commits = {
remote: commitListRemote,
};
}
return syncResult;
}
exports.pushWorker = pushWorker;
//# sourceMappingURL=push_worker.js.map