mirror of
https://github.com/packwiz/packwiz.git
synced 2025-04-19 21:16:30 +02:00
Redo update system to work with batched updates
This commit is contained in:
parent
adcde05693
commit
b77e2080c7
@ -7,8 +7,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
"github.com/vbauerster/mpb/v4"
|
"github.com/vbauerster/mpb/v4"
|
||||||
@ -192,6 +192,7 @@ func (in *Index) Refresh() error {
|
|||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
|
// TODO: this is stupid, traverse the file tree first *then* read all the files
|
||||||
if progressCurrent >= progressLength {
|
if progressCurrent >= progressLength {
|
||||||
progressLength++
|
progressLength++
|
||||||
progress.SetTotal(int64(progressLength), false)
|
progress.SetTotal(int64(progressLength), false)
|
||||||
@ -272,7 +273,7 @@ func (in *Index) RefreshFileWithHash(path, format, hash string, mod bool) error
|
|||||||
func (in Index) FindMod(modName string) (string, bool) {
|
func (in Index) FindMod(modName string) (string, bool) {
|
||||||
for _, v := range in.Files {
|
for _, v := range in.Files {
|
||||||
if v.MetaFile {
|
if v.MetaFile {
|
||||||
_, file := filepath.Split(v.File);
|
_, file := filepath.Split(v.File)
|
||||||
fileTrimmed := strings.TrimSuffix(file, ModExtension)
|
fileTrimmed := strings.TrimSuffix(file, ModExtension)
|
||||||
if fileTrimmed == modName {
|
if fileTrimmed == modName {
|
||||||
return v.File, true
|
return v.File, true
|
||||||
@ -280,4 +281,4 @@ func (in Index) FindMod(modName string) (string, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,43 @@
|
|||||||
package core
|
package core
|
||||||
// UpdateParsers stores all the update parsers that packwiz can use. Add your own update systems to this map.
|
|
||||||
var UpdateParsers = make(map[string]UpdateParser)
|
|
||||||
|
|
||||||
// UpdateParser takes an unparsed interface{} (as a map[string]interface{}), and returns an Updater for a mod file.
|
// Updaters stores all the updaters that packwiz can use. Add your own update systems to this map, keyed by the configuration name.
|
||||||
// This can be done using the mapstructure library or your own parsing methods.
|
var Updaters = make(map[string]Updater)
|
||||||
type UpdateParser interface {
|
|
||||||
ParseUpdate(map[string]interface{}) (Updater, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updater checks for and does updates on a mod
|
// Updater is used to process updates on mods
|
||||||
type Updater interface {
|
type Updater interface {
|
||||||
// DoUpdate returns true if an update was done, false otherwise
|
// ParseUpdate takes an unparsed interface{} (as a map[string]interface{}), and returns an Updater for a mod file.
|
||||||
DoUpdate(Mod) (bool, error)
|
// This can be done using the mapstructure library or your own parsing methods.
|
||||||
|
ParseUpdate(map[string]interface{}) (interface{}, error)
|
||||||
|
// CheckUpdate checks whether there is an update for each of the mods in the given slice,
|
||||||
|
// called for all of the mods that this updater handles
|
||||||
|
CheckUpdate([]Mod) ([]UpdateCheck, error)
|
||||||
|
// DoUpdate carries out the update previously queried in CheckUpdate, on each Mod's metadata,
|
||||||
|
// given pointers to Mods and the value of CachedState for each mod
|
||||||
|
DoUpdate([]*Mod, []interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateCheck represents the data returned from CheckUpdate for each mod
|
||||||
|
type UpdateCheck struct {
|
||||||
|
// UpdateAvailable is true if an update is available for this mod
|
||||||
|
UpdateAvailable bool
|
||||||
|
// UpdateString is a string that details the update in some way to the user. Usually this will be in the form of
|
||||||
|
// a version change (1.0.0 -> 1.0.1), or a file name change (thanos-skin-1.0.0.jar -> thanos-skin-1.0.1.jar).
|
||||||
|
UpdateString string
|
||||||
|
// CachedState can be used to preserve per-mod state between CheckUpdate and DoUpdate (e.g. file metadata)
|
||||||
|
CachedState interface{}
|
||||||
|
// Error stores an error for this specific mod
|
||||||
|
// Errors can also be returned from CheckUpdate directly, if the whole operation failed completely (so only 1 error is printed)
|
||||||
|
// If an error is returned for a mod, or from CheckUpdate, DoUpdate is not called on that mod / at all
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: new docs
|
||||||
|
// to carry out updating:
|
||||||
|
|
||||||
|
// go through all metafiles in index
|
||||||
|
// make a []Mod for each updater, so map[string][]Mod
|
||||||
|
// for each Mod, check the "first" updater, then give the Mod to the map
|
||||||
|
|
||||||
|
// go through the map, call CheckUpdate with the []Mod
|
||||||
|
// print to user, if interactive mode
|
||||||
|
// call doupdate with the mods and interfaces!!
|
||||||
|
20
core/mod.go
20
core/mod.go
@ -19,8 +19,8 @@ type Mod struct {
|
|||||||
Optional bool `toml:"optional,omitempty"`
|
Optional bool `toml:"optional,omitempty"`
|
||||||
Download ModDownload `toml:"download"`
|
Download ModDownload `toml:"download"`
|
||||||
// Update is a map of map of stuff, so you can store arbitrary values on string keys to define updating
|
// Update is a map of map of stuff, so you can store arbitrary values on string keys to define updating
|
||||||
Update map[string]map[string]interface{} `toml:"update"`
|
Update map[string]map[string]interface{} `toml:"update"`
|
||||||
updaters map[string]Updater
|
updateData map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModDownload specifies how to download the mod file
|
// ModDownload specifies how to download the mod file
|
||||||
@ -43,16 +43,16 @@ func LoadMod(modFile string) (Mod, error) {
|
|||||||
if _, err := toml.DecodeFile(modFile, &mod); err != nil {
|
if _, err := toml.DecodeFile(modFile, &mod); err != nil {
|
||||||
return Mod{}, err
|
return Mod{}, err
|
||||||
}
|
}
|
||||||
mod.updaters = make(map[string]Updater)
|
mod.updateData = make(map[string]interface{})
|
||||||
// Horrible reflection library to convert to Updaters
|
// Horrible reflection library to convert map[string]interface to proper struct
|
||||||
for k, v := range mod.Update {
|
for k, v := range mod.Update {
|
||||||
updateParser, ok := UpdateParsers[k]
|
updater, ok := Updaters[k]
|
||||||
if ok {
|
if ok {
|
||||||
updater, err := updateParser.ParseUpdate(v)
|
updateData, err := updater.ParseUpdate(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mod, err
|
return mod, err
|
||||||
}
|
}
|
||||||
mod.updaters[k] = updater
|
mod.updateData[k] = updateData
|
||||||
} else {
|
} else {
|
||||||
return mod, errors.New("Update plugin " + k + " not found!")
|
return mod, errors.New("Update plugin " + k + " not found!")
|
||||||
}
|
}
|
||||||
@ -86,8 +86,8 @@ func (m Mod) Write() (string, string, error) {
|
|||||||
return "sha256", hashString, err
|
return "sha256", hashString, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetParsedUpdater can be used to retrieve updater-specific information after parsing a mod file
|
// GetParsedUpdateData can be used to retrieve updater-specific information after parsing a mod file
|
||||||
func (m Mod) GetParsedUpdater(updaterName string) (Updater, bool) {
|
func (m Mod) GetParsedUpdateData(updaterName string) (interface{}, bool) {
|
||||||
upd, ok := m.updaters[updaterName]
|
upd, ok := m.updateData[updaterName]
|
||||||
return upd, ok
|
return upd, ok
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ func init() {
|
|||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
core.UpdateParsers["curseforge"] = cfUpdateParser{}
|
core.Updaters["curseforge"] = cfUpdater{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileIDRegexes = [...]*regexp.Regexp{
|
var fileIDRegexes = [...]*regexp.Regexp{
|
||||||
@ -100,7 +100,7 @@ func createModFile(flags core.Flags, modInfo modInfo, fileInfo modFileInfo, inde
|
|||||||
updateMap := make(map[string]map[string]interface{})
|
updateMap := make(map[string]map[string]interface{})
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
updateMap["curseforge"], err = cfUpdater{
|
updateMap["curseforge"], err = cfUpdateData{
|
||||||
ProjectID: modInfo.ID,
|
ProjectID: modInfo.ID,
|
||||||
FileID: fileInfo.ID,
|
FileID: fileInfo.ID,
|
||||||
// TODO: determine update channel
|
// TODO: determine update channel
|
||||||
@ -162,11 +162,11 @@ func cmdDoc(flags core.Flags, mod string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
updateData, ok := modData.GetParsedUpdater("curseforge")
|
updateData, ok := modData.GetParsedUpdateData("curseforge")
|
||||||
if !ok {
|
if !ok {
|
||||||
return cli.NewExitError("This mod doesn't seem to be a curseforge mod!", 1)
|
return cli.NewExitError("This mod doesn't seem to be a curseforge mod!", 1)
|
||||||
}
|
}
|
||||||
cfUpdateData := updateData.(cfUpdater)
|
cfUpdateData := updateData.(cfUpdateData)
|
||||||
fmt.Println("Opening browser...")
|
fmt.Println("Opening browser...")
|
||||||
url := "https://minecraft.curseforge.com/projects/" + strconv.Itoa(cfUpdateData.ProjectID)
|
url := "https://minecraft.curseforge.com/projects/" + strconv.Itoa(cfUpdateData.ProjectID)
|
||||||
err = open.Start(url)
|
err = open.Start(url)
|
||||||
@ -178,32 +178,36 @@ func cmdDoc(flags core.Flags, mod string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type cfUpdateParser struct{}
|
type cfUpdateData struct {
|
||||||
|
|
||||||
func (u cfUpdateParser) ParseUpdate(updateUnparsed map[string]interface{}) (core.Updater, error) {
|
|
||||||
var updater cfUpdater
|
|
||||||
err := mapstructure.Decode(updateUnparsed, &updater)
|
|
||||||
return updater, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type cfUpdater struct {
|
|
||||||
ProjectID int `mapstructure:"project-id"`
|
ProjectID int `mapstructure:"project-id"`
|
||||||
FileID int `mapstructure:"file-id"`
|
FileID int `mapstructure:"file-id"`
|
||||||
ReleaseChannel string `mapstructure:"release-channel"`
|
ReleaseChannel string `mapstructure:"release-channel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u cfUpdater) DoUpdate(mod core.Mod) (bool, error) {
|
func (u cfUpdateData) ToMap() (map[string]interface{}, error) {
|
||||||
|
newMap := make(map[string]interface{})
|
||||||
|
err := mapstructure.Decode(u, &newMap)
|
||||||
|
return newMap, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfUpdater struct{}
|
||||||
|
|
||||||
|
func (u cfUpdater) ParseUpdate(updateUnparsed map[string]interface{}) (interface{}, error) {
|
||||||
|
var updateData cfUpdateData
|
||||||
|
err := mapstructure.Decode(updateUnparsed, &updateData)
|
||||||
|
return updateData, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u cfUpdater) CheckUpdate(mod []core.Mod) ([]core.UpdateCheck, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u cfUpdater) DoUpdate(mod []*core.Mod, cachedState []interface{}) error {
|
||||||
// TODO: implement updating
|
// TODO: implement updating
|
||||||
// modInfoData, err := getModInfo(u.ProjectID)
|
// modInfoData, err := getModInfo(u.ProjectID)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return false, err
|
// return false, err
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return false, nil
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func (u cfUpdater) ToMap() (map[string]interface{}, error) {
|
|
||||||
newMap := make(map[string]interface{})
|
|
||||||
err := mapstructure.Decode(u, &newMap)
|
|
||||||
return newMap, err
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user