From 49d7b26b2e67ae843688d4a0bb7525d1826c3571 Mon Sep 17 00:00:00 2001
From: comp500 <comp500@users.noreply.github.com>
Date: Tue, 4 May 2021 19:56:56 +0100
Subject: [PATCH] Add no-internal-hashes mode

---
 README.md            |  4 +++-
 cmd/init.go          |  2 +-
 cmd/refresh.go       |  9 ++++++++
 core/index.go        | 52 +++++++++++++++++++++++++-------------------
 core/pack.go         |  8 ++++++-
 curseforge/import.go |  2 +-
 6 files changed, 51 insertions(+), 26 deletions(-)

diff --git a/README.md b/README.md
index 7b34d5a..b439979 100644
--- a/README.md
+++ b/README.md
@@ -77,4 +77,6 @@ For use on servers, add the `-g` flag to disable the GUI and `-s server` to down
 ## Options
 - Additional options can be configured in the `[options]` section of `pack.toml`, as follows:
     - `mods-folder` The folder to save mod metadata files into, for the install commands
-    - `acceptable-game-versions` A list of additional Minecraft versions to accept when installing or updating mods
\ No newline at end of file
+    - `acceptable-game-versions` A list of additional Minecraft versions to accept when installing or updating mods
+    - `no-internal-hashes` If this is set to true, packwiz will not generate hashes of local files, to prevent merge conflicts and inconsistent hashes when using git/etc.
+        - `packwiz refresh --build` can be used in this mode to generate internal hashes for distributing the pack with packwiz-installer
\ No newline at end of file
diff --git a/cmd/init.go b/cmd/init.go
index 8f607d7..d284a62 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -157,7 +157,7 @@ var initCmd = &cobra.Command{
 			Index: struct {
 				File       string `toml:"file"`
 				HashFormat string `toml:"hash-format"`
-				Hash       string `toml:"hash"`
+				Hash       string `toml:"hash,omitempty"`
 			}{
 				File: indexFilePath,
 			},
diff --git a/cmd/refresh.go b/cmd/refresh.go
index 8a56557..f6807e4 100644
--- a/cmd/refresh.go
+++ b/cmd/refresh.go
@@ -2,6 +2,7 @@ package cmd
 
 import (
 	"fmt"
+	"github.com/spf13/viper"
 	"os"
 
 	"github.com/comp500/packwiz/core"
@@ -20,6 +21,12 @@ var refreshCmd = &cobra.Command{
 			fmt.Println(err)
 			os.Exit(1)
 		}
+		build, err := cmd.Flags().GetBool("build")
+		if err == nil && build {
+			viper.Set("no-internal-hashes", false)
+		} else if viper.GetBool("no-internal-hashes") {
+			fmt.Println("Note: no-internal-hashes mode is set, no hashes will be saved. Use --build to override this for distribution.")
+		}
 		index, err := pack.LoadIndex()
 		if err != nil {
 			fmt.Println(err)
@@ -51,4 +58,6 @@ var refreshCmd = &cobra.Command{
 
 func init() {
 	rootCmd.AddCommand(refreshCmd)
+
+	refreshCmd.Flags().Bool("build", false, "Only has an effect in no-internal-hashes mode: generates internal hashes for distribution with packwiz-installer")
 }
diff --git a/core/index.go b/core/index.go
index 83fa2f7..968f035 100644
--- a/core/index.go
+++ b/core/index.go
@@ -28,7 +28,7 @@ type Index struct {
 type IndexFile struct {
 	// Files are stored in forward-slash format relative to the index file
 	File           string `toml:"file"`
-	Hash           string `toml:"hash"`
+	Hash           string `toml:"hash,omitempty"`
 	HashFormat     string `toml:"hash-format,omitempty"`
 	Alias          string `toml:"alias,omitempty"`
 	MetaFile       bool   `toml:"metafile,omitempty"` // True when it is a .toml metadata file
@@ -121,28 +121,33 @@ func (in *Index) updateFileHashGiven(path, format, hash string, mod bool) error
 
 // 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)
-	if err != nil {
-		return err
-	}
+	var hashString string
+	if viper.GetBool("no-internal-hashes") {
+		hashString = ""
+	} else {
+		f, err := os.Open(path)
+		if err != nil {
+			return err
+		}
 
-	// Hash usage strategy (may change):
-	// Just use SHA256, overwrite existing hash regardless of what it is
-	// May update later to continue using the same hash that was already being used
-	h, err := GetHashImpl("sha256")
-	if err != nil {
-		_ = f.Close()
-		return err
+		// Hash usage strategy (may change):
+		// Just use SHA256, overwrite existing hash regardless of what it is
+		// May update later to continue using the same hash that was already being used
+		h, err := GetHashImpl("sha256")
+		if err != nil {
+			_ = f.Close()
+			return err
+		}
+		if _, err := io.Copy(h, f); err != nil {
+			_ = f.Close()
+			return err
+		}
+		err = f.Close()
+		if err != nil {
+			return err
+		}
+		hashString = hex.EncodeToString(h.Sum(nil))
 	}
-	if _, err := io.Copy(h, f); err != nil {
-		_ = f.Close()
-		return err
-	}
-	err = f.Close()
-	if err != nil {
-		return err
-	}
-	hashString := hex.EncodeToString(h.Sum(nil))
 
 	mod := false
 	// If the file has an extension of toml and is in the mods folder, set mod to true
@@ -290,6 +295,9 @@ func (in Index) Write() error {
 
 // 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 {
+	if viper.GetBool("no-internal-hashes") {
+		hash = ""
+	}
 	err := in.updateFileHashGiven(path, format, hash, mod)
 	if err != nil {
 		return err
@@ -351,7 +359,7 @@ func (in Index) SaveFile(f IndexFile, dest io.Writer) error {
 	}
 
 	calculatedHash := hex.EncodeToString(h.Sum(nil))
-	if calculatedHash != f.Hash {
+	if calculatedHash != f.Hash && !viper.GetBool("no-internal-hashes") {
 		return errors.New("hash of saved file is invalid")
 	}
 
diff --git a/core/pack.go b/core/pack.go
index 06f7fd0..15df170 100644
--- a/core/pack.go
+++ b/core/pack.go
@@ -20,7 +20,7 @@ type Pack struct {
 		// Path is stored in forward slash format relative to pack.toml
 		File       string `toml:"file"`
 		HashFormat string `toml:"hash-format"`
-		Hash       string `toml:"hash"`
+		Hash       string `toml:"hash,omitempty"`
 	} `toml:"index"`
 	Versions map[string]string                 `toml:"versions"`
 	Client   map[string]toml.Primitive         `toml:"client"`
@@ -61,6 +61,12 @@ func (pack Pack) LoadIndex() (Index, error) {
 
 // UpdateIndexHash recalculates the hash of the index file of this modpack
 func (pack *Pack) UpdateIndexHash() error {
+	if viper.GetBool("no-internal-hashes") {
+		pack.Index.HashFormat = "sha256"
+		pack.Index.Hash = ""
+		return nil
+	}
+
 	fileNative := filepath.FromSlash(pack.Index.File)
 	indexFile := filepath.Join(filepath.Dir(viper.GetString("pack-file")), fileNative)
 	if filepath.IsAbs(pack.Index.File) {
diff --git a/curseforge/import.go b/curseforge/import.go
index e81027c..be52f4d 100644
--- a/curseforge/import.go
+++ b/curseforge/import.go
@@ -158,7 +158,7 @@ var importCmd = &cobra.Command{
 				Index: struct {
 					File       string `toml:"file"`
 					HashFormat string `toml:"hash-format"`
-					Hash       string `toml:"hash"`
+					Hash       string `toml:"hash,omitempty"`
 				}{
 					File: indexFilePath,
 				},