mirror of
https://github.com/kopia/kopia.git
synced 2026-03-27 18:42:26 -04:00
* cli: refactored snapshot list * cli: show range tags in snapshot list For example if N snapshots are coalesced together because they have identical roots we may emit now: ``` 2021-03-31 23:09:27 PDT ked3400debc7dd61baffab070bafd59cd (monthly-10) 2021-04-30 06:12:53 PDT kd0576d212e55a831b7ff1636f90a7233 (monthly-4..9) + 5 identical snapshots until 2021-09-30 23:00:19 PDT 2021-10-31 23:22:25 PDT k846bf22aa2863d27f05e820f840b14f8 (monthly-3) 2021-11-08 21:29:31 PST k5793ddcd61ef27b93c75ab74a5828176 (latest-1..3,hourly-1..13,daily-1..7,weekly-1..4,monthly-1..2,annual-1) + 18 identical snapshots until 2021-12-04 10:09:54 PST ``` * server: server-side coalescing of snapshot * ui: added coalescing of retention tags
114 lines
2.6 KiB
Go
114 lines
2.6 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/kopia/kopia/internal/serverapi"
|
|
"github.com/kopia/kopia/snapshot"
|
|
"github.com/kopia/kopia/snapshot/policy"
|
|
)
|
|
|
|
func (s *Server) handleSnapshotList(ctx context.Context, r *http.Request, body []byte) (interface{}, *apiError) {
|
|
si := getSnapshotSourceFromURL(r.URL)
|
|
|
|
manifestIDs, err := snapshot.ListSnapshotManifests(ctx, s.rep, &si, nil)
|
|
if err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
manifests, err := snapshot.LoadSnapshots(ctx, s.rep, manifestIDs)
|
|
if err != nil {
|
|
return nil, internalServerError(err)
|
|
}
|
|
|
|
manifests = snapshot.SortByTime(manifests, false)
|
|
|
|
resp := &serverapi.SnapshotsResponse{
|
|
Snapshots: []*serverapi.Snapshot{},
|
|
}
|
|
|
|
pol, _, _, err := policy.GetEffectivePolicy(ctx, s.rep, si)
|
|
if err == nil {
|
|
pol.RetentionPolicy.ComputeRetentionReasons(manifests)
|
|
}
|
|
|
|
for _, m := range manifests {
|
|
resp.Snapshots = append(resp.Snapshots, convertSnapshotManifest(m))
|
|
}
|
|
|
|
resp.UnfilteredCount = len(resp.Snapshots)
|
|
|
|
if r.URL.Query().Get("all") == "" {
|
|
resp.Snapshots = uniqueSnapshots(resp.Snapshots)
|
|
resp.UniqueCount = len(resp.Snapshots)
|
|
} else {
|
|
resp.UniqueCount = len(uniqueSnapshots(resp.Snapshots))
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func uniqueSnapshots(rows []*serverapi.Snapshot) []*serverapi.Snapshot {
|
|
var result []*serverapi.Snapshot
|
|
|
|
for _, r := range rows {
|
|
if len(result) == 0 {
|
|
result = append(result, r)
|
|
continue
|
|
}
|
|
|
|
last := result[len(result)-1]
|
|
|
|
if r.RootEntry == last.RootEntry {
|
|
last.RetentionReasons = append(last.RetentionReasons, r.RetentionReasons...)
|
|
last.Pins = append(last.Pins, r.Pins...)
|
|
} else {
|
|
result = append(result, r)
|
|
}
|
|
}
|
|
|
|
for _, r := range result {
|
|
r.RetentionReasons = policy.CompactRetentionReasons(r.RetentionReasons)
|
|
r.Pins = policy.CompactPins(r.Pins)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func sourceMatchesURLFilter(src snapshot.SourceInfo, query url.Values) bool {
|
|
if v := query.Get("host"); v != "" && src.Host != v {
|
|
return false
|
|
}
|
|
|
|
if v := query.Get("userName"); v != "" && src.UserName != v {
|
|
return false
|
|
}
|
|
|
|
if v := query.Get("path"); v != "" && src.Path != v {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func convertSnapshotManifest(m *snapshot.Manifest) *serverapi.Snapshot {
|
|
e := &serverapi.Snapshot{
|
|
ID: m.ID,
|
|
Description: m.Description,
|
|
StartTime: m.StartTime,
|
|
EndTime: m.EndTime,
|
|
IncompleteReason: m.IncompleteReason,
|
|
RootEntry: m.RootObjectID().String(),
|
|
RetentionReasons: append([]string{}, m.RetentionReasons...),
|
|
Pins: append([]string{}, m.Pins...),
|
|
}
|
|
|
|
if re := m.RootEntry; re != nil {
|
|
e.Summary = re.DirSummary
|
|
}
|
|
|
|
return e
|
|
}
|