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 package main
import ( import (
"sort"
"golang.org/x/net/context" "golang.org/x/net/context"
rpb "k8s.io/helm/pkg/proto/hapi/release"
tpb "k8s.io/helm/pkg/proto/hapi/services" 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) { 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 return nil, err
} }
sort.Sort(sort.Reverse(byRev(h))) relutil.Reverse(h, relutil.SortByRevision)
var resp tpb.GetHistoryResponse var resp tpb.GetHistoryResponse
for i := 0; i < min(len(h), int(req.Max)); i++ { 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 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 { func min(x, y int) int {
if x < y { if x < y {
return x return x

@ -22,7 +22,6 @@ import (
"fmt" "fmt"
"log" "log"
"regexp" "regexp"
"sort"
"strings" "strings"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
@ -36,6 +35,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
relutil "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/storage/driver" "k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/timeconv" "k8s.io/helm/pkg/timeconv"
"k8s.io/helm/pkg/version" "k8s.io/helm/pkg/version"
@ -123,9 +123,9 @@ func (s *releaseServer) ListReleases(req *services.ListReleasesRequest, stream s
switch req.SortBy { switch req.SortBy {
case services.ListSort_NAME: case services.ListSort_NAME:
sort.Sort(byName(rels)) relutil.SortByName(rels)
case services.ListSort_LAST_RELEASED: case services.ListSort_LAST_RELEASED:
sort.Sort(byDate(rels)) relutil.SortByDate(rels)
} }
if req.SortOrder == services.ListSort_DESC { 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") return nil, nil, errors.New("no revision to rollback")
} }
sort.Sort(sort.Reverse(byRev(h))) relutil.SortByRevision(h)
crls := h[0] crls := h[len(h)-1]
rbv := req.Version rbv := req.Version
if req.Version == 0 { if req.Version == 0 {
@ -878,29 +878,6 @@ func (s *releaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
return res, nil 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 { func splitManifests(bigfile string) map[string]string {
// This is not the best way of doing things, but it's how k8s itself does it. // 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 // 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. 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" import rspb "k8s.io/helm/pkg/proto/hapi/release"
// FilterFunc returns true if the release object satisfies // 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 type FilterFunc func(*rspb.Release) bool
// Check applies the FilterFunc to the release object. // Check applies the FilterFunc to the release object.
@ -30,6 +30,17 @@ func (fn FilterFunc) Check(rls *rspb.Release) bool {
return fn(rls) 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 // Any returns a FilterFunc that filters a list of releases
// determined by the predicate 'f0 || f1 || ... || fn'. // determined by the predicate 'f0 || f1 || ... || fn'.
func Any(filters ...FilterFunc) FilterFunc { 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" "log"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
relutil "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/storage/driver" "k8s.io/helm/pkg/storage/driver"
) )
@ -73,7 +74,7 @@ func (s *Storage) ListReleases() ([]*rspb.Release, error) {
func (s *Storage) ListDeleted() ([]*rspb.Release, error) { func (s *Storage) ListDeleted() ([]*rspb.Release, error) {
log.Println("List deleted releases in storage") log.Println("List deleted releases in storage")
return s.Driver.List(func(rls *rspb.Release) bool { 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) { func (s *Storage) ListDeployed() ([]*rspb.Release, error) {
log.Println("Listing all deployed releases in storage") log.Println("Listing all deployed releases in storage")
return s.Driver.List(func(rls *rspb.Release) bool { 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 // ListFilterAll returns the set of releases satisfying satisfying the predicate
// (filter0 && filter1 && ... && filterN), i.e. a Release is included in the results // (filter0 && filter1 && ... && filterN), i.e. a Release is included in the results
// if and only if all filters return true. // 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") log.Println("Listing all releases with filter")
return s.Driver.List(func(rls *rspb.Release) bool { 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 // ListFilterAny returns the set of releases satisfying satisfying the predicate
// (filter0 || filter1 || ... || filterN), i.e. a Release is included in the results // (filter0 || filter1 || ... || filterN), i.e. a Release is included in the results
// if at least one of the filters returns true. // 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") log.Println("Listing any releases with filter")
return s.Driver.List(func(rls *rspb.Release) bool { return s.Driver.List(func(rls *rspb.Release) bool {
return Any(filters...).Check(rls) return relutil.Any(fns...).Check(rls)
}) })
} }

Loading…
Cancel
Save