UNPKG

git-documentdb

Version:

Offline-first database that syncs with Git

247 lines 11.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.combineDatabaseWithTheirs = void 0; /* eslint-disable no-await-in-loop */ /** * 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 this source tree. */ const path_1 = __importDefault(require("path")); const isomorphic_git_1 = __importDefault(require("isomorphic-git")); const fs_extra_1 = __importDefault(require("fs-extra")); const ulid_1 = require("ulid"); const rimraf_1 = __importDefault(require("rimraf")); const blob_1 = require("../crud/blob"); const error_1 = require("../error"); const const_1 = require("../const"); const utils_1 = require("../utils"); const remote_engine_1 = require("./remote_engine"); /** * Clone a remote repository and combine the current local working directory with it. * TODO: Must catch errors * * @throws {@link Err.FileRemoveTimeoutError} * * @throws # Errors from RemoteEngine[engineName].clone * @throws - {@link RemoteErr.InvalidURLFormatError} * @throws - {@link RemoteErr.NetworkError} * @throws - {@link RemoteErr.HTTPError401AuthorizationRequired} * @throws - {@link RemoteErr.HTTPError404NotFound} * @throws - {@link RemoteErr.CannotConnectError} * * @throws - {@link RemoteErr.HttpProtocolRequiredError} * @throws - {@link RemoteErr.InvalidRepositoryURLError} * @throws - {@link RemoteErr.InvalidSSHKeyPathError} * * @throws - {@link RemoteErr.InvalidAuthenticationTypeError} * * @public */ // eslint-disable-next-line complexity async function combineDatabaseWithTheirs(gitDDB, remoteOptions, remoteName) { // Clone repository if remoteURL exists const remoteDir = gitDDB.workingDir + '_' + (0, ulid_1.ulid)(Date.now()); const tmpLocalDir = gitDDB.workingDir + '_' + (0, ulid_1.ulid)(Date.now()); const duplicates = []; try { await remote_engine_1.RemoteEngine[remoteOptions.connection.engine] .clone(remoteDir, remoteOptions, remoteName, gitDDB.tsLogger) .catch(err => { throw (0, remote_engine_1.wrappingRemoteEngineError)(err); }); // Add refs to remote branch const remoteCommitOid = await isomorphic_git_1.default.resolveRef({ fs: fs_extra_1.default, dir: remoteDir, ref: `refs/remotes/origin/${gitDDB.defaultBranch}`, }); await isomorphic_git_1.default.writeRef({ fs: fs_extra_1.default, dir: remoteDir, ref: `refs/remotes/${remoteName}/${gitDDB.defaultBranch}`, value: remoteCommitOid, force: true, }); // Overwrite upstream branch await isomorphic_git_1.default.setConfig({ fs: fs_extra_1.default, dir: remoteDir, path: `branch.${gitDDB.defaultBranch}.remote`, value: remoteName, }); await isomorphic_git_1.default.setConfig({ fs: fs_extra_1.default, dir: remoteDir, path: `branch.${gitDDB.defaultBranch}.merge`, value: `refs/heads/${gitDDB.defaultBranch}`, }); const localMetadataList = await (0, utils_1.getAllMetadata)(gitDDB.workingDir, gitDDB.serializeFormat); const remoteMetadataList = await (0, utils_1.getAllMetadata)(remoteDir, gitDDB.serializeFormat); const remoteNames = remoteMetadataList.map(meta => meta.name); for (let i = 0; i < localMetadataList.length; i++) { const meta = localMetadataList[i]; const localFilePath = path_1.default.resolve(gitDDB.workingDir, meta.name); const remoteFilePath = path_1.default.resolve(remoteDir, meta.name); const dir = path_1.default.dirname(remoteFilePath); await fs_extra_1.default.ensureDir(dir); const docType = gitDDB.serializeFormat.hasObjectExtension(localFilePath) ? 'json' : 'text'; // eslint-disable-next-line max-depth if (docType === 'text') { // TODO: select binary or text by .gitattribtues } if (remoteNames.includes(meta.name)) { // Add postfix and copy localFilePath to remoteFilePath if remoteFilePath exists let duplicatedFileName = ''; let duplicatedFileId = ''; let duplicatedFileExt = ''; const postfix = const_1.DUPLICATED_FILE_POSTFIX + gitDDB.dbId; let original; let duplicate; const remoteFile = remoteMetadataList.find(data => data.name === meta.name); if (docType === 'json') { let doc; // eslint-disable-next-line max-depth if (gitDDB.serializeFormat.format === 'front-matter') { const txt = fs_extra_1.default.readFileSync(localFilePath, { encoding: 'utf8', }); const [, extension] = localFilePath.match(/.+(\..+?)$/); doc = (0, blob_1.textToJsonDoc)(txt, gitDDB.serializeFormat, extension); } else { doc = fs_extra_1.default.readJSONSync(localFilePath); } const _id = meta._id; // eslint-disable-next-line max-depth if (doc._id !== undefined) { doc._id = _id + postfix; } duplicatedFileName = _id + postfix + gitDDB.serializeFormat.extension(doc); duplicatedFileId = _id + postfix; duplicatedFileExt = gitDDB.serializeFormat.extension(doc); fs_extra_1.default.writeFileSync(path_1.default.resolve(remoteDir, duplicatedFileName), gitDDB.serializeFormat.serialize(doc).data); const duplicatedOid = (await isomorphic_git_1.default.hashBlob({ object: gitDDB.serializeFormat.serialize(doc).data })).oid; original = { _id, name: meta.name, fileOid: remoteFile.fileOid, type: 'json', }; duplicate = { _id: duplicatedFileId, name: duplicatedFileName, fileOid: duplicatedOid, type: 'json', }; } else { // Add postfix before extension. duplicatedFileExt = path_1.default.extname(localFilePath); const onlyName = localFilePath.replace(new RegExp(duplicatedFileExt + '$'), ''); duplicatedFileName = onlyName + postfix + duplicatedFileExt; fs_extra_1.default.copyFileSync(localFilePath, path_1.default.resolve(remoteDir, duplicatedFileName)); original = { name: meta.name, fileOid: remoteFile.fileOid, type: docType, }; duplicate = { name: duplicatedFileName, fileOid: meta.fileOid, type: docType, }; } await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: remoteDir, filepath: duplicatedFileName }); duplicates.push({ original, duplicate, }); } else { // Copy localFilePath to remoteFilePath if remoteFilePath not exists await fs_extra_1.default.copyFile(localFilePath, remoteFilePath); await isomorphic_git_1.default.add({ fs: fs_extra_1.default, dir: remoteDir, filepath: meta.name }); } } if (localMetadataList.length > 0) { const commitMessage = 'combine database head with theirs'; await isomorphic_git_1.default.commit({ fs: fs_extra_1.default, dir: remoteDir, author: gitDDB.author, committer: gitDDB.committer, message: commitMessage, }); } await fs_extra_1.default.rename(gitDDB.workingDir, tmpLocalDir); await fs_extra_1.default.rename(remoteDir, gitDDB.workingDir); const userName = await isomorphic_git_1.default .getConfig({ fs: fs_extra_1.default, dir: tmpLocalDir, path: 'user.name' }) .catch(() => undefined); const userEmail = await isomorphic_git_1.default .getConfig({ fs: fs_extra_1.default, dir: tmpLocalDir, path: 'user.email' }) .catch(() => undefined); if (userName) { await isomorphic_git_1.default.setConfig({ fs: fs_extra_1.default, dir: gitDDB.workingDir, path: 'user.name', value: userName, }); } if (userEmail) { await isomorphic_git_1.default.setConfig({ fs: fs_extra_1.default, dir: gitDDB.workingDir, path: 'user.email', value: userEmail, }); } } catch (e) { console.log(e); throw e; } finally { await new Promise((resolve, reject) => { // Set timeout because rimraf sometimes does not catch EPERM error. setTimeout(() => { reject(new error_1.Err.FileRemoveTimeoutError()); }, const_1.FILE_REMOVE_TIMEOUT); (0, rimraf_1.default)(remoteDir, error => { if (error) { reject(error); } resolve(); }); }); await new Promise((resolve, reject) => { // Set timeout because rimraf sometimes does not catch EPERM error. setTimeout(() => { reject(new error_1.Err.FileRemoveTimeoutError()); }, const_1.FILE_REMOVE_TIMEOUT); (0, rimraf_1.default)(tmpLocalDir, error => { if (error) { reject(error); } resolve(); }); }); } await gitDDB.loadDbInfo(); const result = { action: 'combine database', duplicates, }; return result; } exports.combineDatabaseWithTheirs = combineDatabaseWithTheirs; //# sourceMappingURL=combine.js.map