ref(*): add sorter/filter utilties to releaseutil

pull/1339/head
fibonacci1729 8 years ago
parent 7a5ee459f7
commit 24fe8643de

@ -17,11 +17,9 @@ limitations under the License.
package main
import (
"sort"
"golang.org/x/net/context"
rpb "k8s.io/helm/pkg/proto/hapi/release"
tpb "k8s.io/helm/pkg/proto/hapi/services"
relutil "k8s.io/helm/pkg/releaseutil"
)
func (s *releaseServer) GetHistory(ctx context.Context, req *tpb.GetHistoryRequest) (*tpb.GetHistoryResponse, error) {
@ -34,7 +32,7 @@ func (s *releaseServer) GetHistory(ctx context.Context, req *tpb.GetHistoryReque
return nil, err
}
sort.Sort(sort.Reverse(byRev(h)))
relutil.Reverse(h, relutil.SortByRevision)
var resp tpb.GetHistoryResponse
for i := 0; i < min(len(h), int(req.Max)); i++ {
@ -44,12 +42,6 @@ func (s *releaseServer) GetHistory(ctx context.Context, req *tpb.GetHistoryReque
return &resp, nil
}
type byRev []*rpb.Release
func (s byRev) Len() int { return len(s) }
func (s byRev) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byRev) Less(i, j int) bool { return s[i].Version < s[j].Version }
func min(x, y int) int {
if x < y {
return x

@ -22,7 +22,6 @@ import (
"fmt"
"log"
"regexp"
"sort"
"strings"
"google.golang.org/grpc/metadata"
@ -36,6 +35,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
relutil "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/timeconv"
"k8s.io/helm/pkg/version"
@ -123,9 +123,9 @@ func (s *releaseServer) ListReleases(req *services.ListReleasesRequest, stream s
switch req.SortBy {
case services.ListSort_NAME:
sort.Sort(byName(rels))
relutil.SortByName(rels)
case services.ListSort_LAST_RELEASED:
sort.Sort(byDate(rels))
relutil.SortByDate(rels)
}
if req.SortOrder == services.ListSort_DESC {
@ -480,8 +480,8 @@ func (s *releaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*
return nil, nil, errors.New("no revision to rollback")
}
sort.Sort(sort.Reverse(byRev(h)))
crls := h[0]
relutil.SortByRevision(h)
crls := h[len(h)-1]
rbv := req.Version
if req.Version == 0 {
@ -878,29 +878,6 @@ func (s *releaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
return res, nil
}
// byName implements the sort.Interface for []*release.Release.
type byName []*release.Release
func (r byName) Len() int {
return len(r)
}
func (r byName) Swap(p, q int) {
r[p], r[q] = r[q], r[p]
}
func (r byName) Less(i, j int) bool {
return r[i].Name < r[j].Name
}
type byDate []*release.Release
func (r byDate) Len() int { return len(r) }
func (r byDate) Swap(p, q int) {
r[p], r[q] = r[q], r[p]
}
func (r byDate) Less(p, q int) bool {
return r[p].Info.LastDeployed.Seconds < r[q].Info.LastDeployed.Seconds
}
func splitManifests(bigfile string) map[string]string {
// This is not the best way of doing things, but it's how k8s itself does it.
// Basically, we're quickly splitting a stream of YAML documents into an

@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package storage // import "k8s.io/helm/pkg/storage"
package releaseutil // import "k8s.io/helm/pkg/releaseutil"
import rspb "k8s.io/helm/pkg/proto/hapi/release"
// FilterFunc returns true if the release object satisfies
// the predicate of the underlying func.
// the predicate of the underlying filter func.
type FilterFunc func(*rspb.Release) bool
// Check applies the FilterFunc to the release object.
@ -30,6 +30,17 @@ func (fn FilterFunc) Check(rls *rspb.Release) bool {
return fn(rls)
}
// Filter applies the filter(s) to the list of provided releases
// returning the list that satisfies the filtering predicate.
func (fn FilterFunc) Filter(rels []*rspb.Release) (rets []*rspb.Release) {
for _, rel := range rels {
if fn.Check(rel) {
rets = append(rets, rel)
}
}
return
}
// Any returns a FilterFunc that filters a list of releases
// determined by the predicate 'f0 || f1 || ... || fn'.
func Any(filters ...FilterFunc) FilterFunc {

@ -0,0 +1,58 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package releaseutil // import "k8s.io/helm/pkg/releaseutil"
import (
rspb "k8s.io/helm/pkg/proto/hapi/release"
"testing"
)
func TestFilterAny(t *testing.T) {
ls := Any(StatusFilter(rspb.Status_DELETED)).Filter(releases)
if len(ls) != 2 {
t.Fatalf("expected 2 results, got '%d'", len(ls))
}
r0, r1 := ls[0], ls[1]
switch {
case r0.Info.Status.Code != rspb.Status_DELETED:
t.Fatalf("expected DELETED result, got '%s'", r1.Info.Status.Code)
case r1.Info.Status.Code != rspb.Status_DELETED:
t.Fatalf("expected DELETED result, got '%s'", r1.Info.Status.Code)
}
}
func TestFilterAll(t *testing.T) {
fn := FilterFunc(func(rls *rspb.Release) bool {
// true if not deleted and version < 4
v0 := !StatusFilter(rspb.Status_DELETED).Check(rls)
v1 := rls.Version < 4
return v0 && v1
})
ls := All(fn).Filter(releases)
if len(ls) != 1 {
t.Fatalf("expected 1 result, got '%d'", len(ls))
}
switch r0 := ls[0]; {
case r0.Version == 4:
t.Fatal("got release with status revision 4")
case r0.Info.Status.Code == rspb.Status_DELETED:
t.Fatal("got release with status DELTED")
}
}

@ -0,0 +1,77 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package releaseutil // import "k8s.io/helm/pkg/releaseutil"
import (
"sort"
rspb "k8s.io/helm/pkg/proto/hapi/release"
)
type sorter struct {
list []*rspb.Release
less func(int, int) bool
}
func (s *sorter) Len() int { return len(s.list) }
func (s *sorter) Less(i, j int) bool { return s.less(i, j) }
func (s *sorter) Swap(i, j int) { s.list[i], s.list[j] = s.list[j], s.list[i] }
// Reverse reverses the list of releases sorted by the sort func.
func Reverse(list []*rspb.Release, sortFn func([]*rspb.Release)) {
sortFn(list)
for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
list[i], list[j] = list[j], list[i]
}
}
// SortByName returns the list of releases sorted
// in lexicographical order.
func SortByName(list []*rspb.Release) {
s := &sorter{list: list}
s.less = func(i, j int) bool {
ni := s.list[i].Name
nj := s.list[j].Name
return ni < nj
}
sort.Sort(s)
}
// SortByDate returns the list of releases sorted by a
// release's last deployed time (in seconds).
func SortByDate(list []*rspb.Release) {
s := &sorter{list: list}
s.less = func(i, j int) bool {
ti := s.list[i].Info.LastDeployed.Seconds
tj := s.list[j].Info.LastDeployed.Seconds
return ti < tj
}
sort.Sort(s)
}
// SortByRevision returns the list of releases sorted by a
// release's revision number (release.Version).
func SortByRevision(list []*rspb.Release) {
s := &sorter{list: list}
s.less = func(i, j int) bool {
vi := s.list[i].Version
vj := s.list[j].Version
return vi < vj
}
sort.Sort(s)
}

@ -0,0 +1,81 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package releaseutil // import "k8s.io/helm/pkg/releaseutil"
import (
rspb "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/timeconv"
"testing"
"time"
)
// note: this test data is shared with filter_test.go.
var releases = []*rspb.Release{
tsRelease("quiet-bear", 2, 2000, rspb.Status_SUPERSEDED),
tsRelease("angry-bird", 4, 3000, rspb.Status_DEPLOYED),
tsRelease("happy-cats", 1, 4000, rspb.Status_DELETED),
tsRelease("vocal-dogs", 3, 6000, rspb.Status_DELETED),
}
func tsRelease(name string, vers int32, dur time.Duration, code rspb.Status_Code) *rspb.Release {
tmsp := timeconv.Timestamp(time.Now().Add(time.Duration(dur)))
info := &rspb.Info{Status: &rspb.Status{Code: code}, LastDeployed: tmsp}
return &rspb.Release{
Name: name,
Version: vers,
Info: info,
}
}
func check(t *testing.T, by string, fn func(int, int) bool) {
for i := len(releases) - 1; i > 0; i-- {
if fn(i, i-1) {
t.Errorf("release at positions '(%d,%d)' not sorted by %s", i-1, i, by)
}
}
}
func TestSortByName(t *testing.T) {
SortByName(releases)
check(t, "ByName", func(i, j int) bool {
ni := releases[i].Name
nj := releases[j].Name
return ni < nj
})
}
func TestSortByDate(t *testing.T) {
SortByDate(releases)
check(t, "ByDate", func(i, j int) bool {
ti := releases[i].Info.LastDeployed.Seconds
tj := releases[j].Info.LastDeployed.Seconds
return ti < tj
})
}
func TestSortByRevision(t *testing.T) {
SortByRevision(releases)
check(t, "ByRevision", func(i, j int) bool {
vi := releases[i].Version
vj := releases[j].Version
return vi < vj
})
}

@ -1,22 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Package storage implements storage for Tiller objects.The backend storage
mechanism may be implemented with different backends. This package and its
subpackages provide storage layers for Tiller objects.
*/
package storage // import "k8s.io/helm/pkg/storage"

@ -21,6 +21,7 @@ import (
"log"
rspb "k8s.io/helm/pkg/proto/hapi/release"
relutil "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/storage/driver"
)
@ -73,7 +74,7 @@ func (s *Storage) ListReleases() ([]*rspb.Release, error) {
func (s *Storage) ListDeleted() ([]*rspb.Release, error) {
log.Println("List deleted releases in storage")
return s.Driver.List(func(rls *rspb.Release) bool {
return StatusFilter(rspb.Status_DELETED).Check(rls)
return relutil.StatusFilter(rspb.Status_DELETED).Check(rls)
})
}
@ -82,27 +83,27 @@ func (s *Storage) ListDeleted() ([]*rspb.Release, error) {
func (s *Storage) ListDeployed() ([]*rspb.Release, error) {
log.Println("Listing all deployed releases in storage")
return s.Driver.List(func(rls *rspb.Release) bool {
return StatusFilter(rspb.Status_DEPLOYED).Check(rls)
return relutil.StatusFilter(rspb.Status_DEPLOYED).Check(rls)
})
}
// ListFilterAll returns the set of releases satisfying satisfying the predicate
// (filter0 && filter1 && ... && filterN), i.e. a Release is included in the results
// if and only if all filters return true.
func (s *Storage) ListFilterAll(filters ...FilterFunc) ([]*rspb.Release, error) {
func (s *Storage) ListFilterAll(fns ...relutil.FilterFunc) ([]*rspb.Release, error) {
log.Println("Listing all releases with filter")
return s.Driver.List(func(rls *rspb.Release) bool {
return All(filters...).Check(rls)
return relutil.All(fns...).Check(rls)
})
}
// ListFilterAny returns the set of releases satisfying satisfying the predicate
// (filter0 || filter1 || ... || filterN), i.e. a Release is included in the results
// if at least one of the filters returns true.
func (s *Storage) ListFilterAny(filters ...FilterFunc) ([]*rspb.Release, error) {
func (s *Storage) ListFilterAny(fns ...relutil.FilterFunc) ([]*rspb.Release, error) {
log.Println("Listing any releases with filter")
return s.Driver.List(func(rls *rspb.Release) bool {
return Any(filters...).Check(rls)
return relutil.Any(fns...).Check(rls)
})
}

Loading…
Cancel
Save