diff --git a/cmd/init.go b/cmd/init.go index 0316741..8ebee34 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -151,9 +151,10 @@ var initCmd = &cobra.Command{ // Create the pack pack := core.Pack{ - Name: name, - Author: author, - Version: version, + Name: name, + Author: author, + Version: version, + PackFormat: core.CurrentPackFormat, Index: struct { File string `toml:"file"` HashFormat string `toml:"hash-format"` diff --git a/core/pack.go b/core/pack.go index ae52f84..dc868f2 100644 --- a/core/pack.go +++ b/core/pack.go @@ -3,20 +3,24 @@ package core import ( "encoding/hex" "errors" + "fmt" "io" "os" "path/filepath" + "strings" "github.com/BurntSushi/toml" + "github.com/Masterminds/semver/v3" "github.com/spf13/viper" ) // Pack stores the modpack metadata, usually in pack.toml type Pack struct { - Name string `toml:"name"` - Author string `toml:"author,omitempty"` - Version string `toml:"version,omitempty"` - Index struct { + Name string `toml:"name"` + Author string `toml:"author,omitempty"` + Version string `toml:"version,omitempty"` + PackFormat string `toml:"pack-format"` + Index struct { // Path is stored in forward slash format relative to pack.toml File string `toml:"file"` HashFormat string `toml:"hash-format"` @@ -27,6 +31,19 @@ type Pack struct { Options map[string]interface{} `toml:"options"` } +const CurrentPackFormat = "packwiz:1.0.0" + +var PackFormatConstraintAccepted = mustParseConstraint("~1") +var PackFormatConstraintSuggestUpgrade = mustParseConstraint("~1.0") + +func mustParseConstraint(s string) *semver.Constraints { + c, err := semver.NewConstraint(s) + if err != nil { + panic(err) + } + return c +} + // LoadPack loads the modpack metadata to a Pack struct func LoadPack() (Pack, error) { var modpack Pack @@ -34,6 +51,26 @@ func LoadPack() (Pack, error) { return Pack{}, err } + // Check pack-format + if len(modpack.PackFormat) == 0 { + fmt.Println("Modpack manifest has no pack-format field; assuming packwiz:1.0.0") + modpack.PackFormat = "packwiz:1.0.0" + } + if !strings.HasPrefix(modpack.PackFormat, "packwiz:") { + return Pack{}, errors.New("pack-format field does not indicate a valid packwiz pack") + } + ver, err := semver.StrictNewVersion(strings.TrimPrefix(modpack.PackFormat, "packwiz:")) + if err != nil { + return Pack{}, fmt.Errorf("pack-format field is not valid semver: %w", err) + } + if !PackFormatConstraintAccepted.Check(ver) { + return Pack{}, errors.New("the modpack is incompatible with this version of packwiz; please update") + } + if !PackFormatConstraintSuggestUpgrade.Check(ver) { + fmt.Println("Modpack has a newer feature number than is supported by this version of packwiz. Update to the latest version of packwiz for new features and bugfixes!") + } + // TODO: suggest migration if necessary (primarily for 2.0.0) + // Read options into viper if modpack.Options != nil { err := viper.MergeConfigMap(modpack.Options) diff --git a/curseforge/import.go b/curseforge/import.go index 0216ff7..5f12d1c 100644 --- a/curseforge/import.go +++ b/curseforge/import.go @@ -155,6 +155,8 @@ var importCmd = &cobra.Command{ pack = core.Pack{ Name: packImport.Name(), + // TODO: author, version? + PackFormat: core.CurrentPackFormat, Index: struct { File string `toml:"file"` HashFormat string `toml:"hash-format"` diff --git a/go.mod b/go.mod index 573d363..532e4b8 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,7 @@ module github.com/comp500/packwiz require ( github.com/BurntSushi/toml v0.3.1 + github.com/Masterminds/semver/v3 v3.1.1 github.com/VividCortex/ewma v1.2.0 // indirect github.com/aviddiviner/go-murmur v0.0.0-20150519214947-b9740d71e571 github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect @@ -19,7 +20,6 @@ require ( github.com/spf13/viper v1.8.0 github.com/vbauerster/mpb/v4 v4.12.2 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect - golang.org/x/mod v0.4.2 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect golang.org/x/text v0.3.6 // indirect @@ -27,4 +27,21 @@ require ( gopkg.in/dixonwille/wmenu.v4 v4.0.2 ) -go 1.14 +require ( + github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/pelletier/go-toml v1.9.3 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) + +go 1.17 diff --git a/go.sum b/go.sum index 3a237da..6d88841 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= @@ -143,9 +145,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= -github.com/golangplus/bytes v1.0.0 h1:YQKBijBVMsBxIiXT4IEhlKR2zHohjEqPole4umyDX+c= github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A= -github.com/golangplus/fmt v1.0.0 h1:FnUKtw86lXIPfBMc3FimNF3+ABcV+aH5F17OOitTN+E= github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE= github.com/golangplus/testing v1.0.0 h1:+ZeeiKZENNOMkTTELoSySazi+XaEhVO0mb+eanrSEUQ= github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA= @@ -400,7 +400,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/modrinth/modrinth.go b/modrinth/modrinth.go index 4e485e1..09eab36 100644 --- a/modrinth/modrinth.go +++ b/modrinth/modrinth.go @@ -7,13 +7,12 @@ import ( "io/ioutil" "net/http" "net/url" - "strings" "time" + "github.com/Masterminds/semver/v3" "github.com/comp500/packwiz/cmd" "github.com/comp500/packwiz/core" "github.com/spf13/cobra" - "golang.org/x/mod/semver" ) const modrinthApiUrl = "https://api.modrinth.com/api/v1/" @@ -214,13 +213,12 @@ func getLatestVersion(modID string, pack core.Pack) (Version, error) { latestValidVersion := result[0] for _, v := range result[1:] { - // For some reason, this library requires a "v" prefix for all version numbers - currVersion := "v" + strings.TrimPrefix(v.VersionNumber, "v") - latestVersion := "v" + strings.TrimPrefix(latestValidVersion.VersionNumber, "v") + currVersion, err1 := semver.NewVersion(v.VersionNumber) + latestVersion, err2 := semver.NewVersion(latestValidVersion.VersionNumber) var semverCompare = 0 // Only compare with semver if both are valid semver - otherwise compare by release date - if semver.IsValid(currVersion) && semver.IsValid(latestVersion) { - semverCompare = semver.Compare(currVersion, latestVersion) + if err1 == nil && err2 == nil { + semverCompare = currVersion.Compare(latestVersion) } if semverCompare == 0 {