mirror of
https://github.com/packwiz/packwiz.git
synced 2025-04-19 21:16:30 +02:00
Add cf detect command (experimental but should mostly work)
This commit is contained in:
parent
48971d7b5a
commit
4d4f0d143e
148
curseforge/detect.go
Normal file
148
curseforge/detect.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package curseforge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/aviddiviner/go-murmur"
|
||||||
|
"github.com/comp500/packwiz/core"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: make all of this less bad and hardcoded
|
||||||
|
|
||||||
|
// detectCmd represents the detect command
|
||||||
|
var detectCmd = &cobra.Command{
|
||||||
|
Use: "detect",
|
||||||
|
Short: "Detect .jar files in the mods folder (experimental)",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("Loading modpack...")
|
||||||
|
pack, err := core.LoadPack()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
index, err := pack.LoadIndex()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk files in the mods folder
|
||||||
|
var hashes []int
|
||||||
|
modPaths := make(map[int]string)
|
||||||
|
err = filepath.Walk("mods", func(path string, info os.FileInfo, err error) error {
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(path, ".jar") {
|
||||||
|
// TODO: make this less bad
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Println("Hashing " + path)
|
||||||
|
bytes, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hash := getByteArrayHash(bytes)
|
||||||
|
hashes = append(hashes, int(hash))
|
||||||
|
modPaths[int(hash)] = path
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Found %d files, submitting...\n", len(hashes))
|
||||||
|
|
||||||
|
res, err := getFingerprintInfo(hashes)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Successfully matched %d files\n", len(res.ExactFingerprints))
|
||||||
|
if len(res.PartialMatches) > 0 {
|
||||||
|
fmt.Println("The following fingerprints were partial and I don't know what to do!!!")
|
||||||
|
for _, v := range res.PartialMatches {
|
||||||
|
fmt.Printf("%s (%d)", modPaths[v], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(res.UnmatchedFingerprints) > 0 {
|
||||||
|
fmt.Printf("Failed to match the following %d files:\n", len(res.UnmatchedFingerprints))
|
||||||
|
for _, v := range res.UnmatchedFingerprints {
|
||||||
|
fmt.Printf("%s (%d)\n", modPaths[v], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Installing...")
|
||||||
|
for _, v := range res.ExactMatches {
|
||||||
|
modInfoData, err := getModInfo(v.ID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = createModFile(modInfoData, v.File, &index)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
path, ok := modPaths[v.File.Fingerprint]
|
||||||
|
if ok {
|
||||||
|
err = os.Remove(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Installation done")
|
||||||
|
|
||||||
|
err = index.Refresh()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = index.Write()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = pack.UpdateIndexHash()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = pack.Write()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
curseforgeCmd.AddCommand(detectCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getByteArrayHash(bytes []byte) uint64 {
|
||||||
|
return uint64(murmur.MurmurHash2(computeNormalizedArray(bytes), 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func computeNormalizedArray(bytes []byte) []byte {
|
||||||
|
var newArray []byte
|
||||||
|
for _, b := range bytes {
|
||||||
|
if !isWhitespaceCharacter(b) {
|
||||||
|
newArray = append(newArray, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func isWhitespaceCharacter(b byte) bool {
|
||||||
|
return b == 9 || b == 10 || b == 13 || b == 32
|
||||||
|
}
|
@ -291,3 +291,49 @@ func getSearch(searchText string, gameVersion string) ([]modInfo, error) {
|
|||||||
|
|
||||||
return infoRes, nil
|
return infoRes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type addonFingerprintResponse struct {
|
||||||
|
IsCacheBuilt bool `json:"isCacheBuilt"`
|
||||||
|
ExactMatches []struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
File modFileInfo `json:"file"`
|
||||||
|
LatestFiles []modFileInfo `json:"latestFiles"`
|
||||||
|
} `json:"exactMatches"`
|
||||||
|
ExactFingerprints []int `json:"exactFingerprints"`
|
||||||
|
PartialMatches []int `json:"partialMatches"`
|
||||||
|
PartialMatchFingerprints struct{} `json:"partialMatchFingerprints"`
|
||||||
|
InstalledFingerprints []int `json:"installedFingerprints"`
|
||||||
|
UnmatchedFingerprints []int `json:"unmatchedFingerprints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFingerprintInfo(hashes []int) (addonFingerprintResponse, error) {
|
||||||
|
var infoRes addonFingerprintResponse
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
hashesData, err := json.Marshal(hashes)
|
||||||
|
if err != nil {
|
||||||
|
return addonFingerprintResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", "https://addons-ecs.forgesvc.net/api/v2/fingerprint", bytes.NewBuffer(hashesData))
|
||||||
|
if err != nil {
|
||||||
|
return addonFingerprintResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this configurable application-wide
|
||||||
|
req.Header.Set("User-Agent", "comp500/packwiz client")
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return addonFingerprintResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&infoRes)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return addonFingerprintResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return infoRes, nil
|
||||||
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -2,6 +2,7 @@ module github.com/comp500/packwiz
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v0.3.1
|
github.com/BurntSushi/toml v0.3.1
|
||||||
|
github.com/aviddiviner/go-murmur v0.0.0-20150519214947-b9740d71e571
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
|
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
|
||||||
github.com/daviddengcn/go-colortext v0.0.0-20180409174941-186a3d44e920 // indirect
|
github.com/daviddengcn/go-colortext v0.0.0-20180409174941-186a3d44e920 // indirect
|
||||||
github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817
|
github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817
|
||||||
|
2
go.sum
2
go.sum
@ -7,6 +7,8 @@ github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmx
|
|||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/aviddiviner/go-murmur v0.0.0-20150519214947-b9740d71e571 h1:seCdAEDyB0Hti/v1VajB7pAOIk9zmz/0/KE0D0oFqnc=
|
||||||
|
github.com/aviddiviner/go-murmur v0.0.0-20150519214947-b9740d71e571/go.mod h1:VzSzsYCY3W9xWYWD8T2GLDidWTe5rTZv+UdDMGhLfjg=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user