Manifest delete (DELETE /v2/<name>/manifests/<digest>): rejects tag references with 405 UNSUPPORTED per OCI spec, cascades to tags and manifest_blobs via ON DELETE CASCADE, returns 202 Accepted. Blob delete (DELETE /v2/<name>/blobs/<digest>): removes manifest_blobs associations only — blob row and file are preserved for GC to handle, since other repos may reference the same content-addressed blob. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
63 lines
1.7 KiB
Go
63 lines
1.7 KiB
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// DeleteManifest deletes the manifest with the given digest from a repository.
|
|
// ON DELETE CASCADE handles manifest_blobs and tags rows.
|
|
func (d *DB) DeleteManifest(repoID int64, digest string) error {
|
|
result, err := d.Exec(
|
|
`DELETE FROM manifests WHERE repository_id = ? AND digest = ?`,
|
|
repoID, digest,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("db: delete manifest: %w", err)
|
|
}
|
|
n, err := result.RowsAffected()
|
|
if err != nil {
|
|
return fmt.Errorf("db: delete manifest rows affected: %w", err)
|
|
}
|
|
if n == 0 {
|
|
return ErrManifestNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteBlobFromRepo removes the manifest_blobs associations for a blob
|
|
// in the given repository. It does NOT delete the blob row or file — that
|
|
// is GC's job, since other repositories may reference the same blob.
|
|
// Returns ErrBlobNotFound if the blob is not referenced in this repo.
|
|
func (d *DB) DeleteBlobFromRepo(repoID int64, digest string) error {
|
|
// First check that the blob exists and is in this repo.
|
|
var blobID int64
|
|
err := d.QueryRow(`SELECT id FROM blobs WHERE digest = ?`, digest).Scan(&blobID)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return ErrBlobNotFound
|
|
}
|
|
return fmt.Errorf("db: find blob: %w", err)
|
|
}
|
|
|
|
result, err := d.Exec(
|
|
`DELETE FROM manifest_blobs
|
|
WHERE blob_id = ? AND manifest_id IN (
|
|
SELECT id FROM manifests WHERE repository_id = ?
|
|
)`,
|
|
blobID, repoID,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("db: delete blob from repo: %w", err)
|
|
}
|
|
n, err := result.RowsAffected()
|
|
if err != nil {
|
|
return fmt.Errorf("db: delete blob from repo rows affected: %w", err)
|
|
}
|
|
if n == 0 {
|
|
return ErrBlobNotFound
|
|
}
|
|
return nil
|
|
}
|