1
0
Fork 0
mirror of https://github.com/restic/restic.git synced 2025-03-30 00:00:14 +01:00

Merge pull request #5292 from restic/go-1.23

Add Go 1.24 and drop Go 1.22 support
This commit is contained in:
Michael Eischer 2025-03-23 17:26:31 +01:00 committed by GitHub
commit 89909d41aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 154 additions and 139 deletions

View file

@ -13,7 +13,7 @@ permissions:
contents: read
env:
latest_go: "1.23.x"
latest_go: "1.24.x"
GO111MODULE: on
jobs:
@ -23,29 +23,29 @@ jobs:
# list of jobs to run:
include:
- job_name: Windows
go: 1.23.x
go: 1.24.x
os: windows-latest
- job_name: macOS
go: 1.23.x
go: 1.24.x
os: macOS-latest
test_fuse: false
- job_name: Linux
go: 1.23.x
go: 1.24.x
os: ubuntu-latest
test_cloud_backends: true
test_fuse: true
check_changelog: true
- job_name: Linux (race)
go: 1.23.x
go: 1.24.x
os: ubuntu-latest
test_fuse: true
test_opts: "-race"
- job_name: Linux
go: 1.22.x
go: 1.23.x
os: ubuntu-latest
test_fuse: true
@ -185,7 +185,7 @@ jobs:
# prepare credentials for Google Cloud Storage tests in a temp file
export GOOGLE_APPLICATION_CREDENTIALS=$(mktemp --tmpdir restic-gcs-auth-XXXXXXX)
echo $RESTIC_TEST_GS_APPLICATION_CREDENTIALS_B64 | base64 -d > $GOOGLE_APPLICATION_CREDENTIALS
go test -cover -parallel 4 ./internal/backend/...
go test -cover -parallel 5 -timeout 15m ./internal/backend/...
# only run cloud backend tests for pull requests from and pushes to our
# own repo, otherwise the secrets are not available
@ -204,7 +204,6 @@ jobs:
cross_compile:
strategy:
matrix:
# run cross-compile in three batches parallel so the overall tests run faster
subset:
@ -254,7 +253,7 @@ jobs:
uses: golangci/golangci-lint-action@v6
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.63.4
version: v1.64.8
args: --verbose --timeout 5m
# only run golangci-lint for pull requests, otherwise ALL hints get

View file

@ -58,7 +58,7 @@ var config = Config{
Main: "./cmd/restic", // package name for the main package
DefaultBuildTags: []string{"selfupdate"}, // specify build tags which are always used
Tests: []string{"./..."}, // tests to run
MinVersion: GoVersion{Major: 1, Minor: 22, Patch: 0}, // minimum Go version supported
MinVersion: GoVersion{Major: 1, Minor: 23, Patch: 0}, // minimum Go version supported
}
// Config configures the build.
@ -382,12 +382,6 @@ func main() {
}
}
solarisMinVersion := GoVersion{Major: 1, Minor: 20, Patch: 0}
if env["GOARCH"] == "solaris" && !goVersion.AtLeast(solarisMinVersion) {
fmt.Fprintf(os.Stderr, "Detected version %s is too old, restic requires at least %s for Solaris\n", goVersion, solarisMinVersion)
os.Exit(1)
}
verbosePrintf("detected Go version %v\n", goVersion)
preserveSymbols := false

View file

@ -1,9 +1,11 @@
Change: Update dependencies and require Go 1.22 or newer
Change: Update dependencies and require Go 1.23 or newer
We have updated all dependencies. Since some libraries require newer Go standard
library features, support for Go 1.19, 1.20 and 1.21 has been dropped, which means
that restic now requires at least Go 1.22 to build.
We have updated all dependencies. Since some libraries require newer Go
standard library features, support for Go 1.19, 1.20, 1.21 and 1.22 has been
dropped, which means that restic now requires at least Go 1.23 to build.
This also disables support for TLS versions older than TLS 1.2.
This also disables support for TLS versions older than TLS 1.2. On Windows,
restic now requires at least Windows 10 or Windows Server 2016. On macOS,
restic now requires at least macOS 11 Big Sur.
https://github.com/restic/restic/pull/4938

View file

@ -284,7 +284,7 @@ From Source
***********
restic is written in the Go programming language and you need at least
Go version 1.22. Building restic may also work with older versions of Go,
Go version 1.23. Building restic may also work with older versions of Go,
but that's not supported. See the `Getting
started <https://go.dev/doc/install>`__ guide of the Go project for
instructions how to install Go.

6
go.mod
View file

@ -1,6 +1,10 @@
module github.com/restic/restic
go 1.22
go 1.23
// keep the old behavior for reparse points on windows until handling reparse points has been improved in restic
// https://forum.restic.net/t/windows-junction-backup-with-go1-23-or-later/8940
godebug winsymlink=0
require (
cloud.google.com/go/storage v1.43.0

View file

@ -10,11 +10,13 @@ import (
"os"
"reflect"
"sort"
"sync"
"testing"
"time"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"golang.org/x/sync/errgroup"
"github.com/restic/restic/internal/test"
@ -276,16 +278,26 @@ func (s *Suite[C]) TestList(t *testing.T) {
}
list1 := make(map[restic.ID]int64)
var m sync.Mutex
wg, ctx := errgroup.WithContext(context.TODO())
for i := 0; i < numTestFiles; i++ {
data := test.Random(random.Int(), random.Intn(100)+55)
id := restic.Hash(data)
h := backend.Handle{Type: backend.PackFile, Name: id.String()}
err := b.Save(context.TODO(), h, backend.NewByteReader(data, b.Hasher()))
if err != nil {
t.Fatal(err)
}
list1[id] = int64(len(data))
wg.Go(func() error {
id := restic.Hash(data)
h := backend.Handle{Type: backend.PackFile, Name: id.String()}
err := b.Save(ctx, h, backend.NewByteReader(data, b.Hasher()))
m.Lock()
defer m.Unlock()
list1[id] = int64(len(data))
return err
})
}
err = wg.Wait()
if err != nil {
t.Fatal(err)
}
t.Logf("wrote %v files", len(list1))
@ -713,18 +725,23 @@ func (s *Suite[C]) delayedRemove(t testing.TB, be backend.Backend, handles ...ba
// Some backend (swift, I'm looking at you) may implement delayed
// removal of data. Let's wait a bit if this happens.
wg, ctx := errgroup.WithContext(context.TODO())
for _, h := range handles {
err := be.Remove(context.TODO(), h)
if s.ErrorHandler != nil {
err = s.ErrorHandler(t, be, err)
}
if err != nil {
wg.Go(func() error {
err := be.Remove(ctx, h)
if s.ErrorHandler != nil {
err = s.ErrorHandler(t, be, err)
}
return err
}
})
}
err := wg.Wait()
if err != nil {
return err
}
start := time.Now()
for _, h := range handles {
start := time.Now()
attempt := 0
var found bool
var err error
@ -777,125 +794,124 @@ func delayedList(t testing.TB, b backend.Backend, tpe backend.FileType, max int,
// TestBackend tests all functions of the backend.
func (s *Suite[C]) TestBackend(t *testing.T) {
b := s.open(t)
defer s.close(t, b)
test.Assert(t, !b.IsNotExist(nil), "IsNotExist() recognized nil error")
test.Assert(t, !b.IsPermanentError(nil), "IsPermanentError() recognized nil error")
for _, tpe := range []backend.FileType{
backend.PackFile, backend.KeyFile, backend.LockFile,
backend.SnapshotFile, backend.IndexFile,
} {
// detect non-existing files
for _, ts := range testStrings {
id, err := restic.ParseID(ts.id)
test.OK(t, err)
t.Run(tpe.String(), func(t *testing.T) {
t.Parallel()
// test if blob is already in repository
h := backend.Handle{Type: tpe, Name: id.String()}
ret, err := beTest(context.TODO(), b, h)
test.OK(t, err)
test.Assert(t, !ret, "blob was found to exist before creating")
b := s.open(t)
defer s.close(t, b)
// try to stat a not existing blob
_, err = b.Stat(context.TODO(), h)
test.Assert(t, err != nil, "blob data could be extracted before creation")
test.Assert(t, b.IsNotExist(err), "IsNotExist() did not recognize Stat() error: %v", err)
test.Assert(t, b.IsPermanentError(err), "IsPermanentError() did not recognize Stat() error: %v", err)
test.Assert(t, !b.IsNotExist(nil), "IsNotExist() recognized nil error")
test.Assert(t, !b.IsPermanentError(nil), "IsPermanentError() recognized nil error")
// try to read not existing blob
err = testLoad(b, h)
test.Assert(t, err != nil, "blob could be read before creation")
test.Assert(t, b.IsNotExist(err), "IsNotExist() did not recognize Load() error: %v", err)
test.Assert(t, b.IsPermanentError(err), "IsPermanentError() did not recognize Load() error: %v", err)
// detect non-existing files
for _, ts := range testStrings {
id, err := restic.ParseID(ts.id)
test.OK(t, err)
// try to get string out, should fail
ret, err = beTest(context.TODO(), b, h)
test.OK(t, err)
test.Assert(t, !ret, "id %q was found (but should not have)", ts.id)
}
// test if blob is already in repository
h := backend.Handle{Type: tpe, Name: id.String()}
ret, err := beTest(context.TODO(), b, h)
test.OK(t, err)
test.Assert(t, !ret, "id %q was found (but should not have)", ts.id)
// add files
for _, ts := range testStrings {
store(t, b, tpe, []byte(ts.data))
// try to stat a not existing blob
_, err = b.Stat(context.TODO(), h)
test.Assert(t, err != nil, "blob data could be extracted before creation")
test.Assert(t, b.IsNotExist(err), "IsNotExist() did not recognize Stat() error: %v", err)
test.Assert(t, b.IsPermanentError(err), "IsPermanentError() did not recognize Stat() error: %v", err)
// test Load()
// try to read not existing blob
err = testLoad(b, h)
test.Assert(t, err != nil, "blob could be read before creation")
test.Assert(t, b.IsNotExist(err), "IsNotExist() did not recognize Load() error: %v", err)
test.Assert(t, b.IsPermanentError(err), "IsPermanentError() did not recognize Load() error: %v", err)
}
// add files
for _, ts := range testStrings {
store(t, b, tpe, []byte(ts.data))
// test Load()
h := backend.Handle{Type: tpe, Name: ts.id}
buf, err := LoadAll(context.TODO(), b, h)
test.OK(t, err)
test.Equals(t, ts.data, string(buf))
// try to read it out with an offset and a length
start := 1
end := len(ts.data) - 2
length := end - start
buf2 := make([]byte, length)
var n int
err = b.Load(context.TODO(), h, len(buf2), int64(start), func(rd io.Reader) (ierr error) {
n, ierr = io.ReadFull(rd, buf2)
return ierr
})
test.OK(t, err)
test.OK(t, err)
test.Equals(t, len(buf2), n)
test.Equals(t, ts.data[start:end], string(buf2))
}
// test adding the first file again
ts := testStrings[0]
h := backend.Handle{Type: tpe, Name: ts.id}
buf, err := LoadAll(context.TODO(), b, h)
test.OK(t, err)
test.Equals(t, ts.data, string(buf))
// try to read it out with an offset and a length
start := 1
end := len(ts.data) - 2
length := end - start
buf2 := make([]byte, length)
var n int
err = b.Load(context.TODO(), h, len(buf2), int64(start), func(rd io.Reader) (ierr error) {
n, ierr = io.ReadFull(rd, buf2)
return ierr
})
test.OK(t, err)
test.OK(t, err)
test.Equals(t, len(buf2), n)
test.Equals(t, ts.data[start:end], string(buf2))
}
// test adding the first file again
ts := testStrings[0]
h := backend.Handle{Type: tpe, Name: ts.id}
// remove and recreate
err := s.delayedRemove(t, b, h)
test.OK(t, err)
// test that the blob is gone
ok, err := beTest(context.TODO(), b, h)
test.OK(t, err)
test.Assert(t, !ok, "removed blob still present")
// create blob
err = b.Save(context.TODO(), h, backend.NewByteReader([]byte(ts.data), b.Hasher()))
test.OK(t, err)
// list items
IDs := restic.IDs{}
for _, ts := range testStrings {
id, err := restic.ParseID(ts.id)
test.OK(t, err)
IDs = append(IDs, id)
}
list := delayedList(t, b, tpe, len(IDs), s.WaitForDelayedRemoval)
if len(IDs) != len(list) {
t.Fatalf("wrong number of IDs returned: want %d, got %d", len(IDs), len(list))
}
sort.Sort(IDs)
sort.Sort(list)
if !reflect.DeepEqual(IDs, list) {
t.Fatalf("lists aren't equal, want:\n %v\n got:\n%v\n", IDs, list)
}
var handles []backend.Handle
for _, ts := range testStrings {
id, err := restic.ParseID(ts.id)
// remove and recreate
err := s.delayedRemove(t, b, h)
test.OK(t, err)
h := backend.Handle{Type: tpe, Name: id.String()}
found, err := beTest(context.TODO(), b, h)
// test that the blob is gone
ok, err := beTest(context.TODO(), b, h)
test.OK(t, err)
test.Assert(t, found, fmt.Sprintf("id %v/%q not found", tpe, id))
test.Assert(t, !ok, "removed blob still present")
handles = append(handles, h)
}
// create blob
err = b.Save(context.TODO(), h, backend.NewByteReader([]byte(ts.data), b.Hasher()))
test.OK(t, err)
test.OK(t, s.delayedRemove(t, b, handles...))
// list items
IDs := restic.IDs{}
for _, ts := range testStrings {
id, err := restic.ParseID(ts.id)
test.OK(t, err)
IDs = append(IDs, id)
}
list := delayedList(t, b, tpe, len(IDs), s.WaitForDelayedRemoval)
if len(IDs) != len(list) {
t.Fatalf("wrong number of IDs returned: want %d, got %d", len(IDs), len(list))
}
sort.Sort(IDs)
sort.Sort(list)
if !reflect.DeepEqual(IDs, list) {
t.Fatalf("lists aren't equal, want:\n %v\n got:\n%v\n", IDs, list)
}
var handles []backend.Handle
for _, ts := range testStrings {
id, err := restic.ParseID(ts.id)
test.OK(t, err)
h := backend.Handle{Type: tpe, Name: id.String()}
found, err := beTest(context.TODO(), b, h)
test.OK(t, err)
test.Assert(t, found, fmt.Sprintf("id %v/%q not found", tpe, id))
handles = append(handles, h)
}
test.OK(t, s.delayedRemove(t, b, handles...))
})
}
}