mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-11-11 00:29:15 -05:00
Resolvers take a version's dependencies from the registry metadata, not from the archive, so listing a pushed version needs its manifest. A push now reads package.json from the top directory of an npm tarball, or composer.json from the root or the single top directory of a Composer zip, and keeps it in the new artifacts.manifest column (migration 013_add_artifact_manifest). The manifest has to name the pushed package and version. A Composer manifest may leave the version out, and its name is compared case-insensitively. An archive that can't be read or whose manifest names something else is refused with 400 and removed from storage. The version's integrity is now the archive's sha512, which npm clients expect in dist.integrity. Refs #134
70 lines
2.2 KiB
Go
70 lines
2.2 KiB
Go
package database
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// LocalArtifact is a pushed artifact with the integrity of its version.
|
|
type LocalArtifact struct {
|
|
Artifact
|
|
Integrity sql.NullString `db:"integrity"`
|
|
}
|
|
|
|
// GetLocalArtifacts returns the artifacts pushed to the proxy for a package,
|
|
// ordered by version and filename.
|
|
func (db *DB) GetLocalArtifacts(packagePURL string) ([]LocalArtifact, error) {
|
|
var artifacts []LocalArtifact
|
|
query := db.Rebind(`
|
|
SELECT a.id, a.version_purl, a.filename, a.upstream_url, a.storage_path, a.content_hash,
|
|
a.size, a.content_type, a.fetched_at, a.hit_count, a.last_accessed_at,
|
|
a.created_at, a.updated_at, a.source, a.manifest, v.integrity
|
|
FROM artifacts a
|
|
JOIN versions v ON v.purl = a.version_purl
|
|
WHERE v.package_purl = ? AND a.source = 'local'
|
|
ORDER BY a.version_purl, a.filename
|
|
`)
|
|
if err := db.Select(&artifacts, query, packagePURL); err != nil {
|
|
return nil, err
|
|
}
|
|
return artifacts, nil
|
|
}
|
|
|
|
// DeleteLocalArtifacts removes the pushed artifacts of a version and queues
|
|
// their stored objects for deletion in the same transaction, so a failed
|
|
// queue keeps the records instead of orphaning the objects. Artifacts cached
|
|
// from an upstream are left alone. It returns how many records it removed.
|
|
func (db *DB) DeleteLocalArtifacts(versionPURL string) (int, error) {
|
|
tx, err := db.Beginx()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer func() { _ = tx.Rollback() }()
|
|
|
|
var paths []string
|
|
selectQuery := db.Rebind(`
|
|
SELECT storage_path FROM artifacts
|
|
WHERE version_purl = ? AND source = 'local' AND storage_path IS NOT NULL
|
|
`)
|
|
if err := tx.Select(&paths, selectQuery, versionPURL); err != nil {
|
|
return 0, fmt.Errorf("reading local artifacts: %w", err)
|
|
}
|
|
|
|
res, err := tx.Exec(db.Rebind(`DELETE FROM artifacts WHERE version_purl = ? AND source = 'local'`), versionPURL)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("deleting local artifacts: %w", err)
|
|
}
|
|
deleted, err := res.RowsAffected()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
queuedAt := time.Now().UTC()
|
|
for _, path := range paths {
|
|
if _, err := tx.Exec(db.Rebind(queuePendingDeleteQuery), path, queuedAt); err != nil {
|
|
return 0, fmt.Errorf("queueing %s for deletion: %w", path, err)
|
|
}
|
|
}
|
|
return int(deleted), tx.Commit()
|
|
}
|