From b23f255b5975f7d469de3199a3e5abd0d06106a1 Mon Sep 17 00:00:00 2001 From: bufdev Date: Fri, 10 Nov 2023 16:54:40 -0500 Subject: [PATCH 1/4] Add slicesextended and syncextended --- private/pkg/slicesextended/slicesextended.go | 152 ++++++++++++++++++ .../pkg/slicesextended/slicesextended_test.go | 100 ++++++++++++ private/pkg/slicesextended/usage.gen.go | 19 +++ private/pkg/stringutil/stringutil.go | 72 +++------ private/pkg/stringutil/stringutil_test.go | 80 --------- private/pkg/syncextended/syncextended.go | 52 ++++++ private/pkg/syncextended/usage.gen.go | 19 +++ 7 files changed, 367 insertions(+), 127 deletions(-) create mode 100644 private/pkg/slicesextended/slicesextended.go create mode 100644 private/pkg/slicesextended/slicesextended_test.go create mode 100644 private/pkg/slicesextended/usage.gen.go create mode 100644 private/pkg/syncextended/syncextended.go create mode 100644 private/pkg/syncextended/usage.gen.go diff --git a/private/pkg/slicesextended/slicesextended.go b/private/pkg/slicesextended/slicesextended.go new file mode 100644 index 0000000000..aeace97182 --- /dev/null +++ b/private/pkg/slicesextended/slicesextended.go @@ -0,0 +1,152 @@ +// Copyright 2020-2023 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package slicesextended provides extra functionality on top of the slices package. +package slicesextended + +import ( + "cmp" + "slices" +) + +// Filter filters the slice to only the values where f returns true. +func Filter[T any](s []T, f func(T) bool) []T { + sf := make([]T, 0, len(s)) + for _, e := range s { + if f(e) { + sf = append(sf, e) + } + } + return sf +} + +// FilterError filters the slice to only the values where f returns true. +// +// Returns error the first time f returns error. +func FilterError[T any](s []T, f func(T) (bool, error)) ([]T, error) { + sf := make([]T, 0, len(s)) + for _, e := range s { + ok, err := f(e) + if err != nil { + return nil, err + } + if ok { + sf = append(sf, e) + } + } + return sf, nil +} + +// Map maps the slice. +func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 { + sm := make([]T2, len(s)) + for i, e := range s { + sm[i] = f(e) + } + return sm +} + +// MapError maps the slice. +// +// Returns error the first time f returns error. +func MapError[T1, T2 any](s []T1, f func(T1) (T2, error)) ([]T2, error) { + sm := make([]T2, len(s)) + for i, e := range s { + em, err := f(e) + if err != nil { + return nil, err + } + sm[i] = em + } + return sm, nil +} + +// ToMap converts the slice to a map. +func ToMap[T comparable](s []T) map[T]struct{} { + m := make(map[T]struct{}, len(s)) + for _, e := range s { + m[e] = struct{}{} + } + return m +} + +// MapToSortedSlice converts the map to a sorted slice. +func MapToSortedSlice[M ~map[T]struct{}, T cmp.Ordered](m M) []T { + s := MapToSlice(m) + slices.Sort(s) + return s +} + +// MapToSlice converts the map to a slice. +func MapToSlice[T comparable](m map[T]struct{}) []T { + s := make([]T, 0, len(m)) + for e := range m { + s = append(s, e) + } + return s +} + +// ToUniqueSorted returns a sorted copy of s with no duplicates. +func ToUniqueSorted[S ~[]T, T cmp.Ordered](s S) S { + return MapToSortedSlice(ToMap(s)) +} + +// ToChunks splits s into chunks of the given chunk size. +// +// If s is nil or empty, returns empty. +// If chunkSize is <=0, returns [][]T{s}. +func ToChunks[T any](s []T, chunkSize int) [][]T { + var chunks [][]T + if len(s) == 0 { + return chunks + } + if chunkSize <= 0 { + return [][]T{s} + } + c := make([]T, len(s)) + copy(c, s) + // https://github.com/golang/go/wiki/SliceTricks#batching-with-minimal-allocation + for chunkSize < len(c) { + c, chunks = c[chunkSize:], append(chunks, c[0:chunkSize:chunkSize]) + } + return append(chunks, c) +} + +// ElementsEqual returns true if the two slices have equal elements. +// +// Nil and empty slices are treated as equals. +func ElementsEqual[T comparable](one []T, two []T) bool { + if len(one) != len(two) { + return false + } + for i, elem := range one { + if two[i] != elem { + return false + } + } + return true +} + +// ElementsContained returns true if superset contains subset. +// +// Nil and empty slices are treated as equals. +func ElementsContained(superset []string, subset []string) bool { + m := ToMap(superset) + for _, elem := range subset { + if _, ok := m[elem]; !ok { + return false + } + } + return true +} diff --git a/private/pkg/slicesextended/slicesextended_test.go b/private/pkg/slicesextended/slicesextended_test.go new file mode 100644 index 0000000000..919935a6cc --- /dev/null +++ b/private/pkg/slicesextended/slicesextended_test.go @@ -0,0 +1,100 @@ +// Copyright 2020-2023 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package slicesextended + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestToUniqueSorted(t *testing.T) { + t.Parallel() + assert.Equal(t, []string{}, ToUniqueSorted([]string{})) + assert.Equal(t, []string{"Are", "bats", "cats"}, ToUniqueSorted([]string{"bats", "Are", "cats"})) + assert.Equal(t, []string{"Are", "are", "bats", "cats"}, ToUniqueSorted([]string{"bats", "Are", "cats", "are"})) + assert.Equal(t, []string{"Are", "Bats", "bats", "cats"}, ToUniqueSorted([]string{"bats", "Are", "cats", "Are", "Bats"})) + assert.Equal(t, []string{"", "Are", "Bats", "bats", "cats"}, ToUniqueSorted([]string{"bats", "Are", "cats", "", "Are", "Bats", ""})) + assert.Equal(t, []string{"", " ", "Are", "Bats", "bats", "cats"}, ToUniqueSorted([]string{"bats", "Are", "cats", "", "Are", "Bats", "", " "})) + assert.Equal(t, []string{""}, ToUniqueSorted([]string{"", ""})) + assert.Equal(t, []string{""}, ToUniqueSorted([]string{""})) +} + +func TestElementsContained(t *testing.T) { + t.Parallel() + assert.True(t, ElementsContained(nil, nil)) + assert.True(t, ElementsContained([]string{}, []string{})) + assert.True(t, ElementsContained(nil, []string{})) + assert.True(t, ElementsContained([]string{}, nil)) + assert.True(t, ElementsContained([]string{"one"}, []string{"one"})) + assert.True(t, ElementsContained([]string{"one", "two"}, []string{"one"})) + assert.True(t, ElementsContained([]string{"one", "two"}, []string{"two"})) + assert.True(t, ElementsContained([]string{"one", "two"}, []string{"one", "two"})) + assert.True(t, ElementsContained([]string{"one", "two"}, []string{"two", "one"})) + assert.False(t, ElementsContained([]string{"one", "two"}, []string{"three"})) + assert.False(t, ElementsContained([]string{}, []string{"three"})) + assert.False(t, ElementsContained([]string{"one"}, []string{"one", "two"})) + assert.False(t, ElementsContained([]string{"two"}, []string{"one", "two"})) +} + +func TestToChunks(t *testing.T) { + t.Parallel() + testToChunks( + t, + []string{"are"}, + 1, + []string{"are"}, + ) + testToChunks( + t, + []string{"are", "bats", "cats", "do", "eagle"}, + 1, + []string{"are"}, + []string{"bats"}, + []string{"cats"}, + []string{"do"}, + []string{"eagle"}, + ) + testToChunks( + t, + []string{"are", "bats", "cats", "do", "eagle"}, + 2, + []string{"are", "bats"}, + []string{"cats", "do"}, + []string{"eagle"}, + ) + testToChunks( + t, + []string{"are", "bats", "cats", "do", "eagle"}, + 3, + []string{"are", "bats", "cats"}, + []string{"do", "eagle"}, + ) + testToChunks( + t, + []string{"are", "bats", "cats", "do", "eagle"}, + 6, + []string{"are", "bats", "cats", "do", "eagle"}, + ) + testToChunks( + t, + nil, + 0, + ) +} + +func testToChunks(t *testing.T, input []string, chunkSize int, expected ...[]string) { + assert.Equal(t, expected, ToChunks(input, chunkSize)) +} diff --git a/private/pkg/slicesextended/usage.gen.go b/private/pkg/slicesextended/usage.gen.go new file mode 100644 index 0000000000..13ce387589 --- /dev/null +++ b/private/pkg/slicesextended/usage.gen.go @@ -0,0 +1,19 @@ +// Copyright 2020-2023 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Generated. DO NOT EDIT. + +package slicesextended + +import _ "github.com/bufbuild/buf/private/usage" diff --git a/private/pkg/stringutil/stringutil.go b/private/pkg/stringutil/stringutil.go index 160cf10249..cd6f0d6983 100644 --- a/private/pkg/stringutil/stringutil.go +++ b/private/pkg/stringutil/stringutil.go @@ -16,9 +16,10 @@ package stringutil import ( - "sort" "strings" "unicode" + + "github.com/bufbuild/buf/private/pkg/slicesextended" ) // TrimLines splits the output into individual lines and trims the spaces from each line. @@ -56,95 +57,72 @@ func SplitTrimLinesNoEmpty(output string) []string { } // MapToSortedSlice transforms m to a sorted slice. +// +// Deprecated: Use slicesextended.MapToSortedSlice instead. func MapToSortedSlice(m map[string]struct{}) []string { - s := MapToSlice(m) - sort.Strings(s) - return s + return slicesextended.MapToSortedSlice(m) } // MapToSlice transforms m to a slice. +// +// Deprecated: Use slicesextended.MapToSlice instead. func MapToSlice(m map[string]struct{}) []string { - s := make([]string, 0, len(m)) - for e := range m { - s = append(s, e) - } - return s + return slicesextended.MapToSlice(m) } // SliceToMap transforms s to a map. +// +// Deprecated: Use slicesextended.ToMap instead. func SliceToMap(s []string) map[string]struct{} { - m := make(map[string]struct{}, len(s)) - for _, e := range s { - m[e] = struct{}{} - } - return m + return slicesextended.ToMap(s) } // SliceToUniqueSortedSlice returns a sorted copy of s with no duplicates. +// +// Deprecated: Use slicesextended.ToUniqueSorted instead. func SliceToUniqueSortedSlice(s []string) []string { - return MapToSortedSlice(SliceToMap(s)) + return slicesextended.ToUniqueSorted(s) } // SliceToUniqueSortedSliceFilterEmptyStrings returns a sorted copy of s with no duplicates and no empty strings. // // Strings with only spaces are considered empty. func SliceToUniqueSortedSliceFilterEmptyStrings(s []string) []string { - m := SliceToMap(s) + m := slicesextended.ToMap(s) for key := range m { if strings.TrimSpace(key) == "" { delete(m, key) } } - return MapToSortedSlice(m) + return slicesextended.MapToSortedSlice(m) } // SliceToChunks splits s into chunks of the given chunk size. // // If s is nil or empty, returns empty. // If chunkSize is <=0, returns [][]string{s}. +// +// Deprecated: use slicesextended.ToChunks instead. func SliceToChunks(s []string, chunkSize int) [][]string { - var chunks [][]string - if len(s) == 0 { - return chunks - } - if chunkSize <= 0 { - return [][]string{s} - } - c := make([]string, len(s)) - copy(c, s) - // https://github.com/golang/go/wiki/SliceTricks#batching-with-minimal-allocation - for chunkSize < len(c) { - c, chunks = c[chunkSize:], append(chunks, c[0:chunkSize:chunkSize]) - } - return append(chunks, c) + return slicesextended.ToChunks(s, chunkSize) } // SliceElementsEqual returns true if the two slices have equal elements. // // Nil and empty slices are treated as equals. +// +// Deprecated: use slicesextended.ElementsEqual instead. func SliceElementsEqual(one []string, two []string) bool { - if len(one) != len(two) { - return false - } - for i, elem := range one { - if two[i] != elem { - return false - } - } - return true + return slicesextended.ElementsEqual(one, two) } // SliceElementsContained returns true if superset contains subset. // // Nil and empty slices are treated as equals. +// +// Deprecated: use slicesextended.ElementsContained instead. func SliceElementsContained(superset []string, subset []string) bool { - m := SliceToMap(superset) - for _, elem := range subset { - if _, ok := m[elem]; !ok { - return false - } - } - return true + return slicesextended.ElementsContained(superset, subset) } // JoinSliceQuoted joins the slice with quotes. diff --git a/private/pkg/stringutil/stringutil_test.go b/private/pkg/stringutil/stringutil_test.go index 447ef80856..0c803c692a 100644 --- a/private/pkg/stringutil/stringutil_test.go +++ b/private/pkg/stringutil/stringutil_test.go @@ -222,19 +222,6 @@ func TestSliceToHumanStringOrQuoted(t *testing.T) { assert.Equal(t, `"a", "b", or "c"`, SliceToHumanStringOrQuoted([]string{"a", "b", "c"})) } -func TestSliceToUniqueSortedSlice(t *testing.T) { - t.Parallel() - assert.Equal(t, []string{}, SliceToUniqueSortedSlice(nil)) - assert.Equal(t, []string{}, SliceToUniqueSortedSlice([]string{})) - assert.Equal(t, []string{"Are", "bats", "cats"}, SliceToUniqueSortedSlice([]string{"bats", "Are", "cats"})) - assert.Equal(t, []string{"Are", "are", "bats", "cats"}, SliceToUniqueSortedSlice([]string{"bats", "Are", "cats", "are"})) - assert.Equal(t, []string{"Are", "Bats", "bats", "cats"}, SliceToUniqueSortedSlice([]string{"bats", "Are", "cats", "Are", "Bats"})) - assert.Equal(t, []string{"", "Are", "Bats", "bats", "cats"}, SliceToUniqueSortedSlice([]string{"bats", "Are", "cats", "", "Are", "Bats", ""})) - assert.Equal(t, []string{"", " ", "Are", "Bats", "bats", "cats"}, SliceToUniqueSortedSlice([]string{"bats", "Are", "cats", "", "Are", "Bats", "", " "})) - assert.Equal(t, []string{""}, SliceToUniqueSortedSlice([]string{"", ""})) - assert.Equal(t, []string{""}, SliceToUniqueSortedSlice([]string{""})) -} - func TestSliceToUniqueSortedSliceFilterEmptyStrings(t *testing.T) { t.Parallel() assert.Equal(t, []string{}, SliceToUniqueSortedSliceFilterEmptyStrings(nil)) @@ -247,73 +234,6 @@ func TestSliceToUniqueSortedSliceFilterEmptyStrings(t *testing.T) { assert.Equal(t, []string{}, SliceToUniqueSortedSliceFilterEmptyStrings([]string{""})) } -func TestSliceElementsContained(t *testing.T) { - t.Parallel() - assert.True(t, SliceElementsContained(nil, nil)) - assert.True(t, SliceElementsContained([]string{}, []string{})) - assert.True(t, SliceElementsContained(nil, []string{})) - assert.True(t, SliceElementsContained([]string{}, nil)) - assert.True(t, SliceElementsContained([]string{"one"}, []string{"one"})) - assert.True(t, SliceElementsContained([]string{"one", "two"}, []string{"one"})) - assert.True(t, SliceElementsContained([]string{"one", "two"}, []string{"two"})) - assert.True(t, SliceElementsContained([]string{"one", "two"}, []string{"one", "two"})) - assert.True(t, SliceElementsContained([]string{"one", "two"}, []string{"two", "one"})) - assert.False(t, SliceElementsContained([]string{"one", "two"}, []string{"three"})) - assert.False(t, SliceElementsContained([]string{}, []string{"three"})) - assert.False(t, SliceElementsContained([]string{"one"}, []string{"one", "two"})) - assert.False(t, SliceElementsContained([]string{"two"}, []string{"one", "two"})) -} - -func TestSliceToChunks(t *testing.T) { - t.Parallel() - testSliceToChunks( - t, - []string{"are"}, - 1, - []string{"are"}, - ) - testSliceToChunks( - t, - []string{"are", "bats", "cats", "do", "eagle"}, - 1, - []string{"are"}, - []string{"bats"}, - []string{"cats"}, - []string{"do"}, - []string{"eagle"}, - ) - testSliceToChunks( - t, - []string{"are", "bats", "cats", "do", "eagle"}, - 2, - []string{"are", "bats"}, - []string{"cats", "do"}, - []string{"eagle"}, - ) - testSliceToChunks( - t, - []string{"are", "bats", "cats", "do", "eagle"}, - 3, - []string{"are", "bats", "cats"}, - []string{"do", "eagle"}, - ) - testSliceToChunks( - t, - []string{"are", "bats", "cats", "do", "eagle"}, - 6, - []string{"are", "bats", "cats", "do", "eagle"}, - ) - testSliceToChunks( - t, - nil, - 0, - ) -} - -func testSliceToChunks(t *testing.T, input []string, chunkSize int, expected ...[]string) { - assert.Equal(t, expected, SliceToChunks(input, chunkSize)) -} - func TestAlphanumeric(t *testing.T) { t.Parallel() assert.True(t, IsAlphanumeric('0')) diff --git a/private/pkg/syncextended/syncextended.go b/private/pkg/syncextended/syncextended.go new file mode 100644 index 0000000000..7471329a22 --- /dev/null +++ b/private/pkg/syncextended/syncextended.go @@ -0,0 +1,52 @@ +// Copyright 2020-2023 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package syncextended provides extra functionality on top of the sync package. +package syncextended + +import "sync" + +// OnceValues3 returns a function that invokes f only once and returns the values +// returned by f. The returned function may be called concurrently. +// +// If f panics, the returned function will panic with the same value on every call. +// +// This is copied from sync.OnceValues and extended to for three values. +func OnceValues3[T1, T2, T3 any](f func() (T1, T2, T3)) func() (T1, T2, T3) { + var ( + once sync.Once + valid bool + p any + r1 T1 + r2 T2 + r3 T3 + ) + g := func() { + defer func() { + p = recover() + if !valid { + panic(p) + } + }() + r1, r2, r3 = f() + valid = true + } + return func() (T1, T2, T3) { + once.Do(g) + if !valid { + panic(p) + } + return r1, r2, r3 + } +} diff --git a/private/pkg/syncextended/usage.gen.go b/private/pkg/syncextended/usage.gen.go new file mode 100644 index 0000000000..78a0abf50a --- /dev/null +++ b/private/pkg/syncextended/usage.gen.go @@ -0,0 +1,19 @@ +// Copyright 2020-2023 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Generated. DO NOT EDIT. + +package syncextended + +import _ "github.com/bufbuild/buf/private/usage" From 8edb67c3c91118f8be67fbbe06027acd89cf3990 Mon Sep 17 00:00:00 2001 From: bufdev Date: Fri, 10 Nov 2023 17:00:07 -0500 Subject: [PATCH 2/4] Updates --- private/buf/bufsync/syncer.go | 4 ++-- private/buf/bufwire/module_config_reader.go | 6 +++--- private/buf/bufwork/config.go | 4 ++-- .../cmd/buf/command/beta/studioagent/studioagent.go | 4 ++-- private/buf/cmd/buf/command/breaking/breaking.go | 3 ++- .../internal/bufbreakingcheck/bufbreakingcheck.go | 3 ++- .../buflint/internal/buflintcheck/buflintcheck.go | 11 ++++++----- private/bufpkg/bufcheck/internal/version_spec.go | 8 ++++---- private/bufpkg/bufimage/util.go | 6 +++--- private/bufpkg/bufmodule/bufmoduleconfig/config.go | 3 ++- private/bufpkg/bufmodule/targeting_module.go | 6 +++--- private/pkg/bandeps/state.go | 6 +++--- private/pkg/git/lister.go | 5 +++-- private/pkg/normalpath/normalpath.go | 4 ++-- private/pkg/normalpath/normalpath_unix_test.go | 10 +++++----- private/pkg/normalpath/normalpath_windows_test.go | 10 +++++----- private/pkg/storage/storagetesting/storagetesting.go | 6 +++--- 17 files changed, 52 insertions(+), 47 deletions(-) diff --git a/private/buf/bufsync/syncer.go b/private/buf/bufsync/syncer.go index 9c71e062e9..5ba942dd2a 100644 --- a/private/buf/bufsync/syncer.go +++ b/private/buf/bufsync/syncer.go @@ -26,9 +26,9 @@ import ( "github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmodulebuild" "github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref" "github.com/bufbuild/buf/private/pkg/git" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/storage" "github.com/bufbuild/buf/private/pkg/storage/storagegit" - "github.com/bufbuild/buf/private/pkg/stringutil" "go.uber.org/multierr" "go.uber.org/zap" ) @@ -181,7 +181,7 @@ func (s *syncer) prepareSync(ctx context.Context) error { var branchesToSync []string if s.syncAllBranches { // sync all branches - branchesToSync = stringutil.MapToSlice(allBranches) + branchesToSync = slicesextended.MapToSlice(allBranches) } else { // sync current branch, make sure it's present currentBranch, err := s.repo.CurrentBranch(ctx) diff --git a/private/buf/bufwire/module_config_reader.go b/private/buf/bufwire/module_config_reader.go index 37d7182660..11761cac8e 100644 --- a/private/buf/bufwire/module_config_reader.go +++ b/private/buf/bufwire/module_config_reader.go @@ -29,9 +29,9 @@ import ( "github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref" "github.com/bufbuild/buf/private/pkg/app" "github.com/bufbuild/buf/private/pkg/normalpath" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/storage" "github.com/bufbuild/buf/private/pkg/storage/storageos" - "github.com/bufbuild/buf/private/pkg/stringutil" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" @@ -268,8 +268,8 @@ func (m *moduleConfigReader) getProtoFileModuleSourceConfigSet( if err != nil { return nil, err } - workspaceConfigs := stringutil.SliceToMap(bufwork.AllConfigFilePaths) - moduleConfigs := stringutil.SliceToMap(bufconfig.AllConfigFilePaths) + workspaceConfigs := slicesextended.ToMap(bufwork.AllConfigFilePaths) + moduleConfigs := slicesextended.ToMap(bufconfig.AllConfigFilePaths) terminateFileProvider := readBucketCloser.TerminateFileProvider() var workspaceConfigDirectory string var moduleConfigDirectory string diff --git a/private/buf/bufwork/config.go b/private/buf/bufwork/config.go index 6a82653e1c..a1a0428631 100644 --- a/private/buf/bufwork/config.go +++ b/private/buf/bufwork/config.go @@ -19,7 +19,7 @@ import ( "sort" "github.com/bufbuild/buf/private/pkg/normalpath" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" ) func newConfigV1(externalConfig ExternalConfigV1, workspaceID string) (*Config, error) { @@ -49,7 +49,7 @@ func newConfigV1(externalConfig ExternalConfigV1, workspaceID string) (*Config, } // It's very important that we sort the directories here so that the // constructed modules and/or images are in a deterministic order. - directories := stringutil.MapToSlice(directorySet) + directories := slicesextended.MapToSlice(directorySet) sort.Slice(directories, func(i int, j int) bool { return directories[i] < directories[j] }) diff --git a/private/buf/cmd/buf/command/beta/studioagent/studioagent.go b/private/buf/cmd/buf/command/beta/studioagent/studioagent.go index 5fd7908a99..04100d2098 100644 --- a/private/buf/cmd/buf/command/beta/studioagent/studioagent.go +++ b/private/buf/cmd/buf/command/beta/studioagent/studioagent.go @@ -25,7 +25,7 @@ import ( "github.com/bufbuild/buf/private/pkg/app/appcmd" "github.com/bufbuild/buf/private/pkg/app/appflag" "github.com/bufbuild/buf/private/pkg/cert/certclient" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/transport/http/httpserver" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -186,7 +186,7 @@ func run( container.Logger(), flags.Origin, clientTLSConfig, - stringutil.SliceToMap(flags.DisallowedHeaders), + slicesextended.ToMap(flags.DisallowedHeaders), flags.ForwardHeaders, flags.PrivateNetwork, ) diff --git a/private/buf/cmd/buf/command/breaking/breaking.go b/private/buf/cmd/buf/command/breaking/breaking.go index b4d2b44e37..ecbff98966 100644 --- a/private/buf/cmd/buf/command/breaking/breaking.go +++ b/private/buf/cmd/buf/command/breaking/breaking.go @@ -28,6 +28,7 @@ import ( "github.com/bufbuild/buf/private/pkg/app/appcmd" "github.com/bufbuild/buf/private/pkg/app/appflag" "github.com/bufbuild/buf/private/pkg/command" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/stringutil" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -304,5 +305,5 @@ func getExternalPathsForImages(imageConfigs []bufwire.ImageConfig, excludeImport externalPaths[imageFile.ExternalPath()] = struct{}{} } } - return stringutil.MapToSlice(externalPaths), nil + return slicesextended.MapToSlice(externalPaths), nil } diff --git a/private/bufpkg/bufcheck/bufbreaking/internal/bufbreakingcheck/bufbreakingcheck.go b/private/bufpkg/bufcheck/bufbreaking/internal/bufbreakingcheck/bufbreakingcheck.go index f4d2a2bab2..29da0da959 100644 --- a/private/bufpkg/bufcheck/bufbreaking/internal/bufbreakingcheck/bufbreakingcheck.go +++ b/private/bufpkg/bufcheck/bufbreaking/internal/bufbreakingcheck/bufbreakingcheck.go @@ -25,6 +25,7 @@ import ( "github.com/bufbuild/buf/private/pkg/protodescriptor" "github.com/bufbuild/buf/private/pkg/protosource" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/stringutil" "google.golang.org/protobuf/types/descriptorpb" ) @@ -134,7 +135,7 @@ func checkEnumValueSameName(add addFunc, corpus *corpus, previousNameToEnumValue // ie if you now have FOO=2, BAR=2, you need to have had FOO=2, BAR=2 previously // FOO=2, BAR=2, BAZ=2 now would pass // FOO=2, BAR=2, BAZ=2 previously would fail - if !stringutil.SliceElementsContained(names, previousNames) { + if !slicesextended.ElementsContained(names, previousNames) { previousNamesString := stringutil.JoinSliceQuoted(previousNames, ", ") namesString := stringutil.JoinSliceQuoted(names, ", ") nameSuffix := "" diff --git a/private/bufpkg/bufcheck/buflint/internal/buflintcheck/buflintcheck.go b/private/bufpkg/bufcheck/buflint/internal/buflintcheck/buflintcheck.go index 3d97ecdea1..9704a86721 100644 --- a/private/bufpkg/bufcheck/buflint/internal/buflintcheck/buflintcheck.go +++ b/private/bufpkg/bufcheck/buflint/internal/buflintcheck/buflintcheck.go @@ -29,6 +29,7 @@ import ( "github.com/bufbuild/buf/private/pkg/normalpath" "github.com/bufbuild/buf/private/pkg/protosource" "github.com/bufbuild/buf/private/pkg/protoversion" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/stringutil" ) @@ -116,13 +117,13 @@ func checkDirectorySamePackage(add addFunc, dirPath string, files []protosource. if _, ok := pkgMap[""]; ok { delete(pkgMap, "") if len(pkgMap) > 1 { - messagePrefix = fmt.Sprintf("Multiple packages %q and file with no package", strings.Join(stringutil.MapToSortedSlice(pkgMap), ",")) + messagePrefix = fmt.Sprintf("Multiple packages %q and file with no package", strings.Join(slicesextended.MapToSortedSlice(pkgMap), ",")) } else { // Join works with only one element as well by adding no comma - messagePrefix = fmt.Sprintf("Package %q and file with no package", strings.Join(stringutil.MapToSortedSlice(pkgMap), ",")) + messagePrefix = fmt.Sprintf("Package %q and file with no package", strings.Join(slicesextended.MapToSortedSlice(pkgMap), ",")) } } else { - messagePrefix = fmt.Sprintf("Multiple packages %q", strings.Join(stringutil.MapToSortedSlice(pkgMap), ",")) + messagePrefix = fmt.Sprintf("Multiple packages %q", strings.Join(slicesextended.MapToSortedSlice(pkgMap), ",")) } for _, file := range files { add(file, file.PackageLocation(), nil, "%s detected within directory %q.", messagePrefix, dirPath) @@ -525,7 +526,7 @@ func checkPackageSameDirectory(add addFunc, pkg string, files []protosource.File dirMap[normalpath.Dir(file.Path())] = struct{}{} } if len(dirMap) > 1 { - dirs := stringutil.MapToSortedSlice(dirMap) + dirs := slicesextended.MapToSortedSlice(dirMap) for _, file := range files { add(file, file.PackageLocation(), nil, "Multiple directories %q contain files with package %q.", strings.Join(dirs, ","), pkg) } @@ -602,7 +603,7 @@ func checkPackageSameOptionValue( if len(optionValueMap) > 1 { _, noOptionValue := optionValueMap[""] delete(optionValueMap, "") - optionValues := stringutil.MapToSortedSlice(optionValueMap) + optionValues := slicesextended.MapToSortedSlice(optionValueMap) for _, file := range files { if noOptionValue { add(file, getOptionLocation(file), nil, "Files in package %q have both values %q and no value for option %q and all values must be equal.", pkg, strings.Join(optionValues, ","), name) diff --git a/private/bufpkg/bufcheck/internal/version_spec.go b/private/bufpkg/bufcheck/internal/version_spec.go index d865ca4b46..00221e1176 100644 --- a/private/bufpkg/bufcheck/internal/version_spec.go +++ b/private/bufpkg/bufcheck/internal/version_spec.go @@ -17,7 +17,7 @@ package internal import ( "sort" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" ) // VersionSpec specifies the rules, ids, and categories for a given version. @@ -39,7 +39,7 @@ func AllCategoriesForVersionSpec(versionSpec *VersionSpec) []string { categoriesMap[category] = struct{}{} } } - categories := stringutil.MapToSlice(categoriesMap) + categories := slicesextended.MapToSlice(categoriesMap) sort.Slice( categories, func(i int, j int) bool { @@ -57,7 +57,7 @@ func AllIDsForVersionSpec(versionSpec *VersionSpec) []string { for id := range versionSpec.IDToCategories { m[id] = struct{}{} } - return stringutil.MapToSortedSlice(m) + return slicesextended.MapToSortedSlice(m) } // AllCategoriesAndIDsForVersionSpec returns all categories and rules for the VersionSpec. @@ -71,5 +71,5 @@ func AllCategoriesAndIDsForVersionSpec(versionSpec *VersionSpec) []string { m[category] = struct{}{} } } - return stringutil.MapToSortedSlice(m) + return slicesextended.MapToSortedSlice(m) } diff --git a/private/bufpkg/bufimage/util.go b/private/bufpkg/bufimage/util.go index 5603357312..cbdada50a2 100644 --- a/private/bufpkg/bufimage/util.go +++ b/private/bufpkg/bufimage/util.go @@ -24,7 +24,7 @@ import ( imagev1 "github.com/bufbuild/buf/private/gen/proto/go/buf/alpha/image/v1" "github.com/bufbuild/buf/private/pkg/normalpath" "github.com/bufbuild/buf/private/pkg/protodescriptor" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" "google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" @@ -45,7 +45,7 @@ func imageWithOnlyPaths(image Image, fileOrDirPaths []string, excludeFileOrDirPa if err := normalpath.ValidatePathsNormalizedValidatedUnique(excludeFileOrDirPaths); err != nil { return nil, err } - excludeFileOrDirPathMap := stringutil.SliceToMap(excludeFileOrDirPaths) + excludeFileOrDirPathMap := slicesextended.ToMap(excludeFileOrDirPaths) // These are the files that fileOrDirPaths actually reference and will // result in the non-imports in our resulting Image. The Image will also include // the ImageFiles that the nonImportImageFiles import @@ -133,7 +133,7 @@ func imageWithOnlyPaths(image Image, fileOrDirPaths []string, excludeFileOrDirPa // make a map of the directory paths // note that we do not make this a map to begin with as maps are unordered, // and we want to make sure we iterate over the paths in a deterministic order - potentialDirPathMap := stringutil.SliceToMap(potentialDirPaths) + potentialDirPathMap := slicesextended.ToMap(potentialDirPaths) // map of all paths based on the imageFiles // the map of paths within potentialDirPath that matches a file in image.Files() diff --git a/private/bufpkg/bufmodule/bufmoduleconfig/config.go b/private/bufpkg/bufmodule/bufmoduleconfig/config.go index 501f08b305..b970948522 100644 --- a/private/bufpkg/bufmodule/bufmoduleconfig/config.go +++ b/private/bufpkg/bufmodule/bufmoduleconfig/config.go @@ -21,6 +21,7 @@ import ( "github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref" "github.com/bufbuild/buf/private/bufpkg/bufmodule/internal" "github.com/bufbuild/buf/private/pkg/normalpath" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/stringutil" ) @@ -75,7 +76,7 @@ func newConfigV1Beta1(externalConfig ExternalConfigV1Beta1, deps ...string) (*Co } // verify that all excludes are within a root - rootMap := stringutil.SliceToMap(roots) + rootMap := slicesextended.ToMap(roots) for _, fullExclude := range fullExcludes { switch matchingRoots := normalpath.MapAllEqualOrContainingPaths(rootMap, fullExclude, normalpath.Relative); len(matchingRoots) { case 0: diff --git a/private/bufpkg/bufmodule/targeting_module.go b/private/bufpkg/bufmodule/targeting_module.go index f6e389a383..5d9f0eec7b 100644 --- a/private/bufpkg/bufmodule/targeting_module.go +++ b/private/bufpkg/bufmodule/targeting_module.go @@ -22,8 +22,8 @@ import ( "github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref" "github.com/bufbuild/buf/private/pkg/normalpath" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/storage" - "github.com/bufbuild/buf/private/pkg/stringutil" ) type targetingModule struct { @@ -56,7 +56,7 @@ func (m *targetingModule) TargetFileInfos(ctx context.Context) (fileInfos []bufm bufmoduleref.SortFileInfos(fileInfos) } }() - excludePathMap := stringutil.SliceToMap(m.excludePaths) + excludePathMap := slicesextended.ToMap(m.excludePaths) // We start by ensuring that no paths have been duplicated between target and exclude pathes. for _, targetPath := range m.targetPaths { if _, ok := excludePathMap[targetPath]; ok { @@ -150,7 +150,7 @@ func (m *targetingModule) TargetFileInfos(ctx context.Context) (fileInfos []bufm } // We have potential directory paths, do the expensive operation to // make a map of the directory paths. - potentialDirPathMap := stringutil.SliceToMap(potentialDirPaths) + potentialDirPathMap := slicesextended.ToMap(potentialDirPaths) // The map of paths within potentialDirPath that matches a file. // This needs to contain all paths in potentialDirPathMap at the end for us to // have had matches for every targetPath input. diff --git a/private/pkg/bandeps/state.go b/private/pkg/bandeps/state.go index 1c8bcda738..0606ab0fe9 100644 --- a/private/pkg/bandeps/state.go +++ b/private/pkg/bandeps/state.go @@ -20,7 +20,7 @@ import ( "github.com/bufbuild/buf/private/pkg/app" "github.com/bufbuild/buf/private/pkg/command" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" @@ -172,7 +172,7 @@ func (s *state) packagesForPackageExpressionUncached( span.SetStatus(codes.Error, err.Error()) return nil, err } - return stringutil.SliceToMap(getNonEmptyLines(string(data))), nil + return slicesextended.ToMap(getNonEmptyLines(string(data))), nil } func (s *state) depsForPackage( @@ -234,7 +234,7 @@ func (s *state) depsForPackageUncached( span.SetStatus(codes.Error, err.Error()) return nil, err } - return stringutil.SliceToMap(getNonEmptyLines(string(data))), nil + return slicesextended.ToMap(getNonEmptyLines(string(data))), nil } type packagesResult struct { diff --git a/private/pkg/git/lister.go b/private/pkg/git/lister.go index bdcc02d82a..2103d643a4 100644 --- a/private/pkg/git/lister.go +++ b/private/pkg/git/lister.go @@ -21,6 +21,7 @@ import ( "github.com/bufbuild/buf/private/pkg/app" "github.com/bufbuild/buf/private/pkg/command" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/stringutil" ) @@ -64,7 +65,7 @@ func (l *lister) ListFilesAndUnstagedFiles( if err != nil { return nil, err } - return stringutil.SliceToUniqueSortedSlice( + return slicesextended.ToUniqueSorted( filterNonRegularFiles( stringSliceExceptMatches( stringSliceExcept( @@ -81,7 +82,7 @@ func (l *lister) ListFilesAndUnstagedFiles( // stringSliceExcept returns all elements in source that are not in except. func stringSliceExcept(source []string, except []string) []string { - exceptMap := stringutil.SliceToMap(except) + exceptMap := slicesextended.ToMap(except) result := make([]string, 0, len(source)) for _, s := range source { if _, ok := exceptMap[s]; !ok { diff --git a/private/pkg/normalpath/normalpath.go b/private/pkg/normalpath/normalpath.go index b763a34f7f..432c8d4b34 100644 --- a/private/pkg/normalpath/normalpath.go +++ b/private/pkg/normalpath/normalpath.go @@ -27,7 +27,7 @@ import ( "sort" "strings" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" ) const ( @@ -297,7 +297,7 @@ func MapAllEqualOrContainingPaths(m map[string]struct{}, path string, pathType P if len(m) == 0 { return nil } - return stringutil.MapToSortedSlice(MapAllEqualOrContainingPathMap(m, path, pathType)) + return slicesextended.MapToSortedSlice(MapAllEqualOrContainingPathMap(m, path, pathType)) } // StripComponents strips the specified number of components. diff --git a/private/pkg/normalpath/normalpath_unix_test.go b/private/pkg/normalpath/normalpath_unix_test.go index 7144f4dcfe..7c174c0b90 100644 --- a/private/pkg/normalpath/normalpath_unix_test.go +++ b/private/pkg/normalpath/normalpath_unix_test.go @@ -24,7 +24,7 @@ import ( "sort" "testing" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/stretchr/testify/assert" ) @@ -342,7 +342,7 @@ func TestMapHasEqualOrContainingPath(t *testing.T) { } func testMapHasEqualOrContainingPath(t *testing.T, expected bool, path string, keys ...string) { - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapHasEqualOrContainingPath(keyMap, path, Relative), fmt.Sprintf("%s %v", path, keys)) } @@ -367,7 +367,7 @@ func testMapAllEqualOrContainingPaths(t *testing.T, expected []string, path stri expected = make([]string, 0) } sort.Strings(expected) - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapAllEqualOrContainingPaths(keyMap, path, Relative), fmt.Sprintf("%s %v", path, keys)) } @@ -424,7 +424,7 @@ func TestMapHasEqualOrContainingPathAbs(t *testing.T) { } func testMapHasEqualOrContainingPathAbs(t *testing.T, expected bool, path string, keys ...string) { - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapHasEqualOrContainingPath(keyMap, path, Absolute), fmt.Sprintf("%s %v", path, keys)) } @@ -449,6 +449,6 @@ func testMapAllEqualOrContainingPathsAbs(t *testing.T, expected []string, path s expected = make([]string, 0) } sort.Strings(expected) - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapAllEqualOrContainingPaths(keyMap, path, Absolute), fmt.Sprintf("%s %v", path, keys)) } diff --git a/private/pkg/normalpath/normalpath_windows_test.go b/private/pkg/normalpath/normalpath_windows_test.go index 5d98e57d2c..0daaf2e603 100644 --- a/private/pkg/normalpath/normalpath_windows_test.go +++ b/private/pkg/normalpath/normalpath_windows_test.go @@ -24,7 +24,7 @@ import ( "sort" "testing" - "github.com/bufbuild/buf/private/pkg/stringutil" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/stretchr/testify/assert" ) @@ -362,7 +362,7 @@ func TestMapHasEqualOrContainingPath(t *testing.T) { } func testMapHasEqualOrContainingPath(t *testing.T, expected bool, path string, keys ...string) { - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapHasEqualOrContainingPath(keyMap, path, Relative), fmt.Sprintf("%s %v", path, keys)) } @@ -386,7 +386,7 @@ func testMapAllEqualOrContainingPaths(t *testing.T, expected []string, path stri expected = make([]string, 0) } sort.Strings(expected) - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapAllEqualOrContainingPaths(keyMap, path, Relative), fmt.Sprintf("%s %v", path, keys)) } @@ -497,7 +497,7 @@ func TestMapHasEqualOrContainingPathAbs(t *testing.T) { } func testMapHasEqualOrContainingPathAbs(t *testing.T, expected bool, path string, keys ...string) { - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapHasEqualOrContainingPath(keyMap, path, Absolute), fmt.Sprintf("%s %v", path, keys)) } @@ -527,6 +527,6 @@ func testMapAllEqualOrContainingPathsAbs(t *testing.T, expected []string, path s expected = make([]string, 0) } sort.Strings(expected) - keyMap := stringutil.SliceToMap(keys) + keyMap := slicesextended.ToMap(keys) assert.Equal(t, expected, MapAllEqualOrContainingPaths(keyMap, path, Absolute), fmt.Sprintf("%s %v", path, keys)) } diff --git a/private/pkg/storage/storagetesting/storagetesting.go b/private/pkg/storage/storagetesting/storagetesting.go index 3864144b00..b6d48a80ed 100644 --- a/private/pkg/storage/storagetesting/storagetesting.go +++ b/private/pkg/storage/storagetesting/storagetesting.go @@ -31,11 +31,11 @@ import ( "testing" "github.com/bufbuild/buf/private/pkg/command" + "github.com/bufbuild/buf/private/pkg/slicesextended" "github.com/bufbuild/buf/private/pkg/storage" "github.com/bufbuild/buf/private/pkg/storage/storagearchive" "github.com/bufbuild/buf/private/pkg/storage/storageos" "github.com/bufbuild/buf/private/pkg/storage/storageutil" - "github.com/bufbuild/buf/private/pkg/stringutil" "github.com/bufbuild/buf/private/pkg/tmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -111,7 +111,7 @@ func AssertPathToContent( return nil }, )) - require.Equal(t, len(paths), len(stringutil.SliceToUniqueSortedSlice(paths))) + require.Equal(t, len(paths), len(slicesextended.ToUniqueSorted(paths))) assert.Equal(t, len(expectedPathToContent), len(paths), paths) for _, path := range paths { expectedContent, ok := expectedPathToContent[path] @@ -144,7 +144,7 @@ func AssertPaths( }, )) sort.Strings(paths) - assert.Equal(t, stringutil.SliceToUniqueSortedSlice(expectedPaths), paths) + assert.Equal(t, slicesextended.ToUniqueSorted(expectedPaths), paths) } // GetExternalPathFunc can be used to get the external path of From 7a80621b550bf8cf0ea013c0e1e13e8baf9d9ed6 Mon Sep 17 00:00:00 2001 From: bufdev Date: Fri, 10 Nov 2023 17:06:37 -0500 Subject: [PATCH 3/4] Fix for Golang 1.20 --- private/pkg/slicesextended/slicesextended.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/private/pkg/slicesextended/slicesextended.go b/private/pkg/slicesextended/slicesextended.go index aeace97182..94430c38b8 100644 --- a/private/pkg/slicesextended/slicesextended.go +++ b/private/pkg/slicesextended/slicesextended.go @@ -16,10 +16,19 @@ package slicesextended import ( - "cmp" "slices" ) +// Ordered matches cmp.Ordered until we only support Go versions >= 1.21. +// +// TODO: remove and replace with cmp.Ordered when we only support Go versions >= 1.21. +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + // Filter filters the slice to only the values where f returns true. func Filter[T any](s []T, f func(T) bool) []T { sf := make([]T, 0, len(s)) @@ -82,7 +91,7 @@ func ToMap[T comparable](s []T) map[T]struct{} { } // MapToSortedSlice converts the map to a sorted slice. -func MapToSortedSlice[M ~map[T]struct{}, T cmp.Ordered](m M) []T { +func MapToSortedSlice[M ~map[T]struct{}, T Ordered](m M) []T { s := MapToSlice(m) slices.Sort(s) return s @@ -98,7 +107,7 @@ func MapToSlice[T comparable](m map[T]struct{}) []T { } // ToUniqueSorted returns a sorted copy of s with no duplicates. -func ToUniqueSorted[S ~[]T, T cmp.Ordered](s S) S { +func ToUniqueSorted[S ~[]T, T Ordered](s S) S { return MapToSortedSlice(ToMap(s)) } From 13556d381c3feb78264cea1ac214044adcd3eb7a Mon Sep 17 00:00:00 2001 From: bufdev Date: Fri, 10 Nov 2023 17:08:45 -0500 Subject: [PATCH 4/4] fix --- private/pkg/slicesextended/slicesextended.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/private/pkg/slicesextended/slicesextended.go b/private/pkg/slicesextended/slicesextended.go index 94430c38b8..d8ebb39881 100644 --- a/private/pkg/slicesextended/slicesextended.go +++ b/private/pkg/slicesextended/slicesextended.go @@ -15,9 +15,7 @@ // Package slicesextended provides extra functionality on top of the slices package. package slicesextended -import ( - "slices" -) +import "sort" // Ordered matches cmp.Ordered until we only support Go versions >= 1.21. // @@ -93,7 +91,13 @@ func ToMap[T comparable](s []T) map[T]struct{} { // MapToSortedSlice converts the map to a sorted slice. func MapToSortedSlice[M ~map[T]struct{}, T Ordered](m M) []T { s := MapToSlice(m) - slices.Sort(s) + // TODO: Replace with slices.Sort when we only support Go versions >= 1.21. + sort.Slice( + s, + func(i int, j int) bool { + return s[i] < s[j] + }, + ) return s }