rm: remove useless files (#1416)
diff --git a/pkg/common/util/cache/prometheus_status_counter.go b/pkg/common/util/cache/prometheus_status_counter.go deleted file mode 100644 index 5e9b5f7..0000000 --- a/pkg/common/util/cache/prometheus_status_counter.go +++ /dev/null
@@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 cache - -import ( - "time" - - "github.com/goburrow/cache" - "github.com/prometheus/client_golang/prometheus" -) - -const ResultLabel = "result" - -func NewMetric(name, help string) *prometheus.CounterVec { - return prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: name, - Help: help, - }, []string{ResultLabel}) -} - -type PrometheusStatsCounter struct { - Metric *prometheus.CounterVec -} - -var _ cache.StatsCounter = &PrometheusStatsCounter{} - -func (p *PrometheusStatsCounter) RecordHits(count uint64) { - p.Metric.WithLabelValues("hit").Add(float64(count)) -} - -func (p *PrometheusStatsCounter) RecordMisses(count uint64) { - p.Metric.WithLabelValues("miss").Add(float64(count)) -} - -func (p *PrometheusStatsCounter) RecordLoadSuccess(loadTime time.Duration) { -} - -func (p *PrometheusStatsCounter) RecordLoadError(loadTime time.Duration) { -} - -func (p *PrometheusStatsCounter) RecordEviction() { -} - -func (p *PrometheusStatsCounter) Snapshot(stats *cache.Stats) { -}
diff --git a/pkg/common/util/cache/v3/cache.go b/pkg/common/util/cache/v3/cache.go deleted file mode 100644 index 6156d70..0000000 --- a/pkg/common/util/cache/v3/cache.go +++ /dev/null
@@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 v3 - -import ( - "sort" - - v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" - ctl_cache "github.com/envoyproxy/go-control-plane/pkg/cache/v3" - protov1 "github.com/golang/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" -) - -func ToDeltaDiscoveryResponse(s ctl_cache.Snapshot) (*v3.DeltaDiscoveryResponse, error) { - resp := &v3.DeltaDiscoveryResponse{} - for _, rs := range s.Resources { - for _, name := range sortedResourceNames(rs) { - r := rs.Items[name] - pbany, err := anypb.New(protov1.MessageV2(r.Resource)) - if err != nil { - return nil, err - } - resp.Resources = append(resp.Resources, &v3.Resource{ - Version: rs.Version, - Name: name, - Resource: pbany, - }) - } - } - return resp, nil -} - -func sortedResourceNames(rs ctl_cache.Resources) []string { - names := make([]string, 0, len(rs.Items)) - for name := range rs.Items { - names = append(names, name) - } - sort.Strings(names) - return names -}
diff --git a/pkg/common/util/channels/closed.go b/pkg/common/util/channels/closed.go deleted file mode 100644 index f687b72..0000000 --- a/pkg/common/util/channels/closed.go +++ /dev/null
@@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 channels - -// IsClosed checks if channel is closed by reading the value. It is useful for checking -func IsClosed[T any](ch <-chan T) bool { - select { - case <-ch: - return true - default: - } - return false -}
diff --git a/pkg/common/util/concurrent/debouncer.go b/pkg/common/util/concurrent/debouncer.go deleted file mode 100644 index fd9c32e..0000000 --- a/pkg/common/util/concurrent/debouncer.go +++ /dev/null
@@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 concurrent - -import ( - "time" - - "github.com/apache/dubbo-admin/pkg/common/util/sets" -) - -type Debouncer[T comparable] struct{} - -func (d *Debouncer[T]) Run(ch chan T, stopCh <-chan struct{}, debounceMinInterval, debounceMaxInterval time.Duration, pushFn func(sets.Set[T])) { - var timeChan <-chan time.Time - var startDebounce time.Time - var lastConfigUpdateTime time.Time - - pushCounter := 0 - debouncedEvents := 0 - - // Keeps track of the push requests. If updates are debounce they will be merged. - combinedEvents := sets.New[T]() - - free := true - freeCh := make(chan struct{}, 1) - - push := func(events sets.Set[T], debouncedEvents int, startDebounce time.Time) { - pushFn(events) - freeCh <- struct{}{} - } - - pushWorker := func() { - eventDelay := time.Since(startDebounce) - quietTime := time.Since(lastConfigUpdateTime) - // it has been too long or quiet enough - if eventDelay >= debounceMaxInterval || quietTime >= debounceMinInterval { - if combinedEvents.Len() > 0 { - pushCounter++ - free = false - go push(combinedEvents, debouncedEvents, startDebounce) - combinedEvents = sets.New[T]() - debouncedEvents = 0 - } else { - // For no combined events to process, we can also do nothing here and wait for the config change to trigger - // the next debounce, but I think it's better to set it's to the debounce max interval. - timeChan = time.After(debounceMaxInterval) - } - } else { - timeChan = time.After(debounceMinInterval - quietTime) - } - } - - for { - select { - case <-freeCh: - free = true - pushWorker() - case r := <-ch: - - lastConfigUpdateTime = time.Now() - if debouncedEvents == 0 { - timeChan = time.After(debounceMinInterval) - startDebounce = lastConfigUpdateTime - } - debouncedEvents++ - - combinedEvents = combinedEvents.Insert(r) - case <-timeChan: - if free { - pushWorker() - } - case <-stopCh: - return - } - } -}
diff --git a/pkg/common/util/files/files.go b/pkg/common/util/files/files.go deleted file mode 100644 index 6fdc501..0000000 --- a/pkg/common/util/files/files.go +++ /dev/null
@@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 files - -import ( - "io/fs" - "os" - "path/filepath" -) - -func FileExists(path string) bool { - _, err := os.Stat(path) - return err == nil -} - -func FileEmpty(path string) (bool, error) { - file, err := os.Stat(path) - if err != nil { - return true, err - } - return file.Size() == 0, nil -} - -// IsDirWriteable checks if dir is writable by writing and removing a file -// to dir. It returns nil if dir is writable. -func IsDirWriteable(dir string) error { - f := filepath.Join(dir, ".touch") - perm := 0o600 - if err := os.WriteFile(f, []byte(""), fs.FileMode(perm)); err != nil { - return err - } - return os.Remove(f) -}
diff --git a/pkg/common/util/files/lookup_binary.go b/pkg/common/util/files/lookup_binary.go deleted file mode 100644 index 4b0e001..0000000 --- a/pkg/common/util/files/lookup_binary.go +++ /dev/null
@@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 files - -import ( - "os" - "os/exec" - "path/filepath" - - "github.com/pkg/errors" -) - -type LookupPathFn = func() (string, error) - -// LookupNextToCurrentExecutable looks for the binary next to the current binary -// Example: if this function is executed by /usr/bin/dubbo-dp, this function will lookup for binary 'x' in /usr/bin/x -func LookupNextToCurrentExecutable(binary string) LookupPathFn { - return func() (string, error) { - ex, err := os.Executable() - if err != nil { - return "", err - } - return filepath.Dir(ex) + "/" + binary, nil - } -} - -// LookupInCurrentDirectory looks for the binary in the current directory -// Example: if this function is executed by /usr/bin/dubbo-dp that was run in /home/dubbo-dp, this function will lookup for binary 'x' in /home/dubbo-dp/x -func LookupInCurrentDirectory(binary string) LookupPathFn { - return func() (string, error) { - cwd, err := os.Getwd() - if err != nil { - return "", err - } - return cwd + "/" + binary, nil - } -} - -func LookupInPath(path string) LookupPathFn { - return func() (string, error) { - return path, nil - } -} - -// LookupBinaryPath looks for a binary in order of passed lookup functions. -// It fails only if all lookup function does not contain a binary. -func LookupBinaryPath(pathFns ...LookupPathFn) (string, error) { - var candidatePaths []string - for _, candidatePathFn := range pathFns { - candidatePath, err := candidatePathFn() - if err != nil { - continue - } - candidatePaths = append(candidatePaths, candidatePath) - path, err := exec.LookPath(candidatePath) - if err == nil { - return path, nil - } - } - - return "", errors.Errorf("could not find executable binary in any of the following paths: %v", candidatePaths) -}
diff --git a/pkg/common/util/files/project.go b/pkg/common/util/files/project.go deleted file mode 100644 index 04e8f01..0000000 --- a/pkg/common/util/files/project.go +++ /dev/null
@@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 files - -import ( - "go/build" - "os" - "path" - "strings" -) - -func GetProjectRoot(file string) string { - dir := file - for path.Base(dir) != "pkg" && path.Base(dir) != "app" { - dir = path.Dir(dir) - } - return path.Dir(dir) -} - -func GetProjectRootParent(file string) string { - return path.Dir(GetProjectRoot(file)) -} - -func RelativeToPkgMod(file string) string { - root := path.Dir(path.Dir(path.Dir(GetProjectRoot(file)))) - return strings.TrimPrefix(file, root) -} - -func RelativeToProjectRoot(path string) string { - root := GetProjectRoot(path) - return strings.TrimPrefix(path, root) -} - -func RelativeToProjectRootParent(path string) string { - root := GetProjectRootParent(path) - return strings.TrimPrefix(path, root) -} - -func GetGopath() string { - gopath := os.Getenv("GOPATH") - if gopath == "" { - gopath = build.Default.GOPATH - } - return gopath -}
diff --git a/pkg/common/util/grpc/reverse_unary_rpcs.go b/pkg/common/util/grpc/reverse_unary_rpcs.go deleted file mode 100644 index 8728c34..0000000 --- a/pkg/common/util/grpc/reverse_unary_rpcs.go +++ /dev/null
@@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 grpc - -import ( - "sync" - - "github.com/pkg/errors" - "google.golang.org/grpc" - "google.golang.org/protobuf/proto" -) - -type ReverseUnaryMessage interface { - proto.Message - GetRequestId() string -} - -// ReverseUnaryRPCs helps to implement reverse unary rpcs where server sends requests to a client and receives responses from the client. -type ReverseUnaryRPCs interface { - Send(client string, req ReverseUnaryMessage) error - WatchResponse(client string, reqID string, resp chan ReverseUnaryMessage) error - DeleteWatch(client string, reqID string) - - ClientConnected(client string, stream grpc.ServerStream) - ClientDisconnected(client string) - ResponseReceived(client string, resp ReverseUnaryMessage) error -} - -type clientStreams struct { - streamForClient map[string]*clientStream - sync.Mutex // protects streamForClient -} - -func (x *clientStreams) ResponseReceived(client string, resp ReverseUnaryMessage) error { - stream, err := x.clientStream(client) - if err != nil { - return err - } - stream.Lock() - ch, ok := stream.watchForRequestId[resp.GetRequestId()] - stream.Unlock() - if !ok { - return errors.Errorf("callback for request Id %s not found", resp.GetRequestId()) - } - ch <- resp - return nil -} - -func NewReverseUnaryRPCs() ReverseUnaryRPCs { - return &clientStreams{ - streamForClient: map[string]*clientStream{}, - } -} - -func (x *clientStreams) ClientConnected(client string, stream grpc.ServerStream) { - x.Lock() - defer x.Unlock() - x.streamForClient[client] = &clientStream{ - stream: stream, - watchForRequestId: map[string]chan ReverseUnaryMessage{}, - } -} - -func (x *clientStreams) clientStream(client string) (*clientStream, error) { - x.Lock() - defer x.Unlock() - stream, ok := x.streamForClient[client] - if !ok { - return nil, errors.Errorf("client %s is not connected", client) - } - return stream, nil -} - -func (x *clientStreams) ClientDisconnected(client string) { - x.Lock() - defer x.Unlock() - delete(x.streamForClient, client) -} - -type clientStream struct { - stream grpc.ServerStream - watchForRequestId map[string]chan ReverseUnaryMessage - sync.Mutex // protects watchForRequestId -} - -func (x *clientStreams) Send(client string, req ReverseUnaryMessage) error { - stream, err := x.clientStream(client) - if err != nil { - return err - } - return stream.stream.SendMsg(req) -} - -func (x *clientStreams) WatchResponse(client string, reqID string, resp chan ReverseUnaryMessage) error { - stream, err := x.clientStream(client) - if err != nil { - return err - } - stream.Lock() - defer stream.Unlock() - stream.watchForRequestId[reqID] = resp - return nil -} - -func (x *clientStreams) DeleteWatch(client string, reqID string) { - stream, err := x.clientStream(client) - if err != nil { - return // client was already deleted - } - stream.Lock() - defer stream.Unlock() - delete(stream.watchForRequestId, reqID) -}
diff --git a/pkg/common/util/http/client.go b/pkg/common/util/http/client.go deleted file mode 100644 index 3436965..0000000 --- a/pkg/common/util/http/client.go +++ /dev/null
@@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 http - -import ( - nethttp "net/http" - "net/url" - "path" -) - -type Client interface { - Do(req *nethttp.Request) (*nethttp.Response, error) -} - -type ClientFunc func(req *nethttp.Request) (*nethttp.Response, error) - -func (f ClientFunc) Do(req *nethttp.Request) (*nethttp.Response, error) { - return f(req) -} - -func ClientWithBaseURL(delegate Client, baseURL *url.URL, headers map[string]string) Client { - return ClientFunc(func(req *nethttp.Request) (*nethttp.Response, error) { - if req.URL != nil { - req.URL.Scheme = baseURL.Scheme - req.URL.Host = baseURL.Host - req.URL.Path = path.Join(baseURL.Path, req.URL.Path) - for k, v := range headers { - req.Header.Add(k, v) - } - } - return delegate.Do(req) - }) -}
diff --git a/pkg/common/util/http/client_test.go b/pkg/common/util/http/client_test.go deleted file mode 100644 index 87085f7..0000000 --- a/pkg/common/util/http/client_test.go +++ /dev/null
@@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 http_test - -import ( - "net/http" - "net/url" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - util_http "github.com/apache/dubbo-admin/pkg/common/util/http" -) - -var _ = Describe("Http Util", func() { - Describe("ClientWithBaseURL(..)", func() { - type testCase struct { - baseURL string - requestURL string - expectedURL string - } - - DescribeTable("should rewrite request URL by combining `baseURL` and `requestURL`", - func(given testCase) { - // setup - baseURL, err := url.Parse(given.baseURL) - Expect(err).ToNot(HaveOccurred()) - - // and - var actualURL *url.URL - delegate := util_http.ClientFunc(func(req *http.Request) (*http.Response, error) { - actualURL = req.URL - return &http.Response{}, nil - }) - - // when - client := util_http.ClientWithBaseURL(delegate, baseURL, nil) - // then - Expect(client).ToNot(BeIdenticalTo(delegate)) - - // when - req, err := http.NewRequest("GET", given.requestURL, nil) - // then - Expect(err).ToNot(HaveOccurred()) - - // when - _, err = client.Do(req) - // then - Expect(err).ToNot(HaveOccurred()) - - // and - Expect(actualURL.String()).To(Equal(given.expectedURL)) - }, - Entry("baseURL without path", testCase{ - baseURL: "https://dubbo-control-plane:5681", - requestURL: "/meshes/default/dataplanes", - expectedURL: "https://dubbo-control-plane:5681/meshes/default/dataplanes", - }), - Entry("baseURL without path and request with a relative path", testCase{ - baseURL: "https://dubbo-control-plane:5681", - requestURL: "meshes/default/dataplanes", - expectedURL: "https://dubbo-control-plane:5681/meshes/default/dataplanes", - }), - Entry("baseURL with path", testCase{ - baseURL: "https://dubbo-control-plane:5681/proxy/foo/bar", - requestURL: "/test", - expectedURL: "https://dubbo-control-plane:5681/proxy/foo/bar/test", - }), - Entry("baseURL that ends with /", testCase{ - baseURL: "https://dubbo-control-plane:5681/", - requestURL: "/meshes/default/dataplanes", - expectedURL: "https://dubbo-control-plane:5681/meshes/default/dataplanes", - }), - Entry("baseURL and/or requestURL with double slashes", testCase{ - baseURL: "https://dubbo-control-plane:5681//proxy/foo/bar", - requestURL: "/test//baz", - expectedURL: "https://dubbo-control-plane:5681/proxy/foo/bar/test/baz", - }), - ) - - It("should tolerate nil URL", func() { - // setup - baseURL, err := url.Parse("https://dubbo-control-plane:5681") - Expect(err).ToNot(HaveOccurred()) - - // and - var actualURL *url.URL - delegate := util_http.ClientFunc(func(req *http.Request) (*http.Response, error) { - actualURL = req.URL - return &http.Response{}, nil - }) - - // when - client := util_http.ClientWithBaseURL(delegate, baseURL, nil) - // then - Expect(client).ToNot(BeIdenticalTo(delegate)) - - // when - req := &http.Request{ - URL: nil, - } - // and - _, err = client.Do(req) - // then - Expect(err).ToNot(HaveOccurred()) - - // and - Expect(actualURL).To(BeNil()) - }) - }) -})
diff --git a/pkg/common/util/http/tls.go b/pkg/common/util/http/tls.go deleted file mode 100644 index 262ef08..0000000 --- a/pkg/common/util/http/tls.go +++ /dev/null
@@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 http - -import ( - "crypto/tls" - "crypto/x509" - "net/http" - "os" - - "github.com/pkg/errors" -) - -func ConfigureMTLS(httpClient *http.Client, caCert string, clientCert string, clientKey string) error { - transport := &http.Transport{ - TLSClientConfig: &tls.Config{ - MinVersion: tls.VersionTLS12, - }, - } - - if caCert == "" { - transport.TLSClientConfig.InsecureSkipVerify = true - } else { - certBytes, err := os.ReadFile(caCert) - if err != nil { - return errors.Wrap(err, "could not read CA cert") - } - certPool := x509.NewCertPool() - if ok := certPool.AppendCertsFromPEM(certBytes); !ok { - return errors.New("could not add certificate") - } - transport.TLSClientConfig.RootCAs = certPool - } - - if clientKey != "" && clientCert != "" { - cert, err := tls.LoadX509KeyPair(clientCert, clientKey) - if err != nil { - return errors.Wrap(err, "could not create key pair from client cert and client key") - } - transport.TLSClientConfig.Certificates = []tls.Certificate{cert} - } - - httpClient.Transport = transport - return nil -}
diff --git a/pkg/common/util/k8s/name_converter.go b/pkg/common/util/k8s/name_converter.go deleted file mode 100644 index 04060a3..0000000 --- a/pkg/common/util/k8s/name_converter.go +++ /dev/null
@@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 k8s - -import ( - "fmt" - "strings" - - "github.com/pkg/errors" -) - -func CoreNameToK8sName(coreName string) (string, string, error) { - idx := strings.LastIndex(coreName, ".") - if idx == -1 { - return "", "", errors.Errorf(`name %q must include namespace after the dot, ex. "name.namespace"`, coreName) - } - // namespace cannot contain "." therefore it's always the last part - namespace := coreName[idx+1:] - if namespace == "" { - return "", "", errors.New("namespace must be non-empty") - } - return coreName[:idx], namespace, nil -} - -func K8sNamespacedNameToCoreName(name, namespace string) string { - return fmt.Sprintf("%s.%s", name, namespace) -}
diff --git a/pkg/common/util/maps/sorted_keys.go b/pkg/common/util/maps/sorted_keys.go deleted file mode 100644 index 0eece50..0000000 --- a/pkg/common/util/maps/sorted_keys.go +++ /dev/null
@@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 maps - -import ( - "golang.org/x/exp/constraints" - "golang.org/x/exp/maps" - "golang.org/x/exp/slices" -) - -func SortedKeys[M ~map[K]V, K constraints.Ordered, V any](m M) []K { - keys := maps.Keys(m) - slices.Sort(keys) - return keys -}
diff --git a/pkg/common/util/maps/sorted_keys_test.go b/pkg/common/util/maps/sorted_keys_test.go deleted file mode 100644 index 730c759..0000000 --- a/pkg/common/util/maps/sorted_keys_test.go +++ /dev/null
@@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 maps_test - -import ( - . "github.com/onsi/ginkgo/v2" - - "github.com/apache/dubbo-admin/pkg/common/util/maps" - . "github.com/onsi/gomega" -) - -var _ = Describe("SortedKeys", func() { - It("should return sorted keys", func() { - // given - m := map[string]string{ - "c": "x", - "b": "y", - "a": "z", - } - - // when - keys := maps.SortedKeys(m) - - // then - Expect(keys).To(Equal([]string{"a", "b", "c"})) - }) -})
diff --git a/pkg/common/util/maps/sync.go b/pkg/common/util/maps/sync.go deleted file mode 100644 index 38a910c..0000000 --- a/pkg/common/util/maps/sync.go +++ /dev/null
@@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 maps - -import ( - "sync" -) - -// Sync is a simple wrapper around sync.Map that provides type-safe methods -type Sync[K, V any] struct { - inner sync.Map -} - -func (s *Sync[K, V]) Load(k K) (V, bool) { - v, ok := s.inner.Load(k) - if !ok { - var zero V - return zero, false - } - return v.(V), true -} - -func (s *Sync[K, V]) Store(k K, v V) { - s.inner.Store(k, v) -} - -func (s *Sync[K, V]) LoadOrStore(k K, store V) (V, bool) { - v, ok := s.inner.LoadOrStore(k, store) - return v.(V), ok -} - -func (s *Sync[K, V]) LoadAndDelete(k K) (V, bool) { - v, ok := s.inner.LoadAndDelete(k) - if !ok { - var zero V - return zero, false - } - return v.(V), true -} - -func (s *Sync[K, V]) Delete(k K) { - s.inner.Delete(k) -} - -func (s *Sync[K, V]) Swap(k K, v V) (V, bool) { - prev, ok := s.inner.Swap(k, v) - if !ok { - var zero V - return zero, false - } - return prev.(V), true -} - -func (s *Sync[K, V]) CompareAndSwap(k K, old, new V) bool { - return s.inner.CompareAndSwap(k, old, new) -} - -func (s *Sync[K, V]) CompareAndDelete(k K, old V) bool { - return s.inner.CompareAndDelete(k, old) -} - -func (s *Sync[K, V]) Range(f func(k K, v V) bool) { - s.inner.Range(func(key, value any) bool { - return f(key.(K), value.(V)) - }) -}
diff --git a/pkg/common/util/net/ips.go b/pkg/common/util/net/ips.go deleted file mode 100644 index 9544681..0000000 --- a/pkg/common/util/net/ips.go +++ /dev/null
@@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 net - -import ( - "fmt" - "net" - "sort" - - "github.com/pkg/errors" -) - -type AddressPredicate = func(address *net.IPNet) bool - -func NonLoopback(address *net.IPNet) bool { - return !address.IP.IsLoopback() -} - -// GetAllIPs returns all IPs (IPv4 and IPv6) from the all network interfaces on the machine -func GetAllIPs(predicates ...AddressPredicate) ([]string, error) { - addrs, err := net.InterfaceAddrs() - if err != nil { - return nil, errors.Wrap(err, "could not list network interfaces") - } - var result []string - for _, address := range addrs { - if ipnet, ok := address.(*net.IPNet); ok { - matchedPredicate := true - for _, predicate := range predicates { - if !predicate(ipnet) { - matchedPredicate = false - break - } - } - if matchedPredicate { - result = append(result, ipnet.IP.String()) - } - } - } - sort.Strings(result) // sort so IPv4 are the first elements in the list - return result, nil -} - -// ToV6 return self if ip6 other return the v4 prefixed with ::ffff: -func ToV6(ip string) string { - parsedIp := net.ParseIP(ip) - if parsedIp.To4() != nil { - return fmt.Sprintf("::ffff:%x:%x", uint32(parsedIp[12])<<8+uint32(parsedIp[13]), uint32(parsedIp[14])<<8+uint32(parsedIp[15])) - } - return ip -} - -func IsAddressIPv6(address string) bool { - if address == "" { - return false - } - - ip := net.ParseIP(address) - if ip == nil { - return false - } - - return ip.To4() == nil -}
diff --git a/pkg/common/util/net/ips_test.go b/pkg/common/util/net/ips_test.go deleted file mode 100644 index 78a24d5..0000000 --- a/pkg/common/util/net/ips_test.go +++ /dev/null
@@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 net_test - -import ( - . "github.com/onsi/ginkgo/v2" - - "github.com/apache/dubbo-admin/pkg/common/util/net" - . "github.com/onsi/gomega" -) - -var _ = DescribeTable("ToV6", - func(given string, expected string) { - Expect(net.ToV6(given)).To(Equal(expected)) - }, - Entry("v6 already", "2001:db8::ff00:42:8329", "2001:db8::ff00:42:8329"), - Entry("v6 not compacted", "2001:0db8:0000:0000:0000:ff00:0042:8329", "2001:0db8:0000:0000:0000:ff00:0042:8329"), - Entry("v4 adds prefix", "240.0.0.0", "::ffff:f000:0"), - Entry("v4 adds prefix", "240.0.255.0", "::ffff:f000:ff00"), -) - -var _ = DescribeTable("IsIPv6", - func(given string, expected bool) { - Expect(net.IsAddressIPv6(given)).To(Equal(expected)) - }, - Entry("127.0.0.1 should not be IPv6 ", "127.0.0.1", false), - Entry("should be IPv6", "2001:0db8:0000:0000:0000:ff00:0042:8329", true), - Entry("::6", "::6", true), -)
diff --git a/pkg/common/util/net/tcpsock.go b/pkg/common/util/net/tcpsock.go deleted file mode 100644 index 0d23a98..0000000 --- a/pkg/common/util/net/tcpsock.go +++ /dev/null
@@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 net - -import ( - "fmt" - "net" -) - -func PickTCPPort(ip string, leftPort, rightPort uint32) (uint32, error) { - lowestPort, highestPort := leftPort, rightPort - if highestPort < lowestPort { - lowestPort, highestPort = highestPort, lowestPort - } - // we prefer a port to remain stable over time, that's why we do sequential availability check - // instead of random selection - for port := lowestPort; port <= highestPort; port++ { - if actualPort, err := ReserveTCPAddr(fmt.Sprintf("%s:%d", ip, port)); err == nil { - return actualPort, nil - } - } - return 0, fmt.Errorf("unable to find port in range %d:%d", lowestPort, highestPort) -} - -func ReserveTCPAddr(address string) (uint32, error) { - addr, err := net.ResolveTCPAddr("tcp", address) - if err != nil { - return 0, err - } - l, err := net.ListenTCP("tcp", addr) - if err != nil { - return 0, err - } - defer l.Close() - return uint32(l.Addr().(*net.TCPAddr).Port), nil -}
diff --git a/pkg/common/util/os/fs.go b/pkg/common/util/os/fs.go deleted file mode 100644 index 6d4d60c..0000000 --- a/pkg/common/util/os/fs.go +++ /dev/null
@@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 os - -import ( - "os" - - "github.com/pkg/errors" -) - -func TryWriteToDir(dir string) error { - file, err := os.CreateTemp(dir, "write-access-check") - if err != nil { - if os.IsNotExist(err) { - if err := os.MkdirAll(dir, os.ModeDir|0o755); err != nil { - return errors.Wrapf(err, "unable to create a directory %q", dir) - } - file, err = os.CreateTemp(dir, "write-access-check") - } - if err != nil { - return errors.Wrapf(err, "unable to create temporary files in directory %q", dir) - } - } - if err := os.Remove(file.Name()); err != nil { - return errors.Wrapf(err, "unable to remove temporary files in directory %q", dir) - } - return nil -}
diff --git a/pkg/common/util/os/limits.go b/pkg/common/util/os/limits.go deleted file mode 100644 index ca86aa0..0000000 --- a/pkg/common/util/os/limits.go +++ /dev/null
@@ -1,69 +0,0 @@ -//go:build !windows -// +build !windows - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 os - -import ( - "fmt" - "runtime" - - "golang.org/x/sys/unix" -) - -func setFileLimit(n uint64) error { - limit := unix.Rlimit{ - Cur: n, - Max: n, - } - - if err := unix.Setrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { - return fmt.Errorf("failed to set open file limit to %d: %w", limit.Cur, err) - } - - return nil -} - -// RaiseFileLimit raises the soft open file limit to match the hard limit. -func RaiseFileLimit() error { - limit := unix.Rlimit{} - if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { - return fmt.Errorf("failed to query open file limits: %w", err) - } - - // Darwin sets the max to unlimited, but it is actually limited - // (typically to 24K) by the "kern.maxfilesperproc" systune. - // Since we only run on Darwin for test purposes, just clip this - // to a reasonable value. - if runtime.GOOS == "darwin" && limit.Max > 10240 { - limit.Max = 10240 - } - - return setFileLimit(limit.Max) -} - -// CurrentFileLimit reports the current soft open file limit. -func CurrentFileLimit() (uint64, error) { - limit := unix.Rlimit{} - if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { - return 0, fmt.Errorf("failed to query open file limits: %w", err) - } - - return limit.Cur, nil -}
diff --git a/pkg/common/util/os/limits_test.go b/pkg/common/util/os/limits_test.go deleted file mode 100644 index ef687e3..0000000 --- a/pkg/common/util/os/limits_test.go +++ /dev/null
@@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 os - -import ( - "runtime" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "golang.org/x/sys/unix" -) - -var _ = Describe("File limits", func() { - It("should query the open file limit", func() { - Expect(CurrentFileLimit()).Should(BeNumerically(">", 0)) - }) - - It("should raise the open file limit", func() { - if runtime.GOOS == "darwin" { - Skip("skipping on darwin because it requires priviledges") - } - initialLimits := unix.Rlimit{} - Expect(unix.Getrlimit(unix.RLIMIT_NOFILE, &initialLimits)).Should(Succeed()) - - Expect(CurrentFileLimit()).Should(BeNumerically("==", initialLimits.Cur)) - - Expect(RaiseFileLimit()).Should(Succeed()) - - Expect(CurrentFileLimit()).Should(BeNumerically("==", initialLimits.Max)) - - // Restore the original limit. - Expect(setFileLimit(initialLimits.Cur)).Should(Succeed()) - Expect(CurrentFileLimit()).Should(BeNumerically("==", initialLimits.Cur)) - }) - - It("should fail to exceed the hard file limit", func() { - Expect(setFileLimit(uint64(1) << 63)).Should(HaveOccurred()) - }) -})
diff --git a/pkg/common/util/os/limits_windows.go b/pkg/common/util/os/limits_windows.go deleted file mode 100644 index 7ecd93b..0000000 --- a/pkg/common/util/os/limits_windows.go +++ /dev/null
@@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 os - -import ( - "math" -) - -func RaiseFileLimit() error { - return nil -} - -func CurrentFileLimit() (uint64, error) { - return math.MaxUint64, nil -}
diff --git a/pkg/common/util/prometheus/gorestful_middleware.go b/pkg/common/util/prometheus/gorestful_middleware.go deleted file mode 100644 index 0e7e92c..0000000 --- a/pkg/common/util/prometheus/gorestful_middleware.go +++ /dev/null
@@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 prometheus - -import ( - "context" - - gorestful "github.com/emicklei/go-restful/v3" - "github.com/slok/go-http-metrics/middleware" -) - -// MetricsHandler is based on go-restful middleware. -// -// In the original version, URLPath() uses r.req.Request.URL.Path which results in following stats when querying for individual DPs -// api_server_http_response_size_bytes_bucket{code="201",handler="/meshes/default/dataplanes/backend-01",method="PUT",service="",le="100"} 1 -// api_server_http_response_size_bytes_bucket{code="201",handler="/meshes/default/dataplanes/ingress-01",method="PUT",service="",le="100"} 1 -// this is not scalable solution, we would be producing too many metrics. With r.req.SelectedRoutePath() the metrics look like this -// api_server_http_request_duration_seconds_bucket{code="201",handler="/meshes/{mesh}/dataplanes/{name}",method="PUT",service="",le="0.005"} 3 -func MetricsHandler(handlerID string, m middleware.Middleware) gorestful.FilterFunction { - return func(req *gorestful.Request, resp *gorestful.Response, chain *gorestful.FilterChain) { - r := &reporter{req: req, resp: resp} - m.Measure(handlerID, r, func() { - chain.ProcessFilter(req, resp) - }) - } -} - -type reporter struct { - req *gorestful.Request - resp *gorestful.Response -} - -func (r *reporter) Method() string { return r.req.Request.Method } - -func (r *reporter) Context() context.Context { return r.req.Request.Context() } - -func (r *reporter) URLPath() string { - return r.req.SelectedRoutePath() -} - -func (r *reporter) StatusCode() int { return r.resp.StatusCode() } - -func (r *reporter) BytesWritten() int64 { return int64(r.resp.ContentLength()) }
diff --git a/pkg/common/util/rmkey/resource_name.go b/pkg/common/util/rmkey/resource_name.go deleted file mode 100644 index a1b7782..0000000 --- a/pkg/common/util/rmkey/resource_name.go +++ /dev/null
@@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 rmkey - -import ( - "strings" - - utilk8s "github.com/apache/dubbo-admin/pkg/common/util/k8s" -) - -const ( - firstDelimiter = "-" - secondDelimiter = "." - separator = "/" -) - -func GenerateMetadataResourceKey(app string, revision string, namespace string) string { - res := app - if revision != "" { - res += firstDelimiter + revision - } - if namespace != "" { - res += secondDelimiter + revision - } - return res -} - -func GenerateNamespacedName(name string, namespace string) string { - if namespace == "" { // it's cluster scoped object - return name - } - return utilk8s.K8sNamespacedNameToCoreName(name, namespace) -} - -func GenerateMappingResourceKey(interfaceName string, namespace string) string { - res := strings.ToLower(strings.ReplaceAll(interfaceName, ".", "-")) - if namespace == "" { - return res - } - return utilk8s.K8sNamespacedNameToCoreName(res, namespace) -}
diff --git a/pkg/common/util/rsa/keygen.go b/pkg/common/util/rsa/keygen.go deleted file mode 100644 index ea271d3..0000000 --- a/pkg/common/util/rsa/keygen.go +++ /dev/null
@@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 rsa - -import ( - "crypto/rand" - "crypto/rsa" -) - -const DefaultKeySize = 2048 - -// GenerateKey generates a new default RSA keypair. -func GenerateKey(bits int) (*rsa.PrivateKey, error) { - return rsa.GenerateKey(rand.Reader, bits) -}
diff --git a/pkg/common/util/rsa/pem.go b/pkg/common/util/rsa/pem.go deleted file mode 100644 index c164a73..0000000 --- a/pkg/common/util/rsa/pem.go +++ /dev/null
@@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 rsa - -import ( - "bytes" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - - "github.com/pkg/errors" -) - -const ( - publicBlockType = "PUBLIC KEY" - rsaPrivateBlockType = "RSA PRIVATE KEY" - rsaPublicBlockType = "RSA PUBLIC KEY" -) - -func FromPrivateKeyToPEMBytes(key *rsa.PrivateKey) ([]byte, error) { - block := pem.Block{ - Type: rsaPrivateBlockType, - Bytes: x509.MarshalPKCS1PrivateKey(key), - } - var keyBuf bytes.Buffer - if err := pem.Encode(&keyBuf, &block); err != nil { - return nil, err - } - return keyBuf.Bytes(), nil -} - -func FromPrivateKeyToPublicKeyPEMBytes(key *rsa.PrivateKey) ([]byte, error) { - block := pem.Block{ - Type: rsaPublicBlockType, - Bytes: x509.MarshalPKCS1PublicKey(&key.PublicKey), - } - var keyBuf bytes.Buffer - if err := pem.Encode(&keyBuf, &block); err != nil { - return nil, err - } - return keyBuf.Bytes(), nil -} - -func FromPrivateKeyPEMBytesToPublicKeyPEMBytes(b []byte) ([]byte, error) { - privateKey, err := FromPEMBytesToPrivateKey(b) - if err != nil { - return nil, err - } - - return FromPrivateKeyToPublicKeyPEMBytes(privateKey) -} - -func FromPEMBytesToPrivateKey(b []byte) (*rsa.PrivateKey, error) { - block, _ := pem.Decode(b) - if block.Type != rsaPrivateBlockType { - return nil, errors.Errorf("invalid key encoding %q", block.Type) - } - return x509.ParsePKCS1PrivateKey(block.Bytes) -} - -func FromPEMBytesToPublicKey(b []byte) (*rsa.PublicKey, error) { - block, _ := pem.Decode(b) - - switch block.Type { - case rsaPublicBlockType: - return x509.ParsePKCS1PublicKey(block.Bytes) - case publicBlockType: - return rsaKeyFromPKIX(block.Bytes) - default: - return nil, errors.Errorf("invalid key encoding %q", block.Type) - } -} - -func IsPrivateKeyPEMBytes(b []byte) bool { - block, _ := pem.Decode(b) - return block != nil && block.Type == rsaPrivateBlockType -} - -func IsPublicKeyPEMBytes(b []byte) bool { - block, _ := pem.Decode(b) - - if block != nil && block.Type == rsaPublicBlockType { - return true - } - - if block != nil && block.Type == publicBlockType { - _, err := rsaKeyFromPKIX(block.Bytes) - return err == nil - } - - return false -} - -func rsaKeyFromPKIX(bytes []byte) (*rsa.PublicKey, error) { - key, err := x509.ParsePKIXPublicKey(bytes) - if err != nil { - return nil, err - } - - rsaKey, ok := key.(*rsa.PublicKey) - if !ok { - return nil, errors.Errorf("encoded key is not a RSA key") - } - - return rsaKey, nil -}
diff --git a/pkg/common/util/sets/set.go b/pkg/common/util/sets/set.go deleted file mode 100644 index c1125e8..0000000 --- a/pkg/common/util/sets/set.go +++ /dev/null
@@ -1,293 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 sets - -import ( - "fmt" - - "golang.org/x/exp/constraints" - - "github.com/apache/dubbo-admin/pkg/common/util/slices" -) - -type Set[T comparable] map[T]struct{} - -type String = Set[string] - -// NewWithLength returns an empty Set with the given capacity. -// It's only a hint, not a limitation. -func NewWithLength[T comparable](l int) Set[T] { - return make(Set[T], l) -} - -// New creates a new Set with the given items. -func New[T comparable](items ...T) Set[T] { - s := NewWithLength[T](len(items)) - return s.InsertAll(items...) -} - -// Insert a single item to this Set. -func (s Set[T]) Insert(item T) Set[T] { - s[item] = struct{}{} - return s -} - -// InsertAll adds the items to this Set. -func (s Set[T]) InsertAll(items ...T) Set[T] { - for _, item := range items { - s[item] = struct{}{} - } - return s -} - -// Delete removes an item from the set. -func (s Set[T]) Delete(item T) Set[T] { - delete(s, item) - return s -} - -// DeleteAll removes items from the set. -func (s Set[T]) DeleteAll(items ...T) Set[T] { - for _, item := range items { - delete(s, item) - } - return s -} - -// Merge a set of objects that are in s2 into s -// For example: -// s = {a1, a2, a3} -// s2 = {a3, a4, a5} -// s.Merge(s2) = {a1, a2, a3, a4, a5} -func (s Set[T]) Merge(s2 Set[T]) Set[T] { - for item := range s2 { - s[item] = struct{}{} - } - - return s -} - -// Copy this set. -func (s Set[T]) Copy() Set[T] { - result := NewWithLength[T](s.Len()) - for key := range s { - result.Insert(key) - } - return result -} - -// Union returns a set of objects that are in s or s2 -// For example: -// s = {a1, a2, a3} -// s2 = {a1, a2, a4, a5} -// s.Union(s2) = s2.Union(s) = {a1, a2, a3, a4, a5} -func (s Set[T]) Union(s2 Set[T]) Set[T] { - result := s.Copy() - for key := range s2 { - result.Insert(key) - } - return result -} - -// Difference returns a set of objects that are not in s2 -// For example: -// s = {a1, a2, a3} -// s2 = {a1, a2, a4, a5} -// s.Difference(s2) = {a3} -// s2.Difference(s) = {a4, a5} -func (s Set[T]) Difference(s2 Set[T]) Set[T] { - result := New[T]() - for key := range s { - if !s2.Contains(key) { - result.Insert(key) - } - } - return result -} - -// DifferenceInPlace similar to Difference, but has better performance. -// Note: This function modifies s in place. -func (s Set[T]) DifferenceInPlace(s2 Set[T]) Set[T] { - for key := range s { - if s2.Contains(key) { - delete(s, key) - } - } - return s -} - -// Diff takes a pair of Sets, and returns the elements that occur only on the left and right set. -func (s Set[T]) Diff(other Set[T]) (left []T, right []T) { - for k := range s { - if _, f := other[k]; !f { - left = append(left, k) - } - } - for k := range other { - if _, f := s[k]; !f { - right = append(right, k) - } - } - return -} - -// Intersection returns a set of objects that are common between s and s2 -// For example: -// s = {a1, a2, a3} -// s2 = {a1, a2, a4, a5} -// s.Intersection(s2) = {a1, a2} -func (s Set[T]) Intersection(s2 Set[T]) Set[T] { - result := New[T]() - for key := range s { - if s2.Contains(key) { - result.Insert(key) - } - } - return result -} - -// IntersectInPlace similar to Intersection, but has better performance. -// Note: This function modifies s in place. -func (s Set[T]) IntersectInPlace(s2 Set[T]) Set[T] { - for key := range s { - if !s2.Contains(key) { - delete(s, key) - } - } - return s -} - -// SupersetOf returns true if s contains all elements of s2 -// For example: -// s = {a1, a2, a3} -// s2 = {a1, a2, a3, a4, a5} -// s.SupersetOf(s2) = false -// s2.SupersetOf(s) = true -func (s Set[T]) SupersetOf(s2 Set[T]) bool { - if s2 == nil { - return true - } - if len(s2) > len(s) { - return false - } - for key := range s2 { - if !s.Contains(key) { - return false - } - } - return true -} - -// UnsortedList returns the slice with contents in random order. -func (s Set[T]) UnsortedList() []T { - res := make([]T, 0, s.Len()) - for key := range s { - res = append(res, key) - } - return res -} - -// SortedList returns the slice with contents sorted. -func SortedList[T constraints.Ordered](s Set[T]) []T { - res := s.UnsortedList() - slices.Sort(res) - return res -} - -// InsertContains inserts the item into the set and returns if it was already present. -// Example: -// -// if !set.InsertContains(item) { -// fmt.Println("Added item for the first time", item) -// } -func (s Set[T]) InsertContains(item T) bool { - if s.Contains(item) { - return true - } - s[item] = struct{}{} - return false -} - -// Contains returns whether the given item is in the set. -func (s Set[T]) Contains(item T) bool { - _, ok := s[item] - return ok -} - -// ContainsAll is alias of SupersetOf -// returns true if s contains all elements of s2 -func (s Set[T]) ContainsAll(s2 Set[T]) bool { - return s.SupersetOf(s2) -} - -// Equals checks whether the given set is equal to the current set. -func (s Set[T]) Equals(other Set[T]) bool { - if s.Len() != other.Len() { - return false - } - - for key := range s { - if !other.Contains(key) { - return false - } - } - - return true -} - -// Len returns the number of elements in this Set. -func (s Set[T]) Len() int { - return len(s) -} - -// IsEmpty indicates whether the set is the empty set. -func (s Set[T]) IsEmpty() bool { - return len(s) == 0 -} - -// String returns a string representation of the set. -// Be aware that the order of elements is random so the string representation may vary. -// Use it only for debugging and logging. -func (s Set[T]) String() string { - return fmt.Sprintf("%v", s.UnsortedList()) -} - -// InsertOrNew inserts t into the set if the set exists, or returns a new set with t if not. -// Works well with DeleteCleanupLast. -// Example: -// -// InsertOrNew(m, key, value) -func InsertOrNew[K comparable, T comparable](m map[K]Set[T], k K, v T) { - s, f := m[k] - if !f { - m[k] = New(v) - } else { - s.Insert(v) - } -} - -// DeleteCleanupLast removes an element from a set in a map of sets, deleting the key from the map if there are no keys left. -// Works well with InsertOrNew. -// Example: -// -// sets.DeleteCleanupLast(m, key, value) -func DeleteCleanupLast[K comparable, T comparable](m map[K]Set[T], k K, v T) { - if m[k].Delete(v).IsEmpty() { - delete(m, k) - } -}
diff --git a/pkg/common/util/sets/set_test.go b/pkg/common/util/sets/set_test.go deleted file mode 100644 index 78e7f44..0000000 --- a/pkg/common/util/sets/set_test.go +++ /dev/null
@@ -1,392 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 sets - -import ( - "fmt" - "reflect" - "testing" -) - -import ( - "github.com/stretchr/testify/assert" - - "k8s.io/apimachinery/pkg/util/rand" -) - -func TestNewSet(t *testing.T) { - elements := []string{"a", "b", "c"} - set := New(elements...) - - if len(set) != len(elements) { - t.Errorf("Expected length %d != %d", len(set), len(elements)) - } - - for _, e := range elements { - if _, exist := set[e]; !exist { - t.Errorf("%s is not in set %v", e, set) - } - } -} - -func TestUnion(t *testing.T) { - elements := []string{"a", "b", "c", "d"} - elements2 := []string{"a", "b", "e"} - want := New("a", "b", "c", "d", "e") - for _, sets := range [][]Set[string]{ - {New(elements...), New(elements2...)}, - {New(elements2...), New(elements...)}, - } { - s1, s2 := sets[0], sets[1] - if got := s1.Union(s2); !got.Equals(want) { - t.Errorf("expected %v; got %v", want, got) - } - } -} - -func TestDifference(t *testing.T) { - s1 := New("a", "b", "c", "d") - s2 := New("a", "b", "e") - want := New("c", "d") - - t.Run("difference", func(t *testing.T) { - d := s1.Difference(s2) - if !want.Equals(d) { - t.Errorf("want %+v, but got %+v", want, d) - } - }) - - t.Run("difference in place", func(t *testing.T) { - s1c := s1.Copy() - r := s1c.DifferenceInPlace(s2) - if !want.Equals(r) { - t.Errorf("want %+v, but got %+v", want, r) - } - // s1c should be updated - if !want.Equals(s1c) { - t.Errorf("want %+v, but got %+v", want, s1c) - } - }) -} - -func TestIntersection(t *testing.T) { - s1 := New("a", "b", "d") - s2 := New("a", "b", "c") - want := New("a", "b") - - t.Run("intersection", func(t *testing.T) { - d := s1.Intersection(s2) - if !d.Equals(want) { - t.Errorf("want %+v, but got %+v", want, d) - } - }) - - t.Run("intersect in replace", func(t *testing.T) { - s1c := s1.Copy() - d := s1c.IntersectInPlace(s2) - if !want.Equals(d) { - t.Errorf("want %+v, but got %+v", want, d) - } - // s1c should be updated - if !want.Equals(s1c) { - t.Errorf("want %+v, but got %+v", want, s1c) - } - }) -} - -func TestSupersetOf(t *testing.T) { - testCases := []struct { - name string - first Set[string] - second Set[string] - want bool - }{ - { - name: "both nil", - first: nil, - second: nil, - want: true, - }, - { - name: "first nil", - first: nil, - second: New("a"), - want: false, - }, - { - name: "second nil", - first: New("a"), - second: nil, - want: true, - }, - { - name: "both empty", - first: New[string](), - second: New[string](), - want: true, - }, - { - name: "first empty", - first: New[string](), - second: New("a"), - want: false, - }, - { - name: "second empty", - first: New("a"), - second: New[string](), - want: true, - }, - { - name: "equal", - first: New("a", "b"), - second: New("a", "b"), - want: true, - }, - { - name: "first contains all second", - first: New("a", "b", "c"), - second: New("a", "b"), - want: true, - }, - { - name: "second contains all first", - first: New("a", "b"), - second: New("a", "b", "c"), - want: false, - }, - } - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - if got := tt.first.SupersetOf(tt.second); got != tt.want { - t.Errorf("want %v, but got %v", tt.want, got) - } - }) - } -} - -func BenchmarkSupersetOf(b *testing.B) { - set1 := New[string]() - for i := 0; i < 1000; i++ { - set1.Insert(fmt.Sprint(i)) - } - set2 := New[string]() - for i := 0; i < 50; i++ { - set2.Insert(fmt.Sprint(i)) - } - b.ResetTimer() - - b.Run("SupersetOf", func(b *testing.B) { - for n := 0; n < b.N; n++ { - set1.SupersetOf(set2) - } - }) -} - -func TestEquals(t *testing.T) { - tests := []struct { - name string - first Set[string] - second Set[string] - want bool - }{ - { - "both nil", - nil, - nil, - true, - }, - { - "unequal length", - New("test"), - New("test", "test1"), - false, - }, - { - "equal sets", - New("test", "test1"), - New("test", "test1"), - true, - }, - { - "unequal sets", - New("test", "test1"), - New("test", "test2"), - false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.first.Equals(tt.second); got != tt.want { - t.Errorf("Unexpected Equal. got %v, want %v", got, tt.want) - } - }) - } -} - -func TestMerge(t *testing.T) { - cases := []struct { - s1, s2 Set[string] - expected []string - }{ - { - s1: New("a1", "a2"), - s2: New("a1", "a2"), - expected: []string{"a1", "a2"}, - }, - { - s1: New("a1", "a2", "a3"), - s2: New("a1", "a2"), - expected: []string{"a1", "a2", "a3"}, - }, - { - s1: New("a1", "a2"), - s2: New("a3", "a4"), - expected: []string{"a1", "a2", "a3", "a4"}, - }, - } - - for _, tc := range cases { - got := tc.s1.Merge(tc.s2) - assert.Equal(t, tc.expected, SortedList(got)) - } -} - -func TestInsertAll(t *testing.T) { - tests := []struct { - name string - s Set[string] - items []string - want Set[string] - }{ - { - name: "insert new item", - s: New("a1", "a2"), - items: []string{"a3"}, - want: New("a1", "a2", "a3"), - }, - { - name: "inserted item already exists", - s: New("a1", "a2"), - items: []string{"a1"}, - want: New("a1", "a2"), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.InsertAll(tt.items...); !reflect.DeepEqual(got, tt.want) { - t.Errorf("InsertAll() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInsertContains(t *testing.T) { - s := New[string]() - assert.Equal(t, s.InsertContains("k1"), false) - assert.Equal(t, s.InsertContains("k1"), true) - assert.Equal(t, s.InsertContains("k2"), false) - assert.Equal(t, s.InsertContains("k2"), true) -} - -func BenchmarkSet(b *testing.B) { - containsTest := New[string]() - for i := 0; i < 1000; i++ { - containsTest.Insert(fmt.Sprint(i)) - } - sortOrder := []string{} - for i := 0; i < 1000; i++ { - sortOrder = append(sortOrder, fmt.Sprint(rand.Intn(1000))) - } - b.ResetTimer() - var s Set[string] // ensure no inlining - b.Run("insert", func(b *testing.B) { - for n := 0; n < b.N; n++ { - s = New[string]() - for i := 0; i < 1000; i++ { - s.Insert("item") - } - } - }) - b.Run("contains", func(b *testing.B) { - for n := 0; n < b.N; n++ { - containsTest.Contains("100") - } - }) - b.Run("sorted", func(b *testing.B) { - for n := 0; n < b.N; n++ { - b.StopTimer() - s := New(sortOrder...) - b.StartTimer() - SortedList(s) - } - }) -} - -func TestMapOfSet(t *testing.T) { - m := map[int]String{} - InsertOrNew(m, 1, "a") - InsertOrNew(m, 1, "b") - InsertOrNew(m, 2, "c") - assert.Equal(t, m, map[int]String{1: New("a", "b"), 2: New("c")}) - - DeleteCleanupLast(m, 1, "a") - assert.Equal(t, m, map[int]String{1: New("b"), 2: New("c")}) - DeleteCleanupLast(m, 1, "b") - DeleteCleanupLast(m, 1, "not found") - assert.Equal(t, m, map[int]String{2: New("c")}) -} - -func TestSetString(t *testing.T) { - elements := []string{"a"} - set := New(elements...) - assert.Equal(t, "[a]", set.String()) -} - -func BenchmarkOperateInPlace(b *testing.B) { - s1 := New[int]() - for i := 0; i < 100; i++ { - s1.Insert(i) - } - s2 := New[int]() - for i := 0; i < 100; i += 2 { - s2.Insert(i) - } - b.ResetTimer() - - b.Run("Difference", func(b *testing.B) { - for i := 0; i < b.N; i++ { - s1.Difference(s2) - } - }) - b.Run("DifferenceInPlace", func(b *testing.B) { - for i := 0; i < b.N; i++ { - s1.DifferenceInPlace(s2) - } - }) - b.Run("Intersection", func(b *testing.B) { - for i := 0; i < b.N; i++ { - s1.Intersection(s2) - } - }) - b.Run("IntersectInPlace", func(b *testing.B) { - for i := 0; i < b.N; i++ { - s1.IntersectInPlace(s2) - } - }) -}
diff --git a/pkg/common/util/slices/slices.go b/pkg/common/util/slices/slices.go deleted file mode 100644 index 6165c44..0000000 --- a/pkg/common/util/slices/slices.go +++ /dev/null
@@ -1,313 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 slices - -import ( - "cmp" - "slices" - "strings" - - "golang.org/x/exp/constraints" -) - -// Equal reports whether two slices are equal: the same length and all -// elements equal. If the lengths are different, Equal returns false. -// Otherwise, the elements are compared in increasing index order, and the -// comparison stops at the first unequal pair. -// Floating point NaNs are not considered equal. -func Equal[E comparable](s1, s2 []E) bool { - return slices.Equal(s1, s2) -} - -// EqualUnordered reports whether two slices are equal, ignoring order -func EqualUnordered[E comparable](s1, s2 []E) bool { - if len(s1) != len(s2) { - return false - } - first := make(map[E]struct{}, len(s1)) - for _, c := range s1 { - first[c] = struct{}{} - } - for _, c := range s2 { - if _, f := first[c]; !f { - return false - } - } - return true -} - -// EqualFunc reports whether two slices are equal using a comparison -// function on each pair of elements. If the lengths are different, -// EqualFunc returns false. Otherwise, the elements are compared in -// increasing index order, and the comparison stops at the first index -// for which eq returns false. -func EqualFunc[E1, E2 comparable](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool { - return slices.EqualFunc(s1, s2, eq) -} - -// SortFunc sorts the slice x in ascending order as determined by the less function. -// This sort is not guaranteed to be stable. -// The slice is modified in place but returned. -func SortFunc[E any](x []E, less func(a, b E) int) []E { - if len(x) <= 1 { - return x - } - slices.SortFunc(x, less) - return x -} - -// SortStableFunc sorts the slice x while keeping the original order of equal element. -// The slice is modified in place but returned. -// Please refer to SortFunc for usage instructions. -func SortStableFunc[E any](x []E, less func(a, b E) int) []E { - if len(x) <= 1 { - return x - } - slices.SortStableFunc(x, less) - return x -} - -// SortBy is a helper to sort a slice by some value. Typically, this would be sorting a struct -// by a single field. If you need to have multiple fields, see the ExampleSort. -func SortBy[E any, A constraints.Ordered](x []E, extract func(a E) A) []E { - if len(x) <= 1 { - return x - } - SortFunc(x, func(a, b E) int { - return cmp.Compare(extract(a), extract(b)) - }) - return x -} - -// Sort sorts a slice of any ordered type in ascending order. -// The slice is modified in place but returned. -func Sort[E constraints.Ordered](x []E) []E { - if len(x) <= 1 { - return x - } - slices.Sort(x) - return x -} - -// Clone returns a copy of the slice. -// The elements are copied using assignment, so this is a shallow clone. -func Clone[S ~[]E, E any](s S) S { - return slices.Clone(s) -} - -// Delete removes the element i from s, returning the modified slice. -func Delete[S ~[]E, E any](s S, i int) S { - // Since Go 1.22, "slices.Delete zeroes the elements s[len(s)-(j-i):len(s)]" - // (no memory leak) - return slices.Delete(s, i, i+1) -} - -// Contains reports whether v is present in s. -func Contains[E comparable](s []E, v E) bool { - return slices.Contains(s, v) -} - -// FindFunc finds the first element matching the function, or nil if none do -func FindFunc[E any](s []E, f func(E) bool) *E { - idx := slices.IndexFunc(s, f) - if idx == -1 { - return nil - } - return &s[idx] -} - -// First returns the first item in the slice, if there is one -func First[E any](s []E) *E { - if len(s) == 0 { - return nil - } - return &s[0] -} - -// Reverse returns its argument array reversed -func Reverse[E any](r []E) []E { - for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { - r[i], r[j] = r[j], r[i] - } - return r -} - -func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) { - return slices.BinarySearch(x, target) -} - -// FilterInPlace retains all elements in []E that f(E) returns true for. -// The array is *mutated in place* and returned. -// Use Filter to avoid mutation -func FilterInPlace[E any](s []E, f func(E) bool) []E { - n := 0 - for _, val := range s { - if f(val) { - s[n] = val - n++ - } - } - - // If those elements contain pointers you might consider zeroing those elements - // so that objects they reference can be garbage collected." - var empty E - for i := n; i < len(s); i++ { - s[i] = empty - } - - s = s[:n] - return s -} - -// FilterDuplicatesPresorted retains all unique elements in []E. -// The slices MUST be pre-sorted. -func FilterDuplicatesPresorted[E comparable](s []E) []E { - if len(s) <= 1 { - return s - } - n := 1 - for i := 1; i < len(s); i++ { - val := s[i] - if val != s[i-1] { - s[n] = val - n++ - } - } - - // If those elements contain pointers you might consider zeroing those elements - // so that objects they reference can be garbage collected." - var empty E - for i := n; i < len(s); i++ { - s[i] = empty - } - - s = s[:n] - return s -} - -// Filter retains all elements in []E that f(E) returns true for. -// A new slice is created and returned. Use FilterInPlace to perform in-place -func Filter[E any](s []E, f func(E) bool) []E { - matched := []E{} - for _, v := range s { - if f(v) { - matched = append(matched, v) - } - } - return matched -} - -// Map runs f() over all elements in s and returns the result -func Map[E any, O any](s []E, f func(E) O) []O { - n := make([]O, 0, len(s)) - for _, e := range s { - n = append(n, f(e)) - } - return n -} - -// MapErr runs f() over all elements in s and returns the result, short circuiting if there is an error. -func MapErr[E any, O any](s []E, f func(E) (O, error)) ([]O, error) { - n := make([]O, 0, len(s)) - for _, e := range s { - res, err := f(e) - if err != nil { - return nil, err - } - n = append(n, res) - } - return n, nil -} - -// MapFilter runs f() over all elements in s and returns any non-nil results -func MapFilter[E any, O any](s []E, f func(E) *O) []O { - n := make([]O, 0, len(s)) - for _, e := range s { - if res := f(e); res != nil { - n = append(n, *res) - } - } - return n -} - -// Reference takes a pointer to all elements in the slice -func Reference[E any](s []E) []*E { - res := make([]*E, 0, len(s)) - for _, v := range s { - v := v - res = append(res, &v) - } - return res -} - -// Dereference returns all non-nil references, dereferenced -func Dereference[E any](s []*E) []E { - res := make([]E, 0, len(s)) - for _, v := range s { - if v != nil { - res = append(res, *v) - } - } - return res -} - -// Flatten merges a slice of slices into a single slice. -func Flatten[E any](s [][]E) []E { - if s == nil { - return nil - } - res := make([]E, 0) - for _, v := range s { - res = append(res, v...) - } - return res -} - -// Group groups a slice by a key. -func Group[T any, K comparable](data []T, f func(T) K) map[K][]T { - res := make(map[K][]T, len(data)) - for _, e := range data { - k := f(e) - res[k] = append(res[k], e) - } - return res -} - -// GroupUnique groups a slice by a key. Each key must be unique or data will be lost. To allow multiple use Group. -func GroupUnique[T any, K comparable](data []T, f func(T) K) map[K]T { - res := make(map[K]T, len(data)) - for _, e := range data { - res[f(e)] = e - } - return res -} - -func Join(sep string, fields ...string) string { - return strings.Join(fields, sep) -} - -// Insert inserts the values v... into s at index i, -// returning the modified slice. -// The elements at s[i:] are shifted up to make room. -// In the returned slice r, r[i] == v[0], -// and r[i+len(v)] == value originally at r[i]. -// Insert panics if i is out of range. -// This function is O(len(s) + len(v)). -func Insert[S ~[]E, E any](s S, i int, v ...E) S { - return slices.Insert(s, i, v...) -}
diff --git a/pkg/common/util/slices/slices_test.go b/pkg/common/util/slices/slices_test.go deleted file mode 100644 index facb08e..0000000 --- a/pkg/common/util/slices/slices_test.go +++ /dev/null
@@ -1,916 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 slices - -import ( - "cmp" - "fmt" - "math/rand" - "reflect" - "strconv" - "testing" -) - -import ( - cmp2 "github.com/google/go-cmp/cmp" - - "github.com/stretchr/testify/assert" -) - -type s struct { - Junk string -} - -func TestEqual(t *testing.T) { - tests := []struct { - name string - s1 []int - s2 []int - want bool - }{ - {"Empty Slices", []int{}, []int{}, true}, - {"Equal Slices", []int{1, 2, 3}, []int{1, 2, 3}, true}, - {"Unequal Slices", []int{1, 2, 3}, []int{3, 2, 1}, false}, - {"One Empty Slice", []int{}, []int{1, 2, 3}, false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := Equal(tt.s1, tt.s2) - if got != tt.want { - t.Errorf("Equal() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestEqualFunc(t *testing.T) { - tests := []struct { - name string - s1 []int - s2 []int - eq func(int, int) bool - want bool - }{ - { - name: "Equal slices", - s1: []int{1, 2, 3}, - s2: []int{1, 2, 3}, - eq: func(a, b int) bool { - return a == b - }, - want: true, - }, - { - name: "Unequal slices", - s1: []int{1, 2, 3}, - s2: []int{4, 5, 6}, - eq: func(a, b int) bool { - return a == b - }, - want: false, - }, - { - name: "Empty slices", - s1: []int{}, - s2: []int{}, - eq: func(a, b int) bool { - return a == b - }, - want: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := EqualFunc(tt.s1, tt.s2, tt.eq) - if diff := cmp2.Diff(tt.want, got); diff != "" { - t.Errorf("Unexpected result (-want +got):\n%s", diff) - } - }) - } -} - -func TestSortBy(t *testing.T) { - testCases := []struct { - name string - input []int - extract func(a int) int - expected []int - }{ - { - name: "Normal Case", - input: []int{4, 2, 3, 1}, - extract: func(a int) int { return a }, - expected: []int{1, 2, 3, 4}, - }, - { - name: "Reverse Case", - input: []int{1, 2, 3, 4}, - extract: func(a int) int { return -a }, - expected: []int{4, 3, 2, 1}, - }, - { - name: "Same Elements Case", - input: []int{2, 2, 2, 2}, - extract: func(a int) int { return a }, - expected: []int{2, 2, 2, 2}, - }, - { - name: "Empty Slice Case", - input: []int{}, - extract: func(a int) int { return a }, - expected: []int{}, - }, - { - name: "One Element Case", - input: []int{1}, - extract: func(a int) int { return a }, - expected: []int{1}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := SortBy(tc.input, tc.extract) - if !reflect.DeepEqual(result, tc.expected) { - t.Fatalf("Expected: %+v, but got: %+v", tc.expected, result) - } - }) - } -} - -func TestSort(t *testing.T) { - testCases := []struct { - name string - input []int - expected []int - }{ - { - name: "Single_Element", - input: []int{1}, - expected: []int{1}, - }, - { - name: "Already_Sorted", - input: []int{1, 2, 3, 4}, - expected: []int{1, 2, 3, 4}, - }, - { - name: "Reverse_Order", - input: []int{4, 3, 2, 1}, - expected: []int{1, 2, 3, 4}, - }, - { - name: "Unique_Elements", - input: []int{12, 3, 5, 1, 27}, - expected: []int{1, 3, 5, 12, 27}, - }, - { - name: "Empty_Slice", - input: []int{}, - expected: []int{}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := Sort(tc.input) - if !reflect.DeepEqual(result, tc.expected) { - t.Fatalf("Expected %v, got %v", tc.expected, result) - } - }) - } -} - -func TestReverse(t *testing.T) { - tests := []struct { - name string - input []int - expected []int - }{ - { - name: "empty slice", - input: []int{}, - expected: []int{}, - }, - { - name: "single element", - input: []int{1}, - expected: []int{1}, - }, - { - name: "two elements", - input: []int{1, 2}, - expected: []int{2, 1}, - }, - { - name: "multiple elements", - input: []int{1, 2, 3, 4, 5}, - expected: []int{5, 4, 3, 2, 1}, - }, - { - name: "odd number of elements", - input: []int{1, 2, 3}, - expected: []int{3, 2, 1}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - result := Reverse(tc.input) - if diff := cmp2.Diff(tc.expected, result); diff != "" { - t.Errorf("Reverse() mismatch (-want +got):\n%s", diff) - } - }) - } -} - -func TestClone(t *testing.T) { - tests := []struct { - name string - slice []interface{} - }{ - { - name: "Empty", - slice: []interface{}{}, - }, - { - name: "Single Element", - slice: []interface{}{1}, - }, - { - name: "Multiple Elements", - slice: []interface{}{1, "a", 3.14159}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - clone := Clone(tt.slice) - if !reflect.DeepEqual(clone, tt.slice) { - t.Errorf("Clone() got = %v, want = %v", clone, tt.slice) - } - }) - } -} - -func TestDelete(t *testing.T) { - type s struct { - Junk string - } - var input []*s - var output []*s - t.Run("inner", func(t *testing.T) { - a := &s{"a"} - b := &s{"b"} - input = []*s{a, b} - output = Delete(input, 1) - }) - assert.Equal(t, output, []*s{{"a"}}) -} - -func TestContains(t *testing.T) { - testCases := []struct { - name string - slice []int - v int - want bool - }{ - { - name: "ContainsElement", - slice: []int{1, 2, 3, 4, 5}, - v: 3, - want: true, - }, - { - name: "DoesNotContainElement", - slice: []int{1, 2, 3, 4, 5}, - v: 6, - want: false, - }, - { - name: "EmptySlice", - slice: []int{}, - v: 1, - want: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - if got := Contains(tc.slice, tc.v); got != tc.want { - t.Errorf("Contains(%v, %v) = %v; want %v", tc.slice, tc.v, got, tc.want) - } - }) - } -} - -func TestFindFunc(t *testing.T) { - emptyElement := []string{} - elements := []string{"a", "b", "c"} - tests := []struct { - name string - elements []string - fn func(string) bool - want *string - }{ - { - elements: emptyElement, - fn: func(s string) bool { - return s == "b" - }, - want: nil, - }, - { - elements: elements, - fn: func(s string) bool { - return s == "bb" - }, - want: nil, - }, - { - elements: elements, - fn: func(s string) bool { - return s == "b" - }, - want: &elements[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := FindFunc(tt.elements, tt.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("FindFunc got %v, want %v", got, tt.want) - } - }) - } -} - -func TestFilter(t *testing.T) { - tests := []struct { - name string - elements []string - fn func(string) bool - want []string - }{ - { - name: "empty element", - elements: []string{}, - fn: func(s string) bool { - return len(s) > 1 - }, - want: []string{}, - }, - { - name: "element length equals 0", - elements: []string{"", "", ""}, - fn: func(s string) bool { - return len(s) > 1 - }, - want: []string{}, - }, - { - name: "filter elements with length greater than 1", - elements: []string{"a", "bbb", "ccc", ""}, - fn: func(s string) bool { - return len(s) > 1 - }, - want: []string{"bbb", "ccc"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - filter := Filter(tt.elements, tt.fn) - if !reflect.DeepEqual(filter, tt.want) { - t.Errorf("Filter got %v, want %v", filter, tt.want) - } - filterInPlace := FilterInPlace(tt.elements, tt.fn) - if !reflect.DeepEqual(filterInPlace, tt.want) { - t.Errorf("FilterInPlace got %v, want %v", filterInPlace, tt.want) - } - if !reflect.DeepEqual(filter, filterInPlace) { - t.Errorf("Filter got %v, FilterInPlace got %v", filter, filterInPlace) - } - }) - } -} - -func TestFilterInPlace(t *testing.T) { - var input []*s - var output []*s - a := &s{"a"} - b := &s{"b"} - c := &s{"c"} - input = []*s{a, b, c} - - t.Run("delete first element a", func(t *testing.T) { - output = FilterInPlace(input, func(s *s) bool { - return s != nil && s.Junk != "a" - }) - }) - assert.Equal(t, output, []*s{{"b"}, {"c"}}) - assert.Equal(t, input, []*s{{"b"}, {"c"}, nil}) - - t.Run("delete end element c", func(t *testing.T) { - output = FilterInPlace(input, func(s *s) bool { - return s != nil && s.Junk != "c" - }) - }) - assert.Equal(t, output, []*s{{"b"}}) - assert.Equal(t, input, []*s{{"b"}, nil, nil}) -} - -func TestMap(t *testing.T) { - tests := []struct { - name string - elements []int - fn func(int) int - want []int - }{ - { - name: "empty element", - elements: []int{}, - fn: func(s int) int { - return s + 10 - }, - want: []int{}, - }, - { - name: "add ten to each element", - elements: []int{0, 1, 2, 3}, - fn: func(s int) int { - return s + 10 - }, - want: []int{10, 11, 12, 13}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Map(tt.elements, tt.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Map got %v, want %v", got, tt.want) - } - }) - } -} - -func TestGroup(t *testing.T) { - tests := []struct { - name string - elements []string - fn func(string) int - want map[int][]string - }{ - { - name: "empty element", - elements: []string{}, - fn: func(s string) int { - return len(s) - }, - want: map[int][]string{}, - }, - { - name: "group by the length of each element", - elements: []string{"", "a", "b", "cc"}, - fn: func(s string) int { - return len(s) - }, - want: map[int][]string{0: {""}, 1: {"a", "b"}, 2: {"cc"}}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Group(tt.elements, tt.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GroupUnique got %v, want %v", got, tt.want) - } - }) - } -} - -func TestGroupUnique(t *testing.T) { - tests := []struct { - name string - elements []string - fn func(string) int - want map[int]string - }{ - { - name: "empty element", - elements: []string{}, - fn: func(s string) int { - return len(s) - }, - want: map[int]string{}, - }, - { - name: "group by the length of each element", - elements: []string{"", "a", "bb", "ccc"}, - fn: func(s string) int { - return len(s) - }, - want: map[int]string{0: "", 1: "a", 2: "bb", 3: "ccc"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GroupUnique(tt.elements, tt.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GroupUnique got %v, want %v", got, tt.want) - } - }) - } -} - -var ( - i1, i2, i3 = 1, 2, 3 - s1, s2, s3 = "a", "b", "c" -) - -func TestMapFilter(t *testing.T) { - tests := []struct { - name string - input []int - function func(int) *int - want []int - }{ - { - name: "RegularMapping", - input: []int{1, 2, 3, 4, 5}, - function: func(num int) *int { - if num%2 == 0 { - return &num - } - return nil - }, - want: []int{2, 4}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - got := MapFilter(tc.input, tc.function) - - if len(got) != len(tc.want) { - t.Errorf("got %d, want %d", got, tc.want) - } - - for i := range got { - if got[i] != tc.want[i] { - t.Errorf("got %d, want %d", got[i], tc.want[i]) - } - } - }) - } -} - -func TestReference(t *testing.T) { - type args[E any] struct { - s []E - } - type testCase[E any] struct { - name string - args args[E] - want []*E - } - stringTests := []testCase[string]{ - { - name: "empty slice", - args: args[string]{ - []string{}, - }, - want: []*string{}, - }, - { - name: "slice with 1 element", - args: args[string]{ - []string{s1}, - }, - want: []*string{&s1}, - }, - { - name: "slice with many elements", - args: args[string]{ - []string{s1, s2, s3}, - }, - want: []*string{&s1, &s2, &s3}, - }, - } - intTests := []testCase[int]{ - { - name: "empty slice", - args: args[int]{ - []int{}, - }, - want: []*int{}, - }, - { - name: "slice with 1 element", - args: args[int]{ - []int{i1}, - }, - want: []*int{&i1}, - }, - { - name: "slice with many elements", - args: args[int]{ - []int{i1, i2, i3}, - }, - want: []*int{&i1, &i2, &i3}, - }, - } - for _, tt := range stringTests { - t.Run(tt.name, func(t *testing.T) { - if got := Reference(tt.args.s); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Reference() = %v, want %v", got, tt.want) - } - }) - } - for _, tt := range intTests { - t.Run(tt.name, func(t *testing.T) { - if got := Reference(tt.args.s); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Reference() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestDereference(t *testing.T) { - type args[E any] struct { - s []*E - } - type testCase[E any] struct { - name string - args args[E] - want []E - } - stringTests := []testCase[string]{ - { - name: "empty slice", - args: args[string]{ - []*string{}, - }, - want: []string{}, - }, - { - name: "slice with 1 element", - args: args[string]{ - []*string{&s1}, - }, - want: []string{s1}, - }, - { - name: "slice with many elements", - args: args[string]{ - []*string{&s1, &s2, &s3}, - }, - want: []string{s1, s2, s3}, - }, - } - intTests := []testCase[int]{ - { - name: "empty slice", - args: args[int]{ - []*int{}, - }, - want: []int{}, - }, - { - name: "slice with 1 element", - args: args[int]{ - []*int{&i1}, - }, - want: []int{i1}, - }, - { - name: "slice with many elements", - args: args[int]{ - []*int{&i1, &i2, &i3}, - }, - want: []int{i1, i2, i3}, - }, - } - for _, tt := range stringTests { - t.Run(tt.name, func(t *testing.T) { - if got := Dereference(tt.args.s); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Dereference() = %v, want %v", got, tt.want) - } - }) - } - for _, tt := range intTests { - t.Run(tt.name, func(t *testing.T) { - if got := Dereference(tt.args.s); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Dereference() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFlatten(t *testing.T) { - testCases := []struct { - name string - input [][]int - want []int - }{ - { - name: "simple case", - input: [][]int{{1, 2}, {3, 4}, {5, 6}}, - want: []int{1, 2, 3, 4, 5, 6}, - }, - { - name: "empty inner slices", - input: [][]int{{}, {}, {}}, - want: []int{}, - }, - { - name: "nil slice", - input: nil, - want: nil, - }, - { - name: "empty slice", - input: [][]int{}, - want: []int{}, - }, - { - name: "single element slices", - input: [][]int{{1}, {2}, {3}}, - want: []int{1, 2, 3}, - }, - { - name: "mixed empty and non-empty slices", - input: [][]int{{1, 2}, {}, {3, 4}}, - want: []int{1, 2, 3, 4}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - got := Flatten(tc.input) - if !reflect.DeepEqual(got, tc.want) { - t.Errorf("Flatten(%v) = %v; want %v", tc.input, got, tc.want) - } - }) - } -} - -// nolint: unused -type myStruct struct { - a, b, c, d string - n int -} - -func makeRandomStructs(n int) []*myStruct { - rand.Seed(42) // nolint: staticcheck - structs := make([]*myStruct, n) - for i := 0; i < n; i++ { - structs[i] = &myStruct{n: rand.Intn(n)} // nolint: gosec - } - return structs -} - -const N = 100_000 - -func BenchmarkSort(b *testing.B) { - b.Run("SortFunc", func(b *testing.B) { - cmpFunc := func(a, b *myStruct) int { return a.n - b.n } - for i := 0; i < b.N; i++ { - b.StopTimer() - ss := makeRandomStructs(N) - b.StartTimer() - SortFunc(ss, cmpFunc) - } - }) - b.Run("SortStableFunc", func(b *testing.B) { - cmpFunc := func(a, b *myStruct) int { return a.n - b.n } - for i := 0; i < b.N; i++ { - b.StopTimer() - ss := makeRandomStructs(N) - b.StartTimer() - SortStableFunc(ss, cmpFunc) - } - }) - b.Run("SortBy", func(b *testing.B) { - cmpFunc := func(a *myStruct) int { return a.n } - for i := 0; i < b.N; i++ { - b.StopTimer() - ss := makeRandomStructs(N) - b.StartTimer() - SortBy(ss, cmpFunc) - } - }) -} - -func ExampleSort() { - // ExampleSort shows the best practices in sorting by multiple keys. - // If you just have one key, use SortBy - - // Test has 3 values; we will sort by them in Rank < First < Last order - type Test struct { - Rank int - First string - Last string - } - l := []Test{ - {0, "b", "b"}, - {0, "b", "a"}, - {1, "a", "a"}, - {0, "c", "a"}, - {1, "c", "a"}, - {0, "a", "a"}, - {2, "z", "a"}, - } - SortFunc(l, func(a, b Test) int { - if r := cmp.Compare(a.Rank, b.Rank); r != 0 { - return r - } - if r := cmp.Compare(a.First, b.First); r != 0 { - return r - } - return cmp.Compare(a.Last, b.Last) - }) - fmt.Println(l) - - // Output: - // [{0 a a} {0 b a} {0 b b} {0 c a} {1 a a} {1 c a} {2 z a}] -} - -func BenchmarkEqualUnordered(b *testing.B) { - size := 100 - var l []string - for i := 0; i < size; i++ { - l = append(l, strconv.Itoa(i)) - } - var equal []string - for i := 0; i < size; i++ { - equal = append(equal, strconv.Itoa(i)) - } - var notEqual []string - for i := 0; i < size; i++ { - notEqual = append(notEqual, strconv.Itoa(i)) - } - notEqual[size-1] = "z" - - for n := 0; n < b.N; n++ { - EqualUnordered(l, equal) - EqualUnordered(l, notEqual) - } -} - -func TestFilterDuplicates(t *testing.T) { - tests := []struct { - name string - in []string - out []string - }{ - { - name: "empty", - in: nil, - out: nil, - }, - { - name: "one", - in: []string{"a"}, - out: []string{"a"}, - }, - { - name: "no dupes", - in: []string{"a", "b", "c", "d"}, - out: []string{"a", "b", "c", "d"}, - }, - { - name: "dupes first", - in: []string{"a", "a", "c", "d"}, - out: []string{"a", "c", "d"}, - }, - { - name: "dupes last", - in: []string{"a", "b", "c", "c"}, - out: []string{"a", "b", "c"}, - }, - { - name: "dupes middle", - in: []string{"a", "b", "b", "c"}, - out: []string{"a", "b", "c"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := FilterDuplicatesPresorted(tt.in) - assert.Equal(t, tt.out, got) - assert.Equal(t, tt.out, tt.in[:len(tt.out)]) - }) - } -}
diff --git a/pkg/common/util/template/render.go b/pkg/common/util/template/render.go deleted file mode 100644 index adae2f4..0000000 --- a/pkg/common/util/template/render.go +++ /dev/null
@@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 template - -import ( - "strings" - - "github.com/hoisie/mustache" -) - -type contextMap map[string]interface{} - -func (cm contextMap) merge(other contextMap) { - for k, v := range other { - cm[k] = v - } -} - -func newContextMap(key, value string) contextMap { - if !strings.Contains(key, ".") { - return map[string]interface{}{ - key: value, - } - } - - parts := strings.SplitAfterN(key, ".", 2) - return map[string]interface{}{ - parts[0][:len(parts[0])-1]: newContextMap(parts[1], value), - } -} - -func Render(template string, values map[string]string) []byte { - ctx := contextMap{} - for k, v := range values { - ctx.merge(newContextMap(k, v)) - } - data := mustache.Render(template, ctx) - return []byte(data) -}
diff --git a/pkg/common/util/yaml/split.go b/pkg/common/util/yaml/split.go deleted file mode 100644 index ed5f76b..0000000 --- a/pkg/common/util/yaml/split.go +++ /dev/null
@@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 yaml - -import ( - "regexp" - "strings" -) - -var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*") - -// SplitYAML takes YAMLs separated by `---` line and splits it into multiple YAMLs. Empty entries are ignored -func SplitYAML(yamls string) []string { - var result []string - // Making sure that any extra whitespace in YAML stream doesn't interfere in splitting documents correctly. - trimYAMLs := strings.TrimSpace(yamls) - docs := sep.Split(trimYAMLs, -1) - for _, doc := range docs { - if doc == "" { - continue - } - doc = strings.TrimSpace(doc) - result = append(result, doc) - } - return result -}
diff --git a/pkg/common/validators/common_validators.go b/pkg/common/validators/common_validators.go deleted file mode 100644 index 1f55ad0..0000000 --- a/pkg/common/validators/common_validators.go +++ /dev/null
@@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 validators - -import ( - "fmt" - "math" - "regexp" - "time" - - "github.com/asaskevich/govalidator" - k8s "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func ValidateDurationNotNegative(path PathBuilder, duration *k8s.Duration) ValidationError { - var err ValidationError - if duration == nil { - err.AddViolationAt(path, MustBeDefined) - return err - } - if duration.Duration < 0 { - err.AddViolationAt(path, WhenDefinedHasToBeNonNegative) - } - return err -} - -func ValidateDurationNotNegativeOrNil(path PathBuilder, duration *k8s.Duration) ValidationError { - var err ValidationError - if duration == nil { - return err - } - - if duration.Duration < 0 { - err.AddViolationAt(path, WhenDefinedHasToBeNonNegative) - } - - return err -} - -func ValidateDurationGreaterThanZero(path PathBuilder, duration k8s.Duration) ValidationError { - var err ValidationError - if duration.Duration <= 0 { - err.AddViolationAt(path, MustBeDefinedAndGreaterThanZero) - } - return err -} - -func ValidateDurationGreaterThanZeroOrNil(path PathBuilder, duration *k8s.Duration) ValidationError { - var err ValidationError - if duration == nil { - return err - } - - if duration.Duration <= 0 { - err.AddViolationAt(path, WhenDefinedHasToBeGreaterThanZero) - } - - return err -} - -func ValidateValueGreaterThanZero(path PathBuilder, value int32) ValidationError { - var err ValidationError - if value <= 0 { - err.AddViolationAt(path, MustBeDefinedAndGreaterThanZero) - } - return err -} - -func ValidateValueGreaterThanZeroOrNil(path PathBuilder, value *int32) ValidationError { - var err ValidationError - if value == nil { - return err - } - if *value <= 0 { - err.AddViolationAt(path, WhenDefinedHasToBeGreaterThanZero) - } - return err -} - -func ValidateIntPercentageOrNil(path PathBuilder, percentage *int32) ValidationError { - var err ValidationError - if percentage == nil { - return err - } - - if *percentage < 0 || *percentage > 100 { - err.AddViolationAt(path, HasToBeInUintPercentageRange) - } - - return err -} - -func ValidateUInt32PercentageOrNil(path PathBuilder, percentage *uint32) ValidationError { - var err ValidationError - if percentage == nil { - return err - } - - if *percentage > 100 { - err.AddViolationAt(path, HasToBeInUintPercentageRange) - } - - return err -} - -func ValidateStringDefined(path PathBuilder, value string) ValidationError { - var err ValidationError - if value == "" { - err.AddViolationAt(path, MustBeDefined) - } - - return err -} - -func ValidatePathOrNil(path PathBuilder, filePath *string) ValidationError { - var err ValidationError - if filePath == nil { - return err - } - - isFilePath, _ := govalidator.IsFilePath(*filePath) - if !isFilePath { - err.AddViolationAt(path, WhenDefinedHasToBeValidPath) - } - - return err -} - -func ValidateStatusCode(path PathBuilder, status int32) ValidationError { - var err ValidationError - if status < 100 || status >= 600 { - err.AddViolationAt(path, fmt.Sprintf(HasToBeInRangeFormat, 100, 599)) - } - - return err -} - -func ValidateDurationGreaterThan(path PathBuilder, duration *k8s.Duration, minDuration time.Duration) ValidationError { - var err ValidationError - if duration == nil { - err.AddViolationAt(path, MustBeDefined) - return err - } - - if duration.Duration <= minDuration { - err.AddViolationAt(path, fmt.Sprintf("%s: %s", HasToBeGreaterThan, minDuration)) - } - - return err -} - -func ValidateIntegerGreaterThanZeroOrNil(path PathBuilder, value *uint32) ValidationError { - var err ValidationError - if value == nil { - return err - } - - return ValidateIntegerGreaterThan(path, *value, 0) -} - -func ValidateIntegerGreaterThan(path PathBuilder, value uint32, minValue uint32) ValidationError { - var err ValidationError - if value <= minValue { - err.AddViolationAt(path, fmt.Sprintf("%s %d", HasToBeGreaterThan, minValue)) - } - - return err -} - -var BandwidthRegex = regexp.MustCompile(`(\d*)\s?([GMk]?bps)`) - -func ValidateBandwidth(path PathBuilder, value string) ValidationError { - var err ValidationError - if value == "" { - err.AddViolationAt(path, MustBeDefined) - return err - } - if matched := BandwidthRegex.MatchString(value); !matched { - err.AddViolationAt(path, MustHaveBPSUnit) - } - return err -} - -func ValidateNil[T any](path PathBuilder, t *T, msg string) ValidationError { - var err ValidationError - if t != nil { - err.AddViolationAt(path, msg) - } - return err -} - -func ValidatePort(path PathBuilder, value uint32) ValidationError { - var err ValidationError - if value == 0 || value > math.MaxUint16 { - err.AddViolationAt(path, "port must be a valid (1-65535)") - } - return err -}
diff --git a/pkg/common/validators/messages.go b/pkg/common/validators/messages.go deleted file mode 100644 index 79f1fc4..0000000 --- a/pkg/common/validators/messages.go +++ /dev/null
@@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 validators - -import ( - "fmt" - "strings" -) - -const ( - HasToBeGreaterThan = "must be greater than" - HasToBeLessThan = "must be less than" - HasToBeGreaterOrEqualThen = "must be greater or equal then" - HasToBeGreaterThanZero = "must be greater than 0" - MustNotBeEmpty = "must not be empty" - MustBeDefined = "must be defined" - MustBeSet = "must be set" - MustNotBeSet = "must not be set" - MustNotBeDefined = "must not be defined" - MustBeDefinedAndGreaterThanZero = "must be defined and greater than zero" - WhenDefinedHasToBeNonNegative = "must not be negative when defined" - WhenDefinedHasToBeGreaterThanZero = "must be greater than zero when defined" - HasToBeInRangeFormat = "must be in inclusive range [%v, %v]" - WhenDefinedHasToBeValidPath = "must be a valid path when defined" - StringHasToBeValidNumber = "string must be a valid number" - MustHaveBPSUnit = "must be in kbps/Mbps/Gbps units" -) - -var ( - HasToBeInPercentageRange = fmt.Sprintf(HasToBeInRangeFormat, "0.0", "100.0") - HasToBeInUintPercentageRange = fmt.Sprintf(HasToBeInRangeFormat, 0, 100) -) - -func MustHaveOnlyOne(entity string, allowedValues ...string) string { - return fmt.Sprintf(`%s must have only one type defined: %s`, entity, strings.Join(allowedValues, ", ")) -} - -func MustHaveExactlyOneOf(entity string, allowedValues ...string) string { - return fmt.Sprintf(`%s must have exactly one defined: %s`, entity, strings.Join(allowedValues, ", ")) -} - -func MustHaveAtLeastOne(allowedValues ...string) string { - return fmt.Sprintf(`must have at least one defined: %s`, strings.Join(allowedValues, ", ")) -}
diff --git a/pkg/common/validators/types.go b/pkg/common/validators/types.go deleted file mode 100644 index 9ca82ac..0000000 --- a/pkg/common/validators/types.go +++ /dev/null
@@ -1,214 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 validators - -import ( - "fmt" - "strings" -) - -type ValidationError struct { - Violations []Violation `json:"violations"` -} - -type Violation struct { - Field string `json:"field"` - Message string `json:"message"` -} - -// OK returns and empty validation error (i.e. success). -func OK() ValidationError { - return ValidationError{} -} - -func (v *ValidationError) Error() string { - msg := "" - for _, violation := range v.Violations { - if msg != "" { - msg = fmt.Sprintf("%s; %s: %s", msg, violation.Field, violation.Message) - } else { - msg += fmt.Sprintf("%s: %s", violation.Field, violation.Message) - } - } - return msg -} - -func (v *ValidationError) HasViolations() bool { - return len(v.Violations) > 0 -} - -func (v *ValidationError) OrNil() error { - if v.HasViolations() { - return v - } - return nil -} - -func (v *ValidationError) AddViolationAt(path PathBuilder, message string) { - v.AddViolation(path.String(), message) -} - -func (v *ValidationError) AddViolation(field string, message string) { - violation := Violation{ - Field: field, - Message: message, - } - v.Violations = append(v.Violations, violation) -} - -func (v *ValidationError) AddErrorAt(path PathBuilder, validationErr ValidationError) { - for _, violation := range validationErr.Violations { - field := Root() - if violation.Field != "" { - field = RootedAt(violation.Field) - } - newViolation := Violation{ - Field: path.concat(field).String(), - Message: violation.Message, - } - v.Violations = append(v.Violations, newViolation) - } -} - -func (v *ValidationError) Add(err ValidationError) { - v.AddErrorAt(Root(), err) -} - -func (v *ValidationError) AddError(rootField string, validationErr ValidationError) { - root := Root() - if rootField != "" { - root = RootedAt(rootField) - } - v.AddErrorAt(root, validationErr) -} - -// Transform returns a new ValidationError with every violation -// transformed by a given transformFunc. -func (v *ValidationError) Transform(transformFunc func(Violation) Violation) *ValidationError { - if v == nil { - return nil - } - if transformFunc == nil || len(v.Violations) == 0 { - rv := *v - return &rv - } - result := ValidationError{ - Violations: make([]Violation, len(v.Violations)), - } - for i := range v.Violations { - result.Violations[i] = transformFunc(v.Violations[i]) - } - return &result -} - -func MakeUnimplementedFieldErr(path PathBuilder) ValidationError { - var err ValidationError - err.AddViolationAt(path, "field is not implemented") - return err -} - -func MakeRequiredFieldErr(path PathBuilder) ValidationError { - var err ValidationError - err.AddViolationAt(path, "cannot be empty") - return err -} - -func MakeOneOfErr(fieldA, fieldB, msg string, oneOf []string) ValidationError { - var err ValidationError - var quoted []string - - for _, value := range oneOf { - quoted = append(quoted, fmt.Sprintf("%q", value)) - } - - message := fmt.Sprintf( - "%q %s one of [%s]", - fieldA, - msg, - strings.Join(quoted, ", "), - ) - - if fieldB != "" { - message = fmt.Sprintf( - "%q %s when %q is one of [%s]", - fieldA, - msg, - fieldB, - strings.Join(quoted, ", "), - ) - } - - err.AddViolationAt(Root(), message) - - return err -} - -func MakeFieldMustBeOneOfErr(field string, allowed ...string) ValidationError { - return MakeOneOfErr(field, "", "must be", allowed) -} - -func IsValidationError(err error) bool { - _, ok := err.(*ValidationError) - return ok -} - -type PathBuilder []string - -func RootedAt(name string) PathBuilder { - return PathBuilder{name} -} - -func Root() PathBuilder { - return PathBuilder{} -} - -func (p PathBuilder) Field(name string) PathBuilder { - element := name - if len(p) > 0 { - element = fmt.Sprintf(".%s", element) - } - return append(p, element) -} - -func (p PathBuilder) Index(index int) PathBuilder { - return append(p, fmt.Sprintf("[%d]", index)) -} - -func (p PathBuilder) Key(key string) PathBuilder { - return append(p, fmt.Sprintf("[%q]", key)) -} - -func (p PathBuilder) String() string { - return strings.Join(p, "") -} - -func (p PathBuilder) concat(other PathBuilder) PathBuilder { - if len(other) == 0 { - return p - } - if len(p) == 0 { - return other - } - - firstOther := other[0] - if !strings.HasPrefix(firstOther, "[") { - firstOther = "." + firstOther - } - - return append(append(p, firstOther), other[1:]...) -}
diff --git a/pkg/store/memory/store.go b/pkg/store/memory/store.go index fa0b3a6..28ce04d 100644 --- a/pkg/store/memory/store.go +++ b/pkg/store/memory/store.go
@@ -22,10 +22,10 @@ "sort" set "github.com/duke-git/lancet/v2/datastructure/set" + "github.com/duke-git/lancet/v2/slice" "k8s.io/client-go/tools/cache" "github.com/apache/dubbo-admin/pkg/common/bizerror" - "github.com/apache/dubbo-admin/pkg/common/util/slices" coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model" "github.com/apache/dubbo-admin/pkg/core/runtime" "github.com/apache/dubbo-admin/pkg/core/store" @@ -150,8 +150,8 @@ if err != nil { return nil, err } - resources = slices.SortBy(resources, func(r coremodel.Resource) string { - return r.ResourceKey() + slice.SortBy(resources, func(r1 coremodel.Resource, r2 coremodel.Resource) bool { + return r1.ResourceKey() < r2.ResourceKey() }) return resources, nil }