Repository: kopia/kopia
Pull request #2627 (2022-12-05 14:45:21)

docs(site): add homebrew installation for kopiaui
added 

brew install kopiaui

there is a new homebrew cask installation available:

https://github.com/Homebrew/homebrew-cask/blob/master/Casks/kopiaui.rb




Patch:
diff --git a/cli/command_repository_set_parameters.go b/cli/command_repository_set_parameters.go
index 95a0189f..30cc0df0 100644
--- a/cli/command_repository_set_parameters.go
+++ b/cli/command_repository_set_parameters.go
@@ -122,9 +122,58 @@ func (c *commandRepositorySetParameters) setRetentionModeParameter(ctx context.C
 	log(ctx).Infof(" - setting %v to %s.\n", desc, v)
 }
 
-func (c *commandRepositorySetParameters) run(ctx context.Context, rep repo.DirectRepositoryWriter) error {
-	var anyChange bool
+func updateRepositoryParameters(
+	ctx context.Context,
+	upgradeToEpochManager bool,
+	mp format.MutableParameters,
+	rep repo.DirectRepositoryWriter,
+	blobcfg format.BlobStorageConfiguration,
+	requiredFeatures []feature.Required,
+) error {
+	if upgradeToEpochManager {
+		log(ctx).Infof("migrating current indexes to epoch format")
+
+		if err := rep.ContentManager().PrepareUpgradeToIndexBlobManagerV1(ctx, mp.EpochParameters); err != nil {
+			return errors.Wrap(err, "error upgrading indexes")
+		}
+	}
+
+	if err := rep.FormatManager().SetParameters(ctx, mp, blobcfg, requiredFeatures); err != nil {
+		return errors.Wrap(err, "error setting parameters")
+	}
+
+	if upgradeToEpochManager {
+		if err := content.WriteLegacyIndexPoisonBlob(ctx, rep.BlobStorage()); err != nil {
+			log(ctx).Errorf("unable to write legacy index poison blob: %v", err)
+		}
+	}
+
+	return nil
+}
+
+func updateEpochParameters(mp *format.MutableParameters, anyChange, upgradeToEpochManager *bool) {
+	*anyChange = true
+
+	if !mp.EpochParameters.Enabled {
+		mp.EpochParameters = epoch.DefaultParameters()
+		mp.IndexVersion = 2
+		*upgradeToEpochManager = true
+	}
+
+	if mp.Version < format.FormatVersion2 {
+		mp.Version = format.FormatVersion2
+	}
+}
 
+func (c *commandRepositorySetParameters) disableBlobRetention(ctx context.Context, blobcfg *format.BlobStorageConfiguration, anyChange *bool) {
+	log(ctx).Infof("disabling blob retention")
+
+	blobcfg.RetentionMode = ""
+	blobcfg.RetentionPeriod = 0
+	*anyChange = true
+}
+
+func (c *commandRepositorySetParameters) run(ctx context.Context, rep repo.DirectRepositoryWriter) error {
 	mp, err := rep.FormatManager().GetMutableParameters()
 	if err != nil {
 		return errors.Wrap(err, "mutable parameters")
@@ -140,32 +189,28 @@ func (c *commandRepositorySetParameters) run(ctx context.Context, rep repo.Direc
 		return errors.Wrap(err, "unable to get required features")
 	}
 
+	anyChange := false
 	upgradeToEpochManager := false
 
 	if c.upgradeRepositoryFormat {
-		anyChange = true
+		updateEpochParameters(&mp, &anyChange, &upgradeToEpochManager)
+	}
 
-		if !mp.EpochParameters.Enabled {
-			mp.EpochParameters = epoch.DefaultParameters()
-			upgradeToEpochManager = true
-			mp.IndexVersion = 2
-		}
+	c.setSizeMBParameter(ctx, c.maxPackSizeMB, "maximum pack size", &mp.MaxPackSize, &anyChange)
 
-		if mp.Version < format.FormatVersion2 {
-			mp.Version = format.FormatVersion2
+	// prevent downgrade of index format
+	if c.indexFormatVersion != 0 && c.indexFormatVersion != mp.IndexVersion {
+		if c.indexFormatVersion > mp.IndexVersion {
+			c.setIntParameter(ctx, c.indexFormatVersion, "index format version", &mp.IndexVersion, &anyChange)
+		} else {
+			return errors.Errorf("index format version can only be upgraded")
 		}
 	}
 
-	c.setSizeMBParameter(ctx, c.maxPackSizeMB, "maximum pack size", &mp.MaxPackSize, &anyChange)
-	c.setIntParameter(ctx, c.indexFormatVersion, "index format version", &mp.IndexVersion, &anyChange)
-
 	if c.retentionMode == "none" {
 		if blobcfg.IsRetentionEnabled() {
-			log(ctx).Infof("disabling blob retention")
-
-			blobcfg.RetentionMode = ""
-			blobcfg.RetentionPeriod = 0
-			anyChange = true
+			// disable blob retention if already enabled
+			c.disableBlobRetention(ctx, &blobcfg, &anyChange)
 		}
 	} else {
 		c.setRetentionModeParameter(ctx, blob.RetentionMode(c.retentionMode), "storage backend blob retention mode", &blobcfg.RetentionMode, &anyChange)
@@ -186,22 +231,8 @@ func (c *commandRepositorySetParameters) run(ctx context.Context, rep repo.Direc
 		return errors.Errorf("no changes")
 	}
 
-	if upgradeToEpochManager {
-		log(ctx).Infof("migrating current indexes to epoch format")
-
-		if err := rep.ContentManager().PrepareUpgradeToIndexBlobManagerV1(ctx, mp.EpochParameters); err != nil {
-			return errors.Wrap(err, "error upgrading indexes")
-		}
-	}
-
-	if err := rep.FormatManager().SetParameters(ctx, mp, blobcfg, requiredFeatures); err != nil {
-		return errors.Wrap(err, "error setting parameters")
-	}
-
-	if upgradeToEpochManager {
-		if err := content.WriteLegacyIndexPoisonBlob(ctx, rep.BlobStorage()); err != nil {
-			log(ctx).Errorf("unable to write legacy index poison blob: %v", err)
-		}
+	if err := updateRepositoryParameters(ctx, upgradeToEpochManager, mp, rep, blobcfg, requiredFeatures); err != nil {
+		return errors.Wrap(err, "error updating repository parameters")
 	}
 
 	log(ctx).Infof("NOTE: Repository parameters updated, you must disconnect and re-connect all other Kopia clients.")
diff --git a/go.mod b/go.mod
index cf79b2d2..ee7a98c3 100644
--- a/go.mod
+++ b/go.mod
@@ -48,7 +48,7 @@ require (
 	github.com/zalando/go-keyring v0.2.1
 	github.com/zeebo/blake3 v0.2.3
 	go.opencensus.io v0.24.0 // indirect
-	go.uber.org/zap v1.23.0
+	go.uber.org/zap v1.24.0
 	golang.org/x/crypto v0.3.0
 	golang.org/x/mod v0.7.0
 	golang.org/x/net v0.2.0
diff --git a/go.sum b/go.sum
index 10ac76e4..2ed908b9 100644
--- a/go.sum
+++ b/go.sum
@@ -436,8 +436,8 @@ go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
 go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
 go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
-go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
-go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
+go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
+go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
diff --git a/site/content/docs/Installation/_index.md b/site/content/docs/Installation/_index.md
index ef7df666..ce4bf09e 100644
--- a/site/content/docs/Installation/_index.md
+++ b/site/content/docs/Installation/_index.md
@@ -98,6 +98,22 @@ Alternatively, to install the latest unreleased version of Kopia use the followi
 $ brew install kopia/test-builds/kopia
 ```
 
+#### macOS GUI using Homebrew
+
+On macOS, you can use [Homebrew](https://brew.sh) to install and keep Kopia up-to-date.
+
+To install:
+
+```shell
+$ brew install kopiaui
+```
+
+To upgrade Kopia:
+
+```shell
+$ brew upgrade kopiaui
+```
+
 #### macOS GUI installer
 
 MacOS package with `KopiaUI` is available in DMG and ZIP formats on the [releases page](https://github.com/kopia/kopia/releases/latest).


Test patch:
diff --git a/cli/command_repository_set_parameters_test.go b/cli/command_repository_set_parameters_test.go
index 136785ac..87caecaf 100644
--- a/cli/command_repository_set_parameters_test.go
+++ b/cli/command_repository_set_parameters_test.go
@@ -182,6 +182,49 @@ func (s *formatSpecificTestSuite) TestRepositorySetParametersUpgrade(t *testing.
 	env.RunAndExpectSuccess(t, "index", "epoch", "list")
 }
 
+// TestRepositorySetParametersDowngrade test that a repository cannot be downgraded by using `set-parameters`.
+func (s *formatSpecificTestSuite) TestRepositorySetParametersDowngrade(t *testing.T) {
+	env := s.setupInMemoryRepo(t)
+
+	// checkStatusForVersion is a function with stanzas to check that the repository has the expected version.
+	// 	its saved into a variable to prevent repetition and enforce that nothing has changed between invocations
+	//  if `set-parameters`
+	checkStatusForVersion := func() {
+		out := env.RunAndExpectSuccess(t, "repository", "status")
+
+		// default values
+		require.Contains(t, out, "Max pack length:     21 MB")
+
+		switch s.formatVersion {
+		case format.FormatVersion1:
+			require.Contains(t, out, "Format version:      1")
+			require.Contains(t, out, "Epoch Manager:       disabled")
+			env.RunAndExpectFailure(t, "index", "epoch", "list")
+		case format.FormatVersion2:
+			require.Contains(t, out, "Format version:      2")
+			require.Contains(t, out, "Epoch Manager:       enabled")
+			env.RunAndExpectSuccess(t, "index", "epoch", "list")
+		default:
+			require.Contains(t, out, "Format version:      3")
+			require.Contains(t, out, "Epoch Manager:       enabled")
+			env.RunAndExpectSuccess(t, "index", "epoch", "list")
+		}
+	}
+
+	checkStatusForVersion()
+
+	env.RunAndExpectFailure(t, "repository", "set-parameters", "--index-version=1")
+
+	checkStatusForVersion()
+
+	// run basic check to ensure that an upgrade can still be performed as expected
+	env.RunAndExpectSuccess(t, "repository", "set-parameters", "--upgrade")
+
+	out := env.RunAndExpectSuccess(t, "repository", "status")
+	require.Contains(t, out, "Epoch Manager:       enabled")
+	require.Contains(t, out, "Index Format:        v2")
+}
+
 func (s *formatSpecificTestSuite) TestRepositorySetParametersRequiredFeatures(t *testing.T) {
 	env := s.setupInMemoryRepo(t)