Merge pull request #942 from dolthub/andy/feature-version

Andy/feature version
This commit is contained in:
AndyA
2020-10-26 13:00:13 -07:00
committed by GitHub
7 changed files with 102 additions and 10 deletions

View File

@@ -9,6 +9,14 @@ teardown() {
teardown_common
}
@test "dolt version --feature" {
# bump this test with feature version bumps
run dolt version --feature
[ "$status" -ne 0 ]
[[ "$output" =~ "dolt version" ]] || false
[[ "$output" =~ "the current head does not have a feature version" ]] || false
}
@test "no changes" {
dolt status
run dolt status

View File

@@ -24,6 +24,7 @@ import (
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/events"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
"github.com/dolthub/dolt/go/store/nbs"
)
func isHelp(str string) bool {
@@ -193,6 +194,10 @@ func CheckEnvIsValid(dEnv *env.DoltEnv) bool {
} else if dEnv.DBLoadError != nil {
PrintErrln(color.RedString("Failed to load database."))
PrintErrln(dEnv.DBLoadError.Error())
if dEnv.DBLoadError == nbs.ErrUnreadableManifest {
PrintErrln("\tyou might need to upgrade your Dolt client")
PrintErrln("\tvisit https://github.com/dolthub/dolt/releases/latest/")
}
return false
}

View File

@@ -17,10 +17,16 @@ package commands
import (
"context"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
"github.com/dolthub/dolt/go/cmd/dolt/cli"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
)
const (
featureVersionFlag = "feature"
)
type VersionCmd struct {
@@ -48,10 +54,38 @@ func (cmd VersionCmd) CreateMarkdown(fs filesys.Filesys, path, commandStr string
return nil
}
func (cmd VersionCmd) createArgParser() *argparser.ArgParser {
ap := argparser.NewArgParser()
ap.SupportsFlag(featureVersionFlag, "f", "query the feature version of this repository.")
return ap
}
// Version displays the version of the running dolt client
// Exec executes the command
func (cmd VersionCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv) int {
cli.Println("dolt version", cmd.VersionStr)
return 0
usage := func() {}
ap := cmd.createArgParser()
apr := cli.ParseArgs(ap, args, usage)
var verr errhand.VerboseError
if apr.Contains(featureVersionFlag) {
wr, err := dEnv.WorkingRoot(ctx)
if err != nil {
verr = errhand.BuildDError("could not read working root").AddCause(err).Build()
return HandleVErrAndExitCode(verr, usage)
}
fv, ok, err := wr.GetFeatureVersion(ctx)
if err != nil {
verr = errhand.BuildDError("error reading feature version").AddCause(err).Build()
} else if !ok {
verr = errhand.BuildDError("the current head does not have a feature version").Build()
} else {
cli.Println("feature version:", fv)
}
}
return HandleVErrAndExitCode(verr, usage)
}

View File

@@ -45,9 +45,13 @@ const (
MasterBranch = "master"
CommitStructName = "Commit"
FeatureVersion featureVersion = 0
defaultChunksPerTF = 256 * 1024
)
type featureVersion int64
// LocalDirDoltDB stores the db in the current directory
var LocalDirDoltDB = "file://./" + dbfactory.DoltDataDir
@@ -412,14 +416,30 @@ func (ddb *DoltDB) ReadRootValue(ctx context.Context, h hash.Hash) (*RootValue,
if err != nil {
return nil, err
}
if val == nil {
return nil, errors.New("there is no dolt root value at that hash")
}
if val != nil {
if rootSt, ok := val.(types.Struct); ok && rootSt.Name() == ddbRootStructName {
return &RootValue{ddb.db, rootSt, nil}, nil
rootSt, ok := val.(types.Struct)
if !ok || rootSt.Name() != ddbRootStructName {
return nil, errors.New("there is no dolt root value at that hash")
}
v, ok, err := rootSt.MaybeGet(featureVersKey)
if err != nil {
return nil, err
}
if ok {
ver := featureVersion(v.(types.Int))
if FeatureVersion < ver {
return nil, ErrClientOutOfDate{
clientVer: FeatureVersion,
repoVer: ver,
}
}
}
return nil, errors.New("there is no dolt root value at that hash")
return &RootValue{ddb.db, rootSt, nil}, nil
}
// Commit will update a branch's head value to be that of a previously committed root value hash

View File

@@ -14,7 +14,10 @@
package doltdb
import "errors"
import (
"errors"
"fmt"
)
var ErrInvBranchName = errors.New("not a valid user branch name")
var ErrInvTagName = errors.New("not a valid user tag name")
@@ -40,6 +43,16 @@ var ErrUpToDate = errors.New("up to date")
var ErrIsAhead = errors.New("current fast forward from a to b. a is ahead of b already")
var ErrIsBehind = errors.New("cannot reverse from b to a. b is a is behind a already")
type ErrClientOutOfDate struct {
repoVer featureVersion
clientVer featureVersion
}
func (e ErrClientOutOfDate) Error() string {
return fmt.Sprintf(`client (version: %d) is out of date and must upgrade to read this repo (version: %d).
visit https://github.com/dolthub/dolt/releases/latest/`, e.clientVer, e.repoVer)
}
func IsInvalidFormatErr(err error) bool {
switch err {
case ErrInvBranchName, ErrInvTableName, ErrInvHash, ErrInvalidAncestorSpec, ErrInvalidBranchOrHash:

View File

@@ -35,6 +35,7 @@ const (
tablesKey = "tables"
superSchemasKey = "super_schemas"
foreignKeyKey = "foreign_key"
featureVersKey = "feature_ver"
)
// RootValue defines the structure used inside all Liquidata noms dbs
@@ -131,6 +132,16 @@ func (root *RootValue) VRW() types.ValueReadWriter {
return root.vrw
}
// GetFeatureVersion returns the feature version of this root, if one is written
func (root *RootValue) GetFeatureVersion(ctx context.Context) (ver int64, ok bool, err error) {
v, ok, err := root.valueSt.MaybeGet(featureVersKey)
if err != nil || !ok {
return ver, ok, err
}
ver = int64(v.(types.Int))
return ver, ok, err
}
func (root *RootValue) HasTable(ctx context.Context, tName string) (bool, error) {
val, found, err := root.valueSt.MaybeGet(tablesKey)

View File

@@ -24,7 +24,6 @@ package nbs
import (
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
@@ -48,6 +47,8 @@ const (
prefixLen = 5
)
var ErrUnreadableManifest = errors.New("could not read file manifest")
type manifestParser func(r io.Reader) (manifestContents, error)
type manifestWriter func(temp io.Writer, contents manifestContents) error
type manifestChecker func(upstream, contents manifestContents) error
@@ -81,7 +82,7 @@ func MaybeMigrateFileManifest(ctx context.Context, dir string) (bool, error) {
}
if !ok {
// expected v4 or v5
return false, fmt.Errorf("could not read file manifest")
return false, ErrUnreadableManifest
}
check := func(upstream, contents manifestContents) error {
@@ -127,7 +128,7 @@ func getFileManifest(ctx context.Context, dir string) (manifest, error) {
return fm4, nil
}
return nil, fmt.Errorf("could not read file manifest")
return nil, ErrUnreadableManifest
}
// fileManifestV5 provides access to a NomsBlockStore manifest stored on disk in |dir|. The format