Skip to content

Commit

Permalink
Fixing Logging, Updating for 1.18.2, Documentation Update, Minor bug …
Browse files Browse the repository at this point in the history
…fixing (#6)

Co-authored-by: christopher blodgett <christopher.blodgett@gmail.com>
  • Loading branch information
shotah and christopher blodgett authored Feb 28, 2022
1 parent 0374537 commit 2204980
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
### Personal Development Script and Environment ###
personal-build-and-develop.*
.env
test.json
46 changes: 32 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
# ForgeCLI
# ForgeCLI Guide

Package was created with the express intent to remove the guess work out of Mod acquiring and updating.

## Getting Your Forge API Key
## Getting Your Forge API Key:

This is more complicated because you will be pulling/using the latest mod for the release of your game. To get started make sure you have a [CursedForge API Key](https://docs.curseforge.com/#getting-started). Then use it as a parameter for your build

## Quick start
## Basic Run:

Simple command to download latest fabric modules:

```bash
. ./forgecli.exe -forgekey '$2a$10...' -projects "416089,391366,552655" -family "fabric" -debug
```

## ForgeCLI Usage Details
## Example Outputs:

**Example Successful Run**

```bash
time="2022-02-28T09:37:51-08:00" level=info msg="Starting Forge Mod lookup"
time="2022-02-28T09:37:51-08:00" level=info msg="Found Lastest FileID: 3667363 for Mod: 416089"
time="2022-02-28T09:37:51-08:00" level=info msg="Downloading: https://edge.forgecdn.net/files/3667/363/voicechat-fabric-1.18.2-2.2.24.jar"
time="2022-02-28T09:37:52-08:00" level=info msg="Files in Destination Folder:"
time="2022-02-28T09:37:52-08:00" level=info msg=" voicechat-fabric-1.18.2-2.2.24.jar "
time="2022-02-28T09:37:52-08:00" level=info msg="Download Complete."
```

**Example Failed Run**

```bash
time="2022-02-28T09:52:14-08:00" level=info msg="Starting Forge Mod Lookup"
time="2022-02-28T09:52:14-08:00" level=error msg="could not find 391366 for minecraft version: 1.18.2 or family: fabric"
time="2022-02-28T09:52:14-08:00" level=error msg=Exiting...
```

## ForgeCLI Usage:

**NOTE:** Due to the lack of Version pinning this can lead to unexpected behavior if the publisher updates mod unexpectedly.

Expand All @@ -26,7 +47,7 @@ To get started make sure you have a [CursedForge API Key](https://docs.curseforg
- `Mac:` "~/Library/Application Support/minecraft/mods"
- `Linux:` "~/Library/Application Support/minecraft/mods"

**Mod basics**
**Mod Basics**

- `Mod Release types:` Release, Beta, and Alpha.
- `Mod dependencies:` Required and Optional
Expand All @@ -42,8 +63,8 @@ To get started make sure you have a [CursedForge API Key](https://docs.curseforg
- `family:` Used to filter mods based on server type. Options are Forge, Fabric, and Bukkit
- `release:` Default is Release, Used to allow for Beta and Alpha mod downloads.
- `version:` Default is LATEST, but this is Minecraft VERSION. e.g. 1.18.2
- `clearMods:` Default is false, allows CLI to remove all mods before downloading new Mods.
- `downloadDependencies:` Default is True, this uses the mods required dependencies to download missing mods.
- `clear:` Default is false, allows CLI to remove all mods before downloading new Mods.
- `dependencies:` Default is True, this uses the mods required dependencies to download missing mods.
- `debug:` Enable extra logging.

## JSON File usage:
Expand All @@ -56,7 +77,6 @@ To get started make sure you have a [CursedForge API Key](https://docs.curseforg

**Field Description**


- `name:` is currently unused, but can be used to document each entry.
- `projectID:` is the id found on the CurseForge website for a particular mod
- `releaseType:` Type corresponds to forge's R, B, A icon for each file. Default Release, options are (release|beta|alpha).
Expand All @@ -79,13 +99,13 @@ To get started make sure you have a [CursedForge API Key](https://docs.curseforg
{
"name": "Biomes o plenty",
"projectID": "220318",
"fileName": "BiomesOPlenty-1.18.1-15.0.0.100-universal.jar",
"fileName": "BiomesOPlenty-1.18.2-15.0.0.100-universal.jar",
"releaseType": "release"
}
]
```

### Manually Building and Testing
## Manually Building and Testing:

Make a `./.env` file in the root folder and add your forge key.

Expand All @@ -106,8 +126,6 @@ go build
# . ./forgecli should now be available to be used.
```

### TODO List
## TODO List:

- Update and proof read documentation
- Add normal info logging. Currently the app runs silent without -debug
- add fileName filter from json mods. Currently we have no method to pin versions
- add fileName filter from json mods. Currently we have no method to pin versions.
19 changes: 19 additions & 0 deletions forgecli/forgeapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ var releaseLookup = map[string]ReleaseType{
"alpha": Alpha,
}

// FamilyType string declaration
type FamilyType string

const (
// Fabric used for validating we are using the correct family types
Fabric FamilyType = "fabric"
// Bukkit used for validating we are using the correct family types
Bukkit FamilyType = "bukkit"
// Forge used for validating we are using the correct family types
Forge FamilyType = "forge"
)

// familyTypeLookup used when accepting strings and converting to ints
var familyTypeLookup = map[string]FamilyType{
"fabric": Fabric,
"bukkit": Bukkit,
"forge": Forge,
}

// ForgePagination was to be used with Pagination, currently not used
type ForgePagination struct {
Index int `json:"index"`
Expand Down
50 changes: 33 additions & 17 deletions forgecli/forgecli.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type appEnv struct {
projectIDs string
downloadDependencies bool
clearMods bool
modfamily string
modfamily FamilyType
modReleaseType ReleaseType
destination string
modsFromJSON JSONMods
Expand All @@ -55,20 +55,27 @@ func (app *appEnv) fromArgs(args []string) error {
fl.BoolVar(&app.downloadDependencies, "dependencies", true, "Download Mods Dependencies")
fl.BoolVar(&app.clearMods, "clear", false, "Clear Mods from destination (mods folder)")
fl.BoolVar(&app.isDebug, "debug", false, "enable debug logrusging")
fl.StringVar(&app.modfamily, "family", "", "Minecraft type: Vanilla, Fabric, Forge, Bukkit")
fl.StringVar(&app.projectIDs, "projects", "", "Forge Project IDs separated by commas 12345,67890")
inputReleaseType := fl.String("release", "release", "Mods release type, release, beta, alpha")
app.modReleaseType = releaseLookup[*inputReleaseType]
inputFamily := fl.String("family", "", "Minecraft type: Vanilla, Fabric, Forge, Bukkit")

// Parsing the Args before they can be used
if err := fl.Parse(args); err != nil {
return err
}

// Type Conversions
app.modReleaseType = releaseLookup[*inputReleaseType]
if len(*inputFamily) > 0 {
app.modfamily = familyTypeLookup[*inputFamily]
}

// Setting up logrus
if app.isDebug {
logrus.SetLevel(logrus.DebugLevel)
}

// Checking for Required Fields
if app.projectIDs == "" && app.jsonFile == "" {
fmt.Fprintf(os.Stderr, "Did not receive Project IDs to Download.\n")
fl.Usage()
Expand All @@ -79,7 +86,7 @@ func (app *appEnv) fromArgs(args []string) error {
}

func (app *appEnv) run() error {
logrus.Debug("Starting Run")
logrus.Info("Starting Forge Mod Lookup")
app.SetForgeAPIKey()

app.GetMCVersion()
Expand All @@ -96,7 +103,8 @@ func (app *appEnv) run() error {

app.PrepareDestinationFolder()
app.DownloadMods()
logrus.Debug("Ending Run")
app.PrintDestinationFiles()
logrus.Info("Download Complete.")
return nil
}

Expand Down Expand Up @@ -125,7 +133,8 @@ func (app *appEnv) GetModsByProjectIDs() {
projectIDs := strings.Split(app.projectIDs, ",")
for _, projectID := range projectIDs {
logrus.Debugf("Getting Mod: %s", projectID)
app.GetModsFromForge(projectID, app.modReleaseType)
err := app.GetModsFromForge(projectID, app.modReleaseType)
check(err)
}
}

Expand All @@ -140,9 +149,10 @@ func (app *appEnv) GetModsByJSONFile() {
if fileMod.ReleaseType != "" {
releaseType = releaseLookup[fileMod.ReleaseType]
} else {
releaseType = releaseLookup["release"]
releaseType = app.modReleaseType
}
app.GetModsFromForge(fileMod.ProjectID, releaseType)
err := app.GetModsFromForge(fileMod.ProjectID, releaseType)
check(err)
}
}

Expand All @@ -154,22 +164,23 @@ func (app *appEnv) GetModsDependencies() error {
for _, modDep := range mod.Dependencies {
if modDep.RelationType == 3 {
logrus.Debugf("Getting Mod dependency: %s", strconv.Itoa(modDep.ModID))
app.GetModsFromForge(strconv.Itoa(modDep.ModID), releaseLookup["release"])
err := app.GetModsFromForge(strconv.Itoa(modDep.ModID), releaseLookup["release"])
check(err)
}
}
}
return nil
}

func (app *appEnv) GetModsFromForge(modID string, releaseType ReleaseType) {
func (app *appEnv) GetModsFromForge(modID string, releaseType ReleaseType) error {
var resp ForgeMods
pageIndex := 0
pageSize := 999
url := fmt.Sprintf(
"https://api.curseforge.com/v1/mods/%s/files?gameVersionTypeID=%d&index=%d&pageSize=%d",
modID, app.forgeGameVersionType, pageIndex, pageSize,
)
err := app.fetchforgeAPIJSON(url, &resp)
err := app.FetchForgeAPIJSON(url, &resp)
check(err)

foundID := 0
Expand All @@ -180,8 +191,12 @@ func (app *appEnv) GetModsFromForge(modID string, releaseType ReleaseType) {
foundMod = currMod
}
}
if foundID == 0 {
return fmt.Errorf("could not find %s for minecraft version: %s or family: %s", modID, app.version, app.modfamily)
}
app.modsToDownload[foundID] = foundMod
logrus.Debugf("Found Lastest FileID: %d for Mod: %s", foundID, modID)
logrus.Infof("Found Lastest FileID: %d for Mod: %s", foundID, modID)
return nil
}

func (app *appEnv) ModFilter(currMod ForgeMod) bool {
Expand All @@ -199,7 +214,7 @@ func (app *appEnv) ModFilter(currMod ForgeMod) bool {

func (app *appEnv) GetMCVersion() error {
var resp MCVersionResponse
if err := app.fetchJSON(MinecraftVersionURL, &resp); err != nil {
if err := app.FetchJSON(MinecraftVersionURL, &resp); err != nil {
return fmt.Errorf("could not get minecraft version from:\n%s", MinecraftVersionURL)
}
if app.version == "" {
Expand All @@ -223,15 +238,16 @@ func (app *appEnv) GetVersionTypeNumber() error {
// Forge has a specific format to validate Minecraft 1.17
shortNumber := strings.Join(strings.Split(app.version, ".")[:2], ".")
forgeVersionName := "Minecraft " + shortNumber
logrus.Debugf("Fetching VersionType for MC version: %s, %s", forgeVersionName, ForgeVersionTypeURL)

var resp ForgeVersions
if err := app.fetchforgeAPIJSON(ForgeVersionTypeURL, &resp); err != nil {
if err := app.FetchForgeAPIJSON(ForgeVersionTypeURL, &resp); err != nil {
return err
}
for _, v := range resp.Data {
if v.Name == forgeVersionName {
returnGameVersionType := v.ID
app.forgeGameVersionType = returnGameVersionType
app.forgeGameVersionType = v.ID
logrus.Debugf("found VersionType: %d", v.ID)
return nil
}
}
Expand All @@ -241,7 +257,7 @@ func (app *appEnv) GetVersionTypeNumber() error {

func (app *appEnv) DownloadMods() error {
for _, mod := range app.modsToDownload {
if err := app.fetchAndSave(mod.DownloadURL, mod.Filename); err != nil {
if err := app.FetchAndSave(mod.DownloadURL, mod.Filename); err != nil {
return err
}
}
Expand Down
7 changes: 5 additions & 2 deletions forgecli/forgecli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"testing"

"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
)

func LoadDotEnv() {
logrus.SetLevel(logrus.DebugLevel)
if os.Getenv("FORGEKEY") == "" {
err := godotenv.Load("../.env")
check(err)
Expand All @@ -25,6 +27,7 @@ func TestCLIReturnsError(t *testing.T) {
}
}

// Test will fail as MC receives version updates
func TestGetVersionTypeNumber(t *testing.T) {
LoadDotEnv()
var app appEnv
Expand Down Expand Up @@ -83,7 +86,7 @@ func TestFetchforgeAPIJSON(t *testing.T) {
app.forgeKey = os.Getenv("FORGEKEY")
var resp ForgeMods
url := "https://api.curseforge.com/v1/mods/306612/files?gameVersionTypeID=73250&index=0&pageSize=3"
if err := app.fetchforgeAPIJSON(url, &resp); err != nil {
if err := app.FetchForgeAPIJSON(url, &resp); err != nil {
t.Errorf("Test failed, by throwing error")
}
fmt.Println(resp.Data[0].DisplayName)
Expand All @@ -93,7 +96,7 @@ func TestGetMCVersionNoInput(t *testing.T) {
var app appEnv
app.hc = *http.DefaultClient
app.version = ""
expected := "1.18.1"
expected := "1.18.2"
app.GetMCVersion()
if app.version != expected {
t.Errorf("Test failed, expected: '%s', got: '%s'", expected, app.version)
Expand Down
Loading

0 comments on commit 2204980

Please sign in to comment.