upatde: dockerfile init blender

This commit is contained in:
Tom Boullay
2026-04-14 14:06:04 +02:00
parent 2b3d02e489
commit ab9685b6ee
5 changed files with 264 additions and 65 deletions
+105 -23
View File
@@ -88,23 +88,85 @@ function validateFolder(files: File[]): { model?: File; textures: TextureFile[];
return result
}
async function checkFolderExists(
folderName: string,
/** Compute the git blob SHA1 for a file (same as `git hash-object`) */
async function computeGitBlobSha(file: File): Promise<string> {
const buffer = await file.arrayBuffer()
const content = new Uint8Array(buffer)
const header = new TextEncoder().encode(`blob ${content.length}\0`)
const store = new Uint8Array(header.length + content.length)
store.set(header)
store.set(content, header.length)
const hashBuffer = await crypto.subtle.digest('SHA-1', store)
const hashArray = Array.from(new Uint8Array(hashBuffer))
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
}
interface FileDiff {
name: string
status: 'changed' | 'new' | 'deleted'
}
interface CheckResult {
exists: boolean
diffs: FileDiff[]
}
async function checkFolderDiffs(
folder: FolderEntry,
destination: string,
secret: string,
): Promise<{ exists: boolean; files: string[] }> {
): Promise<CheckResult> {
try {
const params = new URLSearchParams({ folderName, destination })
const params = new URLSearchParams({ folderName: folder.folderName, destination })
const res = await fetch(`/api/upload?${params}`, {
headers: { 'x-upload-secret': secret.trim() },
})
const data = await res.json()
if (data.success && data.exists) {
return { exists: true, files: data.files || [] }
if (!data.success || !data.exists) {
return { exists: false, diffs: [] }
}
return { exists: false, files: [] }
const remoteFiles: { name: string; sha: string }[] = data.files || []
const remoteMap = new Map(remoteFiles.map(f => [f.name.toLowerCase(), f.sha]))
// Compute SHA for all local files
const localFiles: { name: string; sha: string }[] = []
localFiles.push({
name: folder.modelFile.name,
sha: await computeGitBlobSha(folder.modelFile),
})
for (const tex of folder.textures) {
localFiles.push({
name: tex.name,
sha: await computeGitBlobSha(tex.file),
})
}
const diffs: FileDiff[] = []
const localNames = new Set<string>()
for (const local of localFiles) {
const key = local.name.toLowerCase()
localNames.add(key)
const remoteSha = remoteMap.get(key)
if (!remoteSha) {
diffs.push({ name: local.name, status: 'new' })
} else if (remoteSha !== local.sha) {
diffs.push({ name: local.name, status: 'changed' })
}
// unchanged → not in diffs
}
// Files on remote but not in local → deleted
for (const [name] of remoteMap) {
if (!localNames.has(name)) {
diffs.push({ name, status: 'deleted' })
}
}
return { exists: true, diffs }
} catch {
return { exists: false, files: [] }
return { exists: false, diffs: [] }
}
}
@@ -163,7 +225,7 @@ export default function UploadZone() {
const [secretError, setSecretError] = useState<string | null>(null)
const [destination, setDestination] = useState<typeof DESTINATIONS[number]['value']>(DESTINATIONS[0].value)
const [abortController, setAbortController] = useState<AbortController | null>(null)
const [overwriteConfirm, setOverwriteConfirm] = useState<{ folderName: string; files: string[] } | null>(null)
const [overwriteConfirm, setOverwriteConfirm] = useState<{ folderName: string; diffs: FileDiff[] } | null>(null)
const isSecretEmpty = !secret.trim()
@@ -181,11 +243,16 @@ export default function UploadZone() {
setSecretError(null)
setGlobalError(null)
// Check if folder already exists on remote
// Check if folder already exists on remote and compute diffs
const folder = files[0]
const check = await checkFolderExists(folder.folderName, destination, secret)
const check = await checkFolderDiffs(folder, destination, secret)
if (check.exists) {
setOverwriteConfirm({ folderName: folder.folderName, files: check.files })
if (check.diffs.length === 0) {
// Nothing changed at all
setGlobalError('Aucun fichier modifie — le dossier distant est identique.')
return
}
setOverwriteConfirm({ folderName: folder.folderName, diffs: check.diffs })
return
}
@@ -532,26 +599,41 @@ export default function UploadZone() {
<div>
<h3 className="text-sm font-semibold text-gray-100">Dossier deja existant</h3>
<p className="text-xs text-gray-400 mt-0.5">
<span className="font-mono text-yellow-400">{destination}/{overwriteConfirm.folderName}</span> existe deja sur le repo.
<span className="font-mono text-yellow-400">{destination}/{overwriteConfirm.folderName}</span> existe deja sur le repo
</p>
</div>
</div>
{overwriteConfirm.files.length > 0 && (
<div className="bg-black-800 border border-white/10 rounded-xl p-3 max-h-32 overflow-y-auto">
<p className="text-xs text-gray-500 mb-1.5">Fichiers existants qui seront remplaces :</p>
<ul className="space-y-0.5">
{overwriteConfirm.files.map((f) => (
<li key={f} className="text-xs text-gray-400 font-mono">{f}</li>
{overwriteConfirm.diffs.length > 0 && (
<div className="bg-black-800 border border-white/10 rounded-xl p-3 max-h-40 overflow-y-auto">
<p className="text-xs text-gray-500 mb-2">Modifications detectees :</p>
<ul className="space-y-1">
{overwriteConfirm.diffs.map((d) => (
<li key={d.name} className="flex items-center gap-2 text-xs font-mono">
{d.status === 'changed' && (
<>
<span className="text-yellow-400">🔄</span>
<span className="text-gray-300">{d.name}</span>
</>
)}
{d.status === 'new' && (
<>
<span className="text-green-400"></span>
<span className="text-gray-300">{d.name}</span>
</>
)}
{d.status === 'deleted' && (
<>
<span className="text-red-400"></span>
<span className="text-gray-500 line-through">{d.name}</span>
</>
)}
</li>
))}
</ul>
</div>
)}
<p className="text-xs text-gray-400">
Les anciens fichiers seront supprimes et remplaces par les nouveaux. Cette action est irreversible.
</p>
<div className="flex gap-3">
<button
onClick={() => setOverwriteConfirm(null)}