From f847cbbfc94f30900e7ddca5e65c6e281199146e Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 3 Mar 2022 18:07:34 +1100 Subject: [PATCH] WIP - #335 - prototyping committing, EOD --- src/vaults/VaultInternal.ts | 65 ++++++++++--- src/vaults/utils.ts | 2 + tests/vaults/gitPrototyping.test.ts | 145 +++++++++++++++++++++++++++- 3 files changed, 195 insertions(+), 17 deletions(-) diff --git a/src/vaults/VaultInternal.ts b/src/vaults/VaultInternal.ts index 4ebd7a8b80..50a7f32df2 100644 --- a/src/vaults/VaultInternal.ts +++ b/src/vaults/VaultInternal.ts @@ -422,6 +422,7 @@ class VaultInternal { // Mirrored vaults are immutable throw new vaultsErrors.ErrorVaultRemoteDefined(); } + const nodeIdEncoded = nodesUtils.encodeNodeId(this.keyManager.getNodeId()); return withF([this.writeLock], async () => { await this.db.put( this.vaultMetadataDbDomain, @@ -435,39 +436,73 @@ class VaultInternal { await f(this.efsVault); // After doing mutation we need to commit the new history // Checking if commit is appending or branching. - const currentBranch = await git.currentBranch({ + const headRef = await git.resolveRef({ fs: this.efs, dir: this.vaultDataDir, gitdir: this.vaultGitDir, - }) - if (currentBranch === vaultsUtils.canonicalBranch) { + ref: 'HEAD', + }); + const masterRef = await git.resolveRef({ + fs: this.efs, + dir: this.vaultDataDir, + gitdir: this.vaultGitDir, + ref: 'refs/heads/master', + }); + if (headRef === masterRef) { // This is an appending commit // We want to commit - await git.commit({ + const commitRef = await git.commit({ fs: this.efs, dir: this.vaultDataDir, gitdir: this.vaultGitDir, author: { - name: nodesUtils.encodeNodeId(this.keyManager.getNodeId()), + name: nodeIdEncoded, }, message: 'tempMessage', + ref: 'HEAD' + }) + // Updating branch pointer + await git.writeRef({ + fs: this.efs, + dir: this.vaultDataDir, + gitdir: this.vaultGitDir, + ref: vaultsUtils.canonicalBranchRef, + value: commitRef, + force: true, }) } else { // This is a branching commit - // We need to; - // 1. Create a new temp branch - // 2. commit to new branch - // 3. rename main to oldMain - // 4. rename newBranch to main - // 5. delete oldMain - // 6. GC oldMain commits - await git.branch({ + /* + We need to; + 1. make new commit + 2. update master pointer + 3. delete old commits following chain from + masterRef -> headRef + */ + // Making commit + const commitRef = await git.commit({ fs: this.efs, dir: this.vaultDataDir, gitdir: this.vaultGitDir, - ref: 'newBranch', - checkout: true, + author: { + name: nodeIdEncoded, + }, + message: 'tempMessage', + ref: 'HEAD', + }); + // Updating master pointer + await git.writeRef({ + fs: this.efs, + dir: this.vaultDataDir, + gitdir: this.vaultGitDir, + ref: 'refs/heads/main', + value: commitRef, + force: true, }) + // Removing old commits + + + // Renaming canonicalBranch throw Error('Not Implemented'); } diff --git a/src/vaults/utils.ts b/src/vaults/utils.ts index 82751a05fa..77b9717649 100644 --- a/src/vaults/utils.ts +++ b/src/vaults/utils.ts @@ -18,6 +18,7 @@ import * as nodesUtils from '../nodes/utils'; * Where branches are automatically made when new timelines are created */ const canonicalBranch = 'master'; +const canonicalBranchRef = 'refs/heads/' + canonicalBranch; const vaultIdGenerator = new IdRandom(); @@ -95,6 +96,7 @@ export { tagLast, refs, canonicalBranch, + canonicalBranchRef, generateVaultId, encodeVaultId, decodeVaultId, diff --git a/tests/vaults/gitPrototyping.test.ts b/tests/vaults/gitPrototyping.test.ts index 2098c9d272..4a34107907 100644 --- a/tests/vaults/gitPrototyping.test.ts +++ b/tests/vaults/gitPrototyping.test.ts @@ -2,6 +2,7 @@ import git from 'isomorphic-git'; import fs from 'fs'; import path from 'path'; import os from 'os'; +import * as vaultsUtils from '@/vaults/utils'; describe('isogit playground, REMOVE THIS', () => { @@ -43,7 +44,7 @@ describe('isogit playground, REMOVE THIS', () => { async function quickCommit(message: string, data: string, ref?: string) { await fs.promises.writeFile(file, data) - await git.commit({ + return await git.commit({ ...commitMeta, message, ref, @@ -79,6 +80,97 @@ describe('isogit playground, REMOVE THIS', () => { expect(await git.currentBranch(dirMeta)).toEqual('main'); expect(await git.listBranches(dirMeta)).toEqual(['main']); }) + test('Committing linear history alt', async () => { + await git.init({ + ...dirMeta, + defaultBranch: 'main', + }); + await quickCommit('first', 'one'); + await quickCommit('second', 'two'); + const log = await shortLog({}); + console.log(log); + expect(log).toHaveLength(2); + expect(log[1]).toContain('first'); + expect(log[0]).toContain('second'); + expect(await git.currentBranch(dirMeta)).toEqual('main'); + expect(await git.listBranches(dirMeta)).toEqual(['main']); + }) + test('GC linear history', async () => { + await git.init({ + ...dirMeta, + defaultBranch: 'master', + }); + await quickCommit('first', 'one'); + const commit = await quickCommit('second', 'two'); + await quickCommit('third', 'three'); + const lastRef = await quickCommit('fourth', 'four'); + console.log('master', await shortLog({})); + + // Moving pointers + await git.checkout({ + ...dirMeta, + ref: commit, + }); + const headRef = await git.resolveRef({ + ...dirMeta, + ref: 'HEAD', + }); + const masterRef = await git.resolveRef({ + ...dirMeta, + ref: 'refs/heads/master', + }); + await git.writeRef({ + ...dirMeta, + ref: 'refs/heads/master', + value: commit, + force: true, + }) + let currentRef = masterRef; + while (currentRef !== headRef) { + //read commit info + const commit = await git.readCommit({ + ...dirMeta, + oid: currentRef, + }) + console.log('removing', commit.oid ); + // delete commit + await git.deleteRef({ + ...dirMeta, + ref: commit.oid, + }) + // getting new ref + const nextRef = commit.commit.parent.pop(); + if (nextRef == null) break; + currentRef = nextRef; + } + console.log('head', await shortLog({})); + console.log('last', await shortLog({ref: lastRef})); + + + currentRef = masterRef; + while (currentRef !== headRef) { + //read commit info + const commit = await git.readCommit({ + ...dirMeta, + oid: currentRef, + }) + console.log('removing', commit.oid ); + // delete commit + await git.deleteRef({ + ...dirMeta, + ref: commit.oid, + }) + // getting new ref + const nextRef = commit.commit.parent.pop(); + if (nextRef == null) break; + currentRef = nextRef; + } + console.log('head', await shortLog({})); + console.log('last', await shortLog({ref: lastRef})); + + + }) + test('Branching', async () => { await git.init({ @@ -161,4 +253,53 @@ describe('isogit playground, REMOVE THIS', () => { console.log(await git.currentBranch(dirMeta)); // main }) -}) \ No newline at end of file + test('Branching ver2', async () => { + await git.init({ + ...dirMeta, + defaultBranch: 'main' + }); + await quickCommit('S', 'one', 'HEAD'); + + // {[S]} + const ref = (await git.log(dirMeta)).pop() + await quickCommit('A', 'two'); + // S => {[A]} + console.log('head', await shortLog({})); + // head [ + // 'A\n: b13c65fdc1e600802106822d111cdc2998eab0ef', + // 'S\n: 95c49e1126dafd347a51bc20d1af845d4f123210' <- saved ref here + // ] + console.log(await git.currentBranch(dirMeta)); + // main + console.log(await git.listBranches(dirMeta)); + // ['main'] + // checkout previous commit + await git.checkout({ + ...dirMeta, + ref: ref!.oid, + }) + // {S} -> [A] + // creating a temp branch + console.log('head', await shortLog({})); + // head [ 'S\n: 95c49e1126dafd347a51bc20d1af845d4f123210' ] + console.log(await git.currentBranch(dirMeta)); + // -------- branching new history + // Start by committing + const commitRef = await quickCommit('B', 'Alternative', 'HEAD'); + await git.writeRef({ + ...dirMeta, + ref: 'refs/heads/main', + value: commitRef, + force: true, + }) + // -------- + console.log('head', await shortLog({})); + // head [ + // 'B\n: d6caf367291919e02faf924a52aee4a169f13b23', + // 'S\n: b36169b025221b408d74f0c146ffcc36eac6bd86' + // ] + console.log('main', await shortLog({ref: 'main'})); + console.log(await git.listBranches(dirMeta)); + console.log(await git.currentBranch(dirMeta)); + }) +})