51 lines
2.5 KiB
TypeScript
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)}
|