diff --git a/core/index.go b/core/index.go index 6a52f3e..87b16dc 100644 --- a/core/index.go +++ b/core/index.go @@ -75,6 +75,48 @@ func (in *Index) resortIndex() { }) } +func (in *Index) updateFileHashGiven(path, format, hash string, mod bool) error { + // Find in index + found := false + relPath, err := filepath.Rel(filepath.Dir(in.indexFile), path) + if err != nil { + return err + } + for k, v := range in.Files { + if filepath.Clean(filepath.FromSlash(v.File)) == relPath { + found = true + // Update hash + in.Files[k].Hash = hash + if in.HashFormat == format { + in.Files[k].HashFormat = "" + } else { + in.Files[k].HashFormat = format + } + // Mark this file as found + in.Files[k].fileExistsTemp = true + // Clean up path if it's untidy + in.Files[k].File = filepath.ToSlash(relPath) + // Don't break out of loop, as there may be aliased versions that + // also need to be updated + } + } + if !found { + newFile := IndexFile{ + File: filepath.ToSlash(relPath), + Hash: hash, + fileExistsTemp: true, + } + // Override hash format for this file, if the whole index isn't sha256 + if in.HashFormat != format { + newFile.HashFormat = format + } + newFile.MetaFile = mod + + in.Files = append(in.Files, newFile) + } + return nil +} + // updateFile calculates the hash for a given path and updates it in the index func (in *Index) updateFile(path string) error { f, err := os.Open(path) @@ -92,58 +134,22 @@ func (in *Index) updateFile(path string) error { } hashString := hex.EncodeToString(h.Sum(nil)) - // Find in index - found := false - relPath, err := filepath.Rel(filepath.Dir(in.indexFile), path) - if err != nil { - return err - } - for k, v := range in.Files { - if filepath.Clean(filepath.FromSlash(v.File)) == relPath { - found = true - // Update hash - in.Files[k].Hash = hashString - if in.HashFormat == "sha256" { - in.Files[k].HashFormat = "" - } else { - in.Files[k].HashFormat = "sha256" - } - // Mark this file as found - in.Files[k].fileExistsTemp = true - // Clean up path if it's untidy - in.Files[k].File = filepath.ToSlash(relPath) - // Don't break out of loop, as there may be aliased versions that - // also need to be updated - } - } - if !found { - newFile := IndexFile{ - File: filepath.ToSlash(relPath), - Hash: hashString, - fileExistsTemp: true, - } - // Override hash format for this file, if the whole index isn't sha256 - if in.HashFormat != "sha256" { - newFile.HashFormat = "sha256" - } - // If the file is in the mods folder, set MetaFile to true (mods are metafiles by default) - // This is incredibly powerful: you can put a normal jar in the mods folder just by - // setting MetaFile to false. Or you can use the "mod" metadata system for other types - // of files, like CraftTweaker resources. - absFileDir, err := filepath.Abs(filepath.Dir(path)) + mod := false + // If the file is in the mods folder, set MetaFile to true (mods are metafiles by default) + // This is incredibly powerful: you can put a normal jar in the mods folder just by + // setting MetaFile to false. Or you can use the "mod" metadata system for other types + // of files, like CraftTweaker resources. + absFileDir, err := filepath.Abs(filepath.Dir(path)) + if err == nil { + absModsDir, err := filepath.Abs(in.flags.ModsFolder) if err == nil { - absModsDir, err := filepath.Abs(in.flags.ModsFolder) - if err == nil { - if absFileDir == absModsDir { - newFile.MetaFile = true - } + if absFileDir == absModsDir { + mod = true } } - - in.Files = append(in.Files, newFile) } - return nil + return in.updateFileHashGiven(path, "sha256", hashString, mod) } // Refresh updates the hashes of all the files in the index, and adds new files to the index @@ -250,3 +256,12 @@ func (in Index) Write() error { return enc.Encode(in) } +// RefreshFileWithHash updates a file in the index, given a file hash and whether it is a mod or not +func (in *Index) RefreshFileWithHash(path, format, hash string, mod bool) error { + err := in.updateFileHashGiven(path, format, hash, mod) + if err != nil { + return err + } + in.resortIndex() + return nil +} diff --git a/core/mod.go b/core/mod.go index ca6d697..c9c3d3d 100644 --- a/core/mod.go +++ b/core/mod.go @@ -1,6 +1,10 @@ package core + import ( + "crypto/sha256" + "encoding/hex" "errors" + "io" "os" "github.com/BurntSushi/toml" @@ -58,21 +62,26 @@ func LoadMod(modFile string) (Mod, error) { } // SetMetaName sets the mod metadata file from a given file name (to be put in the mods folder) -func (m *Mod) SetMetaName(metaName string, flags Flags) { +func (m *Mod) SetMetaName(metaName string, flags Flags) string { m.metaFile = ResolveMod(metaName, flags) + return m.metaFile } -// Write saves the mod file -func (m Mod) Write() error { +// Write saves the mod file, returning a hash format and the value of the hash of the saved file +func (m Mod) Write() (string, string, error) { f, err := os.Create(m.metaFile) if err != nil { - return err + return "sha256", "", err } defer f.Close() - enc := toml.NewEncoder(f) + h := sha256.New() + w := io.MultiWriter(h, f) + + enc := toml.NewEncoder(w) // Disable indentation enc.Indent = "" - return enc.Encode(m) + err = enc.Encode(m) + hashString := hex.EncodeToString(h.Sum(nil)) + return "sha256", hashString, err } - diff --git a/curseforge/curseforge.go b/curseforge/curseforge.go index 4100cba..848c26c 100644 --- a/curseforge/curseforge.go +++ b/curseforge/curseforge.go @@ -92,7 +92,7 @@ func getModIDFromString(mod string) (bool, int, error) { return false, 0, nil } -func createModFile(flags core.Flags, modInfo modInfo, fileInfo modFileInfo) error { +func createModFile(flags core.Flags, modInfo modInfo, fileInfo modFileInfo, index *core.Index) error { updateMap := make(map[string]map[string]interface{}) var err error @@ -100,7 +100,7 @@ func createModFile(flags core.Flags, modInfo modInfo, fileInfo modFileInfo) erro ProjectID: modInfo.ID, FileID: fileInfo.ID, // TODO: determine update channel - ReleaseChannel: "release", + ReleaseChannel: "beta", }.ToMap() if err != nil { return err @@ -119,15 +119,20 @@ func createModFile(flags core.Flags, modInfo modInfo, fileInfo modFileInfo) erro }, Update: updateMap, } - modMeta.SetMetaName(modInfo.Slug, flags) + path := modMeta.SetMetaName(modInfo.Slug, flags) // If the file already exists, this will overwrite it!!! // TODO: Should this be improved? // Current strategy is to go ahead and do stuff without asking, with the assumption that you are using // VCS anyway. - // TODO: add to index - return modMeta.Write() + format, hash, err := modMeta.Write() + if err != nil { + return err + } + + // TODO: send written data directly to index, instead of write+read? + return index.RefreshFileWithHash(path, format, hash, true) } func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error { @@ -234,9 +239,6 @@ func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error { } } - fmt.Println(modInfoData) - _ = index - if fileID == 0 { fmt.Println("WIP: get an actual file ID!!!") return nil @@ -247,11 +249,18 @@ func cmdInstall(flags core.Flags, mod string, modArgsTail []string) error { return cli.NewExitError(err, 1) } - err = createModFile(flags, modInfoData, fileInfo) + err = createModFile(flags, modInfoData, fileInfo, &index) if err != nil { return cli.NewExitError(err, 1) } + err = index.Write() + if err != nil { + return cli.NewExitError(err, 1) + } + + fmt.Printf("Mod \"%s\" successfully installed!\n", modInfoData.Name) + return nil } diff --git a/curseforge/import.go b/curseforge/import.go index fcba61e..81baa56 100644 --- a/curseforge/import.go +++ b/curseforge/import.go @@ -43,6 +43,15 @@ type twitchPackMeta struct { } func cmdImport(flags core.Flags, file string) error { + pack, err := core.LoadPack(flags) + if err != nil { + return cli.NewExitError(err, 1) + } + index, err := pack.LoadIndex() + if err != nil { + return cli.NewExitError(err, 1) + } + var packMeta twitchPackMeta // TODO: is this relative to something? f, err := os.Open(file) @@ -83,14 +92,19 @@ func cmdImport(flags core.Flags, file string) error { continue } - fmt.Printf("Imported \"%s\" successfully!\n", modInfoValue.Name) + fmt.Printf("Imported mod \"%s\" successfully!\n", modInfoValue.Name) - err = createModFile(flags, modInfoValue, modFileInfo(v.File)) + err = createModFile(flags, modInfoValue, modFileInfo(v.File), &index) if err != nil { return cli.NewExitError(err, 1) } } + err = index.Write() + if err != nil { + return cli.NewExitError(err, 1) + } + // TODO: import existing files (config etc.) return nil