Files
sausage/extensions/workspaces/tree.ts
T

51 lines
2.5 KiB
TypeScript

/** World Git execution, inherited caller identity, and VFS-only checkout registration checks. */
import { Started } from '../messages/addresses.ts'
export const resolve = (base:string,path:string) => {
const parts:string[]=[]
for(const part of (path.startsWith('/')?path:`${base}/${path}`).split('/')) {
if(part==='..')parts.pop();else if(part&&part!=='.')parts.push(part)
}
return '/'+parts.join('/')
}
export async function chain(host:any,id:number,context:any):Promise<string[]> {
const ids=new Set<number>()
const visit=async(id:number)=>{
if(ids.has(id))return
ids.add(id)
const row=await host.harness().commit((tx:any)=>tx.conversation(id),context)
const up=row?.owner?.conversationId??row?.parent?.conversationId
if(up!==undefined)await visit(up)
const starter=(await host.harness().snapshot(Started,id,context))?.by
if(starter!==undefined)await visit(starter)
}
await visit(id)
return [...ids].map(String)
}
export const git = async(host:any,cwd:string,args:string[],identity:any={})=>{
const result=await host.exec(['git',...args],{cwd,timeout:30,...identity})
if(result.code)throw new Error(`${cwd}: git ${args.join(' ')}: ${result.stderr||result.stdout||`exited ${result.code}`}`)
return result.stdout.trim()
}
export async function mkdir(host:any,path:string) {
let current=''
for(const part of path.split('/').filter(Boolean)) {
current+='/'+part
try {await host.fs.mkdir(current)} catch(error) {if((error as any).code!=='already_exists')throw error}
}
}
export async function gitdir(host:any,source:string) {
const path=`${source}/.git`
return (await host.fs.stat(path)).kind==='directory'?path:resolve(source,(await host.fs.read(path)).trim().replace(/^gitdir: /,''))
}
export async function registered(host:any,workspace:{source:string;path:string}) {
try {
const admin=await gitdir(host,workspace.path)
const source=await gitdir(host,workspace.source)
const common=await host.fs.read(`${source}/commondir`).then((p:string)=>resolve(source,p.trim()),(e:any)=>{if(e.code==='not_found')return source;throw e})
return admin.startsWith(`${common}/worktrees/`) &&
resolve(admin,(await host.fs.read(`${admin}/gitdir`)).trim())===`${workspace.path}/.git` &&
(await host.fs.stat(`${admin}/HEAD`)).kind==='file'
} catch(error) {if((error as any).code==='not_found')return false;throw error}
}
export const hash=(text:string)=>{let hash=2166136261;for(const c of text)hash=Math.imul(hash^c.charCodeAt(0),16777619);return (hash>>>0).toString(16)}