mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-11-09 15:49:16 -05:00
* Delete cached artifacts through the API and the UI
cache_delete (PROXY_CACHE_DELETE) registers
DELETE /api/cache/{ecosystem}/{name}/{version}, which removes a
version's cached files, or only ?filename=, so the next request fetches
them from the upstream again. Records are cleared and the stored objects
queued for deletion like a replaced artifact. Pushed archives are left
alone: a whole-version delete skips them and naming one answers 409.
With it enabled, the version page shows a Delete button for each cached
file and one for the whole version. The UI calls /ui/api/cache so the
same ingress rules that guard /ui guard its deletes. Neither route has
authentication of its own, so the option is off by default.
* Load the cache delete script from a static file
Move the version page's delete-button JavaScript into
static/cache-delete.js and load it with a script tag, as
packages-list.js does.
---------
Co-authored-by: Giles Westwood <201443+gilesw@users.noreply.github.com>
86 lines
2.9 KiB
Go
86 lines
2.9 KiB
Go
package server
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/git-pkgs/proxy/internal/database"
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
// CacheDeleteResponse lists the cached files removed for a version.
|
|
type CacheDeleteResponse struct {
|
|
PURL string `json:"purl"`
|
|
Deleted []string `json:"deleted"`
|
|
}
|
|
|
|
// handleCacheDelete handles DELETE /api/cache/{ecosystem}/{name}/{version}
|
|
// @Summary Delete cached artifacts
|
|
// @Description Removes the cached files of name@version, or only the one named by filename, so the next request fetches them from the upstream again. Pushed archives are not touched; delete those through /api/hosted.
|
|
// @Tags cache
|
|
// @Produce json
|
|
// @Param ecosystem path string true "Ecosystem"
|
|
// @Param name path string true "Package name as shown in the UI, e.g. com.google.guava:guava for Maven"
|
|
// @Param version path string true "Version"
|
|
// @Param filename query string false "Delete only this file"
|
|
// @Success 200 {object} CacheDeleteResponse
|
|
// @Failure 400 {object} ErrorResponse
|
|
// @Failure 404 {object} ErrorResponse
|
|
// @Failure 409 {object} ErrorResponse
|
|
// @Router /api/cache/{ecosystem}/{name}/{version} [delete]
|
|
func (s *Server) handleCacheDelete(w http.ResponseWriter, r *http.Request) {
|
|
segments, err := packagePathSegments(r)
|
|
if err != nil {
|
|
badRequest(w, err.Error())
|
|
return
|
|
}
|
|
if len(segments) < minVersionPathSegments {
|
|
badRequest(w, "path must be /api/cache/{ecosystem}/{name}/{version}")
|
|
return
|
|
}
|
|
last := len(segments) - 1
|
|
ecosystem, name, version := chi.URLParam(r, "ecosystem"), strings.Join(segments[:last], "/"), segments[last]
|
|
filename := r.URL.Query().Get("filename")
|
|
|
|
versionPURL := s.cachedVersionPURL(ecosystem, name, version)
|
|
if versionPURL == "" {
|
|
notFound(w, "package not found")
|
|
return
|
|
}
|
|
artifacts, err := s.db.GetArtifactsByVersionPURL(versionPURL)
|
|
if err != nil {
|
|
s.logger.Error("failed to list artifacts", "purl", versionPURL, "error", err)
|
|
internalError(w, "failed to list artifacts")
|
|
return
|
|
}
|
|
|
|
deleted := []string{}
|
|
for _, art := range artifacts {
|
|
if filename != "" && art.Filename != filename {
|
|
continue
|
|
}
|
|
if !art.StoragePath.Valid {
|
|
continue
|
|
}
|
|
if art.Source == database.SourceLocal {
|
|
if filename != "" {
|
|
writeError(w, http.StatusConflict, ErrCodeConflict, "pushed archives are deleted through /api/hosted")
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
if err := s.db.DiscardArtifact(versionPURL, art.Filename, art.StoragePath.String); err != nil {
|
|
s.logger.Error("failed to delete cached artifact", "purl", versionPURL, "filename", art.Filename, "error", err)
|
|
internalError(w, "failed to delete cached artifact")
|
|
return
|
|
}
|
|
deleted = append(deleted, art.Filename)
|
|
}
|
|
if len(deleted) == 0 {
|
|
notFound(w, "no cached artifact matched")
|
|
return
|
|
}
|
|
|
|
s.logger.Info("deleted cached artifacts", "purl", versionPURL, "files", deleted)
|
|
writeJSON(w, CacheDeleteResponse{PURL: versionPURL, Deleted: deleted})
|
|
}
|