|
|
@@ -1,14 +1,7 @@
|
|
|
import { App } from "../app/app"
|
|
|
-import {
|
|
|
- add,
|
|
|
- commit,
|
|
|
- init,
|
|
|
- checkout,
|
|
|
- statusMatrix,
|
|
|
- remove,
|
|
|
-} from "isomorphic-git"
|
|
|
+import { $ } from "bun"
|
|
|
import path from "path"
|
|
|
-import fs from "fs"
|
|
|
+import fs from "fs/promises"
|
|
|
import { Ripgrep } from "../file/ripgrep"
|
|
|
import { Log } from "../util/log"
|
|
|
|
|
|
@@ -19,76 +12,52 @@ export namespace Snapshot {
|
|
|
log.info("creating snapshot")
|
|
|
const app = App.info()
|
|
|
const git = gitdir(sessionID)
|
|
|
- const files = await Ripgrep.files({
|
|
|
- cwd: app.path.cwd,
|
|
|
- limit: app.git ? undefined : 1000,
|
|
|
- })
|
|
|
- log.info("found files", { count: files.length })
|
|
|
- // not a git repo and too big to snapshot
|
|
|
- if (!app.git && files.length === 1000) return
|
|
|
- await init({
|
|
|
- dir: app.path.cwd,
|
|
|
- gitdir: git,
|
|
|
- fs,
|
|
|
- })
|
|
|
- log.info("initialized")
|
|
|
- const status = await statusMatrix({
|
|
|
- fs,
|
|
|
- gitdir: git,
|
|
|
- dir: app.path.cwd,
|
|
|
- })
|
|
|
- log.info("matrix", {
|
|
|
- count: status.length,
|
|
|
- })
|
|
|
- const added = []
|
|
|
- for (const [file, head, workdir, stage] of status) {
|
|
|
- if (workdir === 0 && stage === 1) {
|
|
|
- log.info("remove", { file })
|
|
|
- await remove({
|
|
|
- fs,
|
|
|
- gitdir: git,
|
|
|
- dir: app.path.cwd,
|
|
|
- filepath: file,
|
|
|
+
|
|
|
+ // not a git repo, check if too big to snapshot
|
|
|
+ if (!app.git) {
|
|
|
+ const files = await Ripgrep.files({
|
|
|
+ cwd: app.path.cwd,
|
|
|
+ limit: 1000,
|
|
|
+ })
|
|
|
+ log.info("found files", { count: files.length })
|
|
|
+ if (files.length > 1000) return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (await fs.mkdir(git, { recursive: true })) {
|
|
|
+ await $`git init`
|
|
|
+ .env({
|
|
|
+ ...process.env,
|
|
|
+ GIT_DIR: git,
|
|
|
+ GIT_WORK_TREE: app.path.root,
|
|
|
})
|
|
|
- continue
|
|
|
- }
|
|
|
- if (workdir !== head) {
|
|
|
- added.push(file)
|
|
|
- }
|
|
|
+ .quiet()
|
|
|
+ .nothrow()
|
|
|
+ log.info("initialized")
|
|
|
}
|
|
|
- log.info("removed files")
|
|
|
- await add({
|
|
|
- fs,
|
|
|
- gitdir: git,
|
|
|
- parallel: true,
|
|
|
- dir: app.path.cwd,
|
|
|
- filepath: added,
|
|
|
- })
|
|
|
+
|
|
|
+ await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
|
|
|
log.info("added files")
|
|
|
- const result = await commit({
|
|
|
- fs,
|
|
|
- gitdir: git,
|
|
|
- dir: app.path.cwd,
|
|
|
- message: "snapshot",
|
|
|
- author: {
|
|
|
- name: "opencode",
|
|
|
- email: "[email protected]",
|
|
|
- },
|
|
|
- })
|
|
|
- log.info("commit", { result })
|
|
|
- return result
|
|
|
+
|
|
|
+ const result =
|
|
|
+ await $`git --git-dir ${git} commit --allow-empty -m "snapshot" --author="opencode <[email protected]>"`
|
|
|
+ .quiet()
|
|
|
+ .cwd(app.path.cwd)
|
|
|
+ .nothrow()
|
|
|
+ log.info("commit")
|
|
|
+
|
|
|
+ // Extract commit hash from output like "[main abc1234] snapshot"
|
|
|
+ const match = result.stdout.toString().match(/\[.+ ([a-f0-9]+)\]/)
|
|
|
+ if (!match) throw new Error("Failed to extract commit hash")
|
|
|
+ return match[1]
|
|
|
}
|
|
|
|
|
|
export async function restore(sessionID: string, commit: string) {
|
|
|
log.info("restore", { commit })
|
|
|
const app = App.info()
|
|
|
- await checkout({
|
|
|
- fs,
|
|
|
- gitdir: gitdir(sessionID),
|
|
|
- dir: app.path.cwd,
|
|
|
- ref: commit,
|
|
|
- force: true,
|
|
|
- })
|
|
|
+ const git = gitdir(sessionID)
|
|
|
+ await $`git --git-dir=${git} checkout ${commit} --force`
|
|
|
+ .quiet()
|
|
|
+ .cwd(app.path.root)
|
|
|
}
|
|
|
|
|
|
function gitdir(sessionID: string) {
|