mirror of
				https://github.com/packwiz/packwiz.git
				synced 2025-10-30 18:34:31 +01:00 
			
		
		
		
	Redo update system to work with batched updates
This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
| @@ -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!! | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								core/mod.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								core/mod.go
									
									
									
									
									
								
							| @@ -20,7 +20,7 @@ type Mod struct { | |||||||
| 	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 |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user