Skip to content

Commit

Permalink
Merge pull request #382 from mutagen-io/v016-development
Browse files Browse the repository at this point in the history
all: prepare for v0.16.0-beta1
  • Loading branch information
xenoscopic authored Sep 12, 2022
2 parents 175eb21 + 2e3b8d1 commit 1194f46
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .github/issue_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ relevant information such as:
The more information you provide, the easier it will be to diagnose the problem.
Thanks for taking the time to submit a report!
-->
2 changes: 2 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ these guidelines cannot be merged.
If you're not quite ready for a final review, please feel free to open a draft
pull request.
Thanks for taking the time to open a pull request!
-->

**What does this pull request do and why is it needed?**
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.19.0'
go-version: '1.19.*'
- name: "Install sha256sum"
run: brew install coreutils
- run: scripts/ci/setup_go.sh
Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.19.0'
go-version: '1.19.*'
- run: scripts/ci/setup_go.sh
- run: scripts/ci/setup_ssh.sh
- run: scripts/ci/setup_docker.sh
Expand All @@ -90,7 +90,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.19.0'
go-version: '1.19.*'
- run: scripts/ci/setup_go.sh
shell: bash
- run: scripts/ci/setup_docker.sh
Expand All @@ -113,7 +113,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.19.0'
go-version: '1.19.*'
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- uses: docker/login-action@v1
Expand Down
2 changes: 1 addition & 1 deletion images/sidecar/linux/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use an Alpine-based Go builder.
FROM golang:1.19.0-alpine3.16 AS builder
FROM golang:1.19-alpine3.16 AS builder

# Disable cgo in order to match the behavior of our release binaries (and to
# avoid the need for gcc on certain architectures).
Expand Down
2 changes: 1 addition & 1 deletion pkg/mutagen/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const (
// VersionTag represents a tag to be appended to the Mutagen version string.
// It must not contain spaces. If empty, no tag is appended to the version
// string.
VersionTag = "alpha3"
VersionTag = "beta1"
)

// DevelopmentModeEnabled indicates that development mode is active. This is
Expand Down
10 changes: 6 additions & 4 deletions pkg/state/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ type pollRequest struct {
// Tracker provides index-based state tracking using a condition variable.
type Tracker struct {
// change is the condition variable used to track changes. It is used to
// signal state changes to index and terminated. Its lock also guards the
// pollRequests map.
// signal state changes to index and terminated. It is also used to
// serialize and signal changes to pollRequests.
change *sync.Cond
// index is the current state index.
// NOTE: In theory, we should track and handle overflow on this index, but
Expand Down Expand Up @@ -194,8 +194,10 @@ func (t *Tracker) WaitForChange(ctx context.Context, previousIndex uint64) (uint
// Release the state lock.
t.change.L.Unlock()

// Wait for a state change or cancellation. If the polling operation
// succeeds, then the tracking loop will deregister the request.
// Wait for a state change or cancellation. If the request is cancelled,
// then we'll deregister it ourselves (in which case there's no need to
// notify the tracking loop). If the polling operation succeeds, then the
// tracking loop will deregister the request.
select {
case <-ctx.Done():
t.change.L.Lock()
Expand Down
2 changes: 1 addition & 1 deletion pkg/synchronization/core/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func EnsureDefaultFileModeValid(permissionsMode PermissionsMode, mode filesystem

// EnsureDefaultDirectoryModeValid validates that a user-provided default
// directory mode is valid in the context of a given permissions mode.
func EnsureDefaultDirectoryModeValid(permissionsMode PermissionsMode, mode filesystem.Mode) error {
func EnsureDefaultDirectoryModeValid(_ PermissionsMode, mode filesystem.Mode) error {
// Verify that the mode is non-zero. This should never be the case, because
// we treat a zero-value mode as unspecified.
if mode == 0 {
Expand Down
112 changes: 112 additions & 0 deletions pkg/synchronization/core/permissions_mode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package core

import (
"testing"
)

// TestPermissionsModeIsDefault tests PermissionsMode.IsDefault.
func TestPermissionsModeIsDefault(t *testing.T) {
// Define test cases.
tests := []struct {
value PermissionsMode
expected bool
}{
{PermissionsMode_PermissionsModeDefault - 1, false},
{PermissionsMode_PermissionsModeDefault, true},
{PermissionsMode_PermissionsModePortable, false},
{PermissionsMode_PermissionsModeManual, false},
{PermissionsMode_PermissionsModeManual + 1, false},
}

// Process test cases.
for i, test := range tests {
if result := test.value.IsDefault(); result && !test.expected {
t.Errorf("test index %d: value was unexpectedly classified as default", i)
} else if !result && test.expected {
t.Errorf("test index %d: value was unexpectedly classified as non-default", i)
}
}
}

// TestPermissionsModeUnmarshalText tests PermissionsMode.UnmarshalText.
func TestPermissionsModeUnmarshalText(t *testing.T) {
// Define test cases.
tests := []struct {
text string
expectedMode PermissionsMode
expectFailure bool
}{
{"", PermissionsMode_PermissionsModeDefault, true},
{"asdf", PermissionsMode_PermissionsModeDefault, true},
{"portable", PermissionsMode_PermissionsModePortable, false},
{"manual", PermissionsMode_PermissionsModeManual, false},
}

// Process test cases.
for _, test := range tests {
var mode PermissionsMode
if err := mode.UnmarshalText([]byte(test.text)); err != nil {
if !test.expectFailure {
t.Errorf("unable to unmarshal text (%s): %s", test.text, err)
}
} else if test.expectFailure {
t.Error("unmarshaling succeeded unexpectedly for text:", test.text)
} else if mode != test.expectedMode {
t.Errorf(
"unmarshaled mode (%s) does not match expected (%s)",
mode,
test.expectedMode,
)
}
}
}

// TestPermissionsModeSupported tests PermissionsMode.Supported.
func TestPermissionsModeSupported(t *testing.T) {
// Set up test cases.
testCases := []struct {
mode PermissionsMode
expectSupported bool
}{
{PermissionsMode_PermissionsModeDefault, false},
{PermissionsMode_PermissionsModePortable, true},
{PermissionsMode_PermissionsModeManual, true},
{(PermissionsMode_PermissionsModeManual + 1), false},
}

// Process test cases.
for _, testCase := range testCases {
if supported := testCase.mode.Supported(); supported != testCase.expectSupported {
t.Errorf(
"mode support status (%t) does not match expected (%t)",
supported,
testCase.expectSupported,
)
}
}
}

// TestPermissionsModeDescription tests PermissionsMode.Description.
func TestPermissionsModeDescription(t *testing.T) {
// Set up test cases.
testCases := []struct {
mode PermissionsMode
expectedDescription string
}{
{PermissionsMode_PermissionsModeDefault, "Default"},
{PermissionsMode_PermissionsModePortable, "Portable"},
{PermissionsMode_PermissionsModeManual, "Manual"},
{(PermissionsMode_PermissionsModeManual + 1), "Unknown"},
}

// Process test cases.
for _, testCase := range testCases {
if description := testCase.mode.Description(); description != testCase.expectedDescription {
t.Errorf(
"mode description (%s) does not match expected (%s)",
description,
testCase.expectedDescription,
)
}
}
}
11 changes: 6 additions & 5 deletions pkg/synchronization/core/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,10 @@ func (s *scanner) directory(
// encoded with Protocol Buffers (which enforces that strings are UTF-8
// encoded when marshaling). Since the file name isn't valid for storing
// in the content map, we'll replace all unknown byte sequences with a
// (hopefully) non-coliding character sequence.
// replacement character and store the entry with a (hopefully)
// non-coliding derivative name.
if !utf8.ValidString(contentName) {
contents[strings.ToValidUTF8(contentName, "�")] = &Entry{
contents[strings.ToValidUTF8(contentName, "�")+" (non-UTF-8)"] = &Entry{
Kind: EntryKind_Problematic,
Problem: "non-UTF-8 filename",
}
Expand Down Expand Up @@ -566,9 +567,9 @@ func (s *scanner) directory(
}

// Scan creates a new filesystem snapshot at the specified root. The only
// required arguments are ctx, root, hasher, ignores, probeMode, and
// symbolicLinkMode. The baseline, recheckPaths, cache, and ignoreCache fields
// merely provide acceleration options.
// required arguments are ctx, root, hasher, ignores, probeMode,
// symbolicLinkMode, and permissionsMode. The baseline, recheckPaths, cache, and
// ignoreCache fields merely provide acceleration options.
func Scan(
ctx context.Context,
root string,
Expand Down
2 changes: 1 addition & 1 deletion pkg/synchronization/core/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestScan(t *testing.T) {
PermissionsMode_PermissionsModePortable,
false,
&Entry{Contents: map[string]*Entry{
"hell�": tPInvalidUTF8,
"hell� (non-UTF-8)": tPInvalidUTF8,
}},
nil,
},
Expand Down
19 changes: 10 additions & 9 deletions pkg/synchronization/core/transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,18 @@ func (t *transitioner) ensureExpectedFile(parent *filesystem.Directory, name, pa
//
// Notably absent from this comparison is an explicit equality check of the
// Executability property of the expected entry with some computed
// executability value. Unfortunately this can't be done directly, because
// executability value. Unfortunately, this can't be done directly because
// we may be on a filesystem that does not preserve exectuability
// information. Indeed, the Executability property may have been set by the
// executability propagation algorithm before reconciliation. Instead, we
// take an indirect comparison approach and simply compare permission bits
// (as part of the mode equivalence check) from the current metadata and the
// cache. If these match, we take it as an indication that the permission
// bits which (via some mechanism in the synchronization algorithm)
// generated the current Executability property value are unchanged, and
// hence the Executability property value would be unchanged as well if we
// were able to compute and compare it directly.
// executability propagation algorithm before reconciliation. We may also be
// in a permissions mode where we're not recording executability information
// in entries. Thus, we take an indirect comparison approach and simply
// compare permission bits (as part a broader mode equivalence check) from
// the current metadata and the cache. If these match, then we take it as an
// indication that the permission bits which (via some mechanism in the
// synchronization algorithm) generated the current Executability property
// value are unchanged, and hence the Executability property value would be
// unchanged as well if we were able to compute and compare it directly.
match := metadata.Mode == filesystem.Mode(cached.Mode) &&
metadata.ModificationTime.Equal(cached.ModificationTime.AsTime()) &&
metadata.Size == cached.Size &&
Expand Down

0 comments on commit 1194f46

Please sign in to comment.