Version fetching refactoring (#373)

* Put modloader version data in struct for legibility

* Create modloader map from list

This is a minor change, but it prevents any errors with the keys not being equal to the modloader's Name field

* Less anonymous functions in modloader version retrieval

With previous code, almost everything was lazy and returned a function. Changed this to only have anonymous function in the modloader definitions, and the rest of the functions all just execute their results immediately instead or returning a function. Makes for a bit more legible code.

* Simplify FetchMavenVersionFiltered

* Rewrite version retrieval

* Use Errorf in versionutil

* Remove httpclient parameter

turned out not to be needed

* Add testing for version retrieval

* Explain fetchMavenWithFilterMap
This commit is contained in:
TheEpicBlock
2026-02-18 23:01:04 +01:00
committed by GitHub
parent 52b123018f
commit 945f852259
12 changed files with 1123 additions and 179 deletions

View File

@@ -3,6 +3,7 @@ package cmd
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"maps"
"os" "os"
"path/filepath" "path/filepath"
"slices" "slices"
@@ -89,7 +90,7 @@ var initCmd = &cobra.Command{
modLoaderVersions := make(map[string]string) modLoaderVersions := make(map[string]string)
if modLoaderName != "none" { if modLoaderName != "none" {
if ok { if ok {
versions, latestVersion, err := loader.VersionListGetter(mcVersion) versionData, err := core.DoQuery(core.MakeQuery(loader, mcVersion))
if err != nil { if err != nil {
fmt.Printf("Error loading versions: %s\n", err) fmt.Printf("Error loading versions: %s\n", err)
os.Exit(1) os.Exit(1)
@@ -97,9 +98,9 @@ var initCmd = &cobra.Command{
componentVersion := viper.GetString("init." + loader.Name + "-version") componentVersion := viper.GetString("init." + loader.Name + "-version")
if len(componentVersion) == 0 { if len(componentVersion) == 0 {
if viper.GetBool("init." + loader.Name + "-latest") { if viper.GetBool("init." + loader.Name + "-latest") {
componentVersion = latestVersion componentVersion = versionData.Latest
} else { } else {
componentVersion = initReadValue(loader.FriendlyName+" version ["+latestVersion+"]: ", latestVersion) componentVersion = initReadValue(loader.FriendlyName+" version ["+versionData.Latest+"]: ", versionData.Latest)
} }
} }
v := componentVersion v := componentVersion
@@ -108,7 +109,7 @@ var initCmd = &cobra.Command{
if loader.Name == "forge" || (loader.Name == "neoforge" && mcVersion == "1.20.1") { if loader.Name == "forge" || (loader.Name == "neoforge" && mcVersion == "1.20.1") {
v = cmdshared.GetRawForgeVersion(componentVersion) v = cmdshared.GetRawForgeVersion(componentVersion)
} }
if !slices.Contains(versions, v) { if !slices.Contains(versionData.Versions, v) {
fmt.Println("Given " + loader.FriendlyName + " version cannot be found!") fmt.Println("Given " + loader.FriendlyName + " version cannot be found!")
os.Exit(1) os.Exit(1)
} }
@@ -116,13 +117,8 @@ var initCmd = &cobra.Command{
} else { } else {
fmt.Println("Given mod loader is not supported! Use \"none\" to specify no modloader, or to configure one manually.") fmt.Println("Given mod loader is not supported! Use \"none\" to specify no modloader, or to configure one manually.")
fmt.Print("The following mod loaders are supported: ") fmt.Print("The following mod loaders are supported: ")
keys := make([]string, len(core.ModLoaders)) loader_names := slices.Collect(maps.Keys(core.ModLoaders))
i := 0 fmt.Println(strings.Join(loader_names, ", "))
for k := range core.ModLoaders {
keys[i] = k
i++
}
fmt.Println(strings.Join(keys, ", "))
os.Exit(1) os.Exit(1)
} }
} }

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>net.fabricmc</groupId>
<artifactId>fabric-loader</artifactId>
<versioning>
<latest>0.17.3</latest>
<release>0.17.3</release>
<versions>
<version>0.1.0.48</version>
<version>0.1.0.49</version>
<version>0.1.0.50</version>
<version>0.1.0.51</version>
<version>0.1.0.52</version>
<version>0.2.0.53</version>
<version>0.2.0.54</version>
<version>0.2.0.55</version>
<version>0.2.0.56</version>
<version>0.2.0.57</version>
<version>0.2.0.58</version>
<version>0.2.0.59</version>
<version>0.2.0.60</version>
<version>0.2.0.61</version>
<version>0.2.0.62</version>
<version>0.3.3.99</version>
<version>0.3.3.100</version>
<version>0.3.3.101</version>
<version>0.3.3.102</version>
<version>0.3.7.109</version>
<version>0.3.7.110</version>
<version>0.3.7.111</version>
<version>0.4.0+build.112</version>
<version>0.4.0+build.113</version>
<version>0.4.0+build.114</version>
<version>0.4.0+build.115</version>
<version>0.4.0+build.116</version>
<version>0.4.1+build.122</version>
<version>0.4.1+build.123</version>
<version>0.4.1+build.124</version>
<version>0.4.1+build.127</version>
<version>0.9.1+build.205</version>
<version>0.9.2+build.206</version>
<version>0.9.3+build.207</version>
<version>0.10.0+build.208</version>
<version>0.10.1+build.209</version>
<version>0.10.2+build.210</version>
<version>0.10.5+build.213</version>
<version>0.10.6+build.214</version>
<version>0.10.7</version>
<version>0.10.8</version>
<version>0.11.0</version>
<version>0.11.1</version>
<version>0.11.2</version>
<version>0.11.3</version>
<version>0.11.5</version>
<version>0.12.4</version>
<version>0.12.5</version>
<version>0.12.6</version>
<version>0.12.7</version>
<version>0.12.8</version>
<version>0.12.9</version>
<version>0.12.10</version>
<version>0.12.11</version>
<version>0.12.12</version>
<version>0.13.0</version>
<version>0.13.1</version>
<version>0.13.2</version>
<version>0.13.3</version>
<version>0.14.0</version>
<version>0.14.4</version>
<version>0.14.5</version>
<version>0.14.6</version>
<version>0.14.7</version>
<version>0.14.8</version>
<version>0.14.9</version>
<version>0.14.10</version>
<version>0.14.11</version>
<version>0.14.12</version>
<version>0.14.13</version>
<version>0.14.14</version>
<version>0.14.19</version>
<version>0.14.20</version>
<version>0.14.21</version>
<version>0.14.22</version>
<version>0.14.23</version>
<version>0.14.24</version>
<version>0.14.25</version>
<version>0.15.0</version>
<version>0.15.8</version>
<version>0.15.9</version>
<version>0.15.10</version>
<version>0.15.11</version>
<version>0.16.0</version>
<version>0.16.1</version>
<version>0.16.2</version>
<version>0.16.3</version>
<version>0.16.11</version>
<version>0.16.12</version>
<version>0.16.13</version>
<version>0.16.14</version>
<version>0.17.0</version>
<version>0.17.1</version>
<version>0.17.2</version>
<version>0.17.3</version>
</versions>
<lastUpdated>20251009160949</lastUpdated>
</versioning>
</metadata>

View File

@@ -0,0 +1,290 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>net.minecraftforge</groupId>
<artifactId>forge</artifactId>
<versioning>
<latest>1.21.10-60.0.14</latest>
<release>1.21.10-60.0.14</release>
<versions>
<version>1.21-51.0.33</version>
<version>1.21-51.0.32</version>
<version>1.21-51.0.21</version>
<version>1.21-51.0.18</version>
<version>1.21-51.0.17</version>
<version>1.21-51.0.16</version>
<version>1.21-51.0.15</version>
<version>1.21-51.0.13</version>
<version>1.21-51.0.8</version>
<version>1.21-51.0.7</version>
<version>1.21-51.0.6</version>
<version>1.21-51.0.5</version>
<version>1.21-51.0.4</version>
<version>1.21-51.0.3</version>
<version>1.21-51.0.1</version>
<version>1.21-51.0.0</version>
<version>1.21.8-58.0.3</version>
<version>1.21.8-58.0.2</version>
<version>1.21.8-58.0.1</version>
<version>1.21.8-58.0.0</version>
<version>1.21.7-57.0.3</version>
<version>1.21.7-57.0.2</version>
<version>1.21.5-55.0.17</version>
<version>1.21.1-52.0.0</version>
<version>1.20-46.0.14</version>
<version>1.20-46.0.11</version>
<version>1.20-46.0.10</version>
<version>1.20-46.0.2</version>
<version>1.20-46.0.1</version>
<version>1.20.6-50.2.1</version>
<version>1.20.6-50.2.0</version>
<version>1.20.6-50.1.51</version>
<version>1.19-41.0.98</version>
<version>1.19.2-43.2.21</version>
<version>1.18.2-40.1.92</version>
<version>1.16.1-32.0.10</version>
<version>1.16.1-32.0.9</version>
<version>1.16.1-32.0.8</version>
<version>1.16.1-32.0.7</version>
<version>1.16.1-32.0.6</version>
<version>1.16.1-32.0.2</version>
<version>1.16.1-32.0.1</version>
<version>1.15-29.0.4</version>
<version>1.15-29.0.3</version>
<version>1.15-29.0.2</version>
<version>1.15-29.0.1</version>
<version>1.15-29.0.0</version>
<version>1.15.2-31.2.57</version>
<version>1.14.3-27.0.3</version>
<version>1.14.3-27.0.2</version>
<version>1.14.3-27.0.1</version>
<version>1.14.3-27.0.0</version>
<version>1.14.2-26.0.63</version>
<version>1.14.2-26.0.62</version>
<version>1.14.2-26.0.61</version>
<version>1.14.2-26.0.60</version>
<version>1.12-14.21.0.2324</version>
<version>1.12-14.21.0.2323</version>
<version>1.12-14.21.0.2322</version>
<version>1.12-14.21.0.2320</version>
<version>1.12.2-14.23.5.2860</version>
<version>1.12.2-14.23.4.2721</version>
<version>1.12.2-14.23.4.2720-4627</version>
<version>1.12.2-14.23.4.2719</version>
<version>1.12.1-14.22.0.2444</version>
<version>1.11-13.19.1.2199</version>
<version>1.11-13.19.0.2130</version>
<version>1.11-13.19.0.2129-1.11.x</version>
<version>1.11-13.19.0.2128-1.11.x</version>
<version>1.11-13.19.0.2127-1.11.x</version>
<version>1.11-13.19.0.2126-1.11.x</version>
<version>1.11.2-13.20.1.2588</version>
<version>1.11.2-13.20.0.2245-3630</version>
<version>1.11.2-13.20.0.2244</version>
<version>1.11.2-13.20.0.2200</version>
<version>1.10-12.18.0.2000-1.10.0</version>
<version>1.10-12.18.0.1999-1.10.0</version>
<version>1.10-12.18.0.1981-1.10.0</version>
<version>1.10.2-12.18.3.2511</version>
<version>1.10.2-12.18.3.2488</version>
<version>1.10.2-12.18.1.2019</version>
<version>1.10.2-12.18.1.2018</version>
<version>1.10.2-12.18.1.2017</version>
<version>1.10.2-12.18.1.2016-failtests</version>
<version>1.10.2-12.18.1.2015-failtests</version>
<version>1.10.2-12.18.1.2014</version>
<version>1.10.2-12.18.1.2013</version>
<version>1.10.2-12.18.0.2010</version>
<version>1.10.2-12.18.0.2009</version>
<version>1.10.2-12.18.0.2008</version>
<version>1.10.2-12.18.0.2007-1.10.0</version>
<version>1.10.2-12.18.0.2001-1.10.0</version>
<version>1.9-12.16.1.1938-1.9.0</version>
<version>1.9-12.16.1.1934</version>
<version>1.9-12.16.0.1886</version>
<version>1.9-12.16.0.1885-1.9</version>
<version>1.9-12.16.0.1766-1.9</version>
<version>1.9.4-12.17.0.2317-1.9.4</version>
<version>1.9.4-12.17.0.2051</version>
<version>1.9.4-12.17.0.1990</version>
<version>1.9.4-12.17.0.1987</version>
<version>1.9.4-12.17.0.1976</version>
<version>1.9.4-12.17.0.1975</version>
<version>1.9.4-12.17.0.1974-1.9.4</version>
<version>1.9.4-12.17.0.1973</version>
<version>1.9.4-12.17.0.1937</version>
<version>1.9.4-12.17.0.1936-1.9.4</version>
<version>1.9.4-12.17.0.1935-1.9.4</version>
<version>1.9.4-12.17.0.1920-1.9.4</version>
<version>1.9.4-12.17.0.1919-EHUnit</version>
<version>1.9.4-12.17.0.1908-1.9.4</version>
<version>1.8-11.14.4.1577</version>
<version>1.8-11.14.0.1296</version>
<version>1.8-11.14.0.1295-1.8</version>
<version>1.8-11.14.0.1237-1.8</version>
<version>1.8.9-11.15.1.2318-1.8.9</version>
<version>1.8.9-11.15.1.1902-1.8.9</version>
<version>1.8.9-11.15.1.1890-1.8.9</version>
<version>1.8.9-11.15.1.1875</version>
<version>1.8.9-11.15.1.1873</version>
<version>1.8.9-11.15.1.1758</version>
<version>1.8.9-11.15.1.1757</version>
<version>1.8.9-11.15.1.1756</version>
<version>1.8.9-11.15.1.1755</version>
<version>1.8.9-11.15.0.1657</version>
<version>1.8.9-11.15.0.1656</version>
<version>1.8.8-11.15.0.1655</version>
<version>1.8.8-11.15.0.1654-1.8.8</version>
<version>1.8.8-11.15.0.1653-1.8.8</version>
<version>1.8.8-11.14.4.1579-1.8.8</version>
<version>1.8.8-11.14.4.1576-1.8.8</version>
<version>1.8.8-11.14.4.1575-1.8.8</version>
<version>1.7.10-10.13.4.1614-1.7.10</version>
<version>1.7.10-10.13.3.1406-1.7.10</version>
<version>1.7.10-10.13.3.1403-1.7.10</version>
<version>1.7.10-10.13.3.1401-1710ls</version>
<version>1.7.10-10.13.3.1400-1.7.10</version>
<version>1.7.10-10.13.3.1399-1.7.10</version>
<version>1.7.10-10.13.3.1395-1710ls</version>
<version>1.7.10-10.13.3.1394-1710ls</version>
<version>1.7.10-10.13.3.1393-1710ls</version>
<version>1.7.10-10.13.3.1391-1710ls</version>
<version>1.7.10-10.13.3.1389-1710ls</version>
<version>1.7.10-10.13.3.1388-1.7.10</version>
<version>1.7.10-10.13.2.1307-1.7.10</version>
<version>1.7.10-10.13.2.1300-1.7.10</version>
<version>1.7.10-10.13.2.1291</version>
<version>1.7.10-10.13.2.1286</version>
<version>1.7.10-10.13.2.1284</version>
<version>1.7.10-10.13.2.1283</version>
<version>1.7.10-10.13.2.1277</version>
<version>1.7.10-10.13.2.1276</version>
<version>1.7.10-10.13.2.1275</version>
<version>1.7.10-10.13.1.1219</version>
<version>1.7.10-10.13.1.1217</version>
<version>1.7.10-10.13.1.1216-new</version>
<version>1.7.10-10.13.1.1215-new</version>
<version>1.7.10-10.13.1.1214-new</version>
<version>1.7.10-10.13.1.1213-new</version>
<version>1.7.10-10.13.1.1212-new</version>
<version>1.7.10-10.13.1.1211-new</version>
<version>1.7.10-10.13.1.1210-new</version>
<version>1.7.10-10.13.0.1208</version>
<version>1.7.10-10.13.0.1150</version>
<version>1.7.2-10.12.2.1161-mc172</version>
<version>1.7.2-10.12.2.1155-mc172</version>
<version>1.7.2-10.12.2.1154-mc172</version>
<version>1.7.2-10.12.2.1147</version>
<version>1.7.2-10.12.2.1145</version>
<version>1.7.2-10.12.0.1030</version>
<version>1.7.2-10.12.0.1029</version>
<version>1.7.2-10.12.0.1028</version>
<version>1.7.2-10.12.0.1027</version>
<version>1.7.2-10.12.0.1026</version>
<version>1.7.2-10.12.0.1025</version>
<version>1.7.2-10.12.0.1024</version>
<version>1.7.2-10.12.0.1023</version>
<version>1.7.2-10.12.0.1022</version>
<version>1.7.2-10.12.0.1021</version>
<version>1.7.2-10.12.0.1020</version>
<version>1.7.2-10.12.0.1000</version>
<version>1.7.2-10.12.0.999</version>
<version>1.7.2-10.12.0.998</version>
<version>1.7.10_pre4-10.12.2.1149-prerelease</version>
<version>1.7.10_pre4-10.12.2.1148-prerelease</version>
<version>1.7.10_pre4-10.12.2.1146-prerelease</version>
<version>1.7.10_pre4-10.12.2.1144-prerelease</version>
<version>1.7.10_pre4-10.12.2.1143-prerelease</version>
<version>1.7.10_pre4-10.12.2.1142-prerelease</version>
<version>1.7.10_pre4-10.12.2.1141-prerelease</version>
<version>1.7.10_pre4-10.12.2.1139-prerelease</version>
<version>1.7.10_pre4-10.12.2.1138-prerelease</version>
<version>1.7.10_pre4-10.12.2.1137-prerelease</version>
<version>1.6.4-9.11.1.1345</version>
<version>1.6.4-9.11.1.965</version>
<version>1.6.4-9.11.1.964</version>
<version>1.6.4-9.11.1.963</version>
<version>1.6.4-9.11.1.961</version>
<version>1.6.4-9.11.1.960</version>
<version>1.6.1-8.9.0.775</version>
<version>1.6.1-8.9.0.749</version>
<version>1.5-7.7.0.598</version>
<version>1.5-7.7.0.565</version>
<version>1.5-7.7.0.563</version>
<version>1.5-7.7.0.562</version>
<version>1.5-7.7.0.561</version>
<version>1.5-7.7.0.560</version>
<version>1.5-7.7.0.559</version>
<version>1.5.2-7.8.1.738</version>
<version>1.5.2-7.8.1.737</version>
<version>1.5.2-7.8.0.736</version>
<version>1.5.2-7.8.0.735</version>
<version>1.5.2-7.8.0.734</version>
<version>1.5.2-7.8.0.733</version>
<version>1.5.2-7.8.0.732</version>
<version>1.5.2-7.8.0.731</version>
<version>1.5.2-7.8.0.730</version>
<version>1.5.2-7.8.0.729</version>
<version>1.5.2-7.8.0.728</version>
<version>1.5.2-7.8.0.727</version>
<version>1.1-1.3.2.3</version>
<version>1.1-1.3.2.2</version>
<version>1.1-1.3.2.1</version>
<version>1.21.8-58.0.4</version>
<version>1.21.1-52.1.3</version>
<version>1.20.1-47.4.6</version>
<version>1.21.8-58.0.5</version>
<version>1.19.4-45.4.2</version>
<version>1.15.2-31.2.60</version>
<version>1.21.8-58.0.6</version>
<version>1.21.8-58.0.7</version>
<version>1.21.8-58.0.8</version>
<version>1.21.8-58.0.9</version>
<version>1.21.8-58.0.10</version>
<version>1.21.5-55.0.25</version>
<version>1.21.5-55.1.0</version>
<version>1.21.8-58.1.0</version>
<version>1.20.4-49.2.1</version>
<version>1.20.1-47.4.8</version>
<version>1.21.8-58.1.1</version>
<version>1.21.8-58.1.2</version>
<version>1.21.8-58.1.3</version>
<version>1.21.8-58.1.4</version>
<version>1.20.1-47.4.9</version>
<version>1.21.5-55.1.1</version>
<version>1.21.3-53.1.3</version>
<version>1.21.4-54.1.7</version>
<version>1.20.6-50.2.2</version>
<version>1.20.4-49.2.2</version>
<version>1.21.1-52.1.4</version>
<version>1.21.8-58.1.6</version>
<version>1.21.5-55.1.2</version>
<version>1.21.4-54.1.8</version>
<version>1.21.3-53.1.4</version>
<version>1.21.1-52.1.5</version>
<version>1.21.9-59.0.0</version>
<version>1.21.9-59.0.1</version>
<version>1.21.9-59.0.2</version>
<version>1.21.8-58.1.7</version>
<version>1.21.9-59.0.3</version>
<version>1.21.9-59.0.4</version>
<version>1.21.9-59.0.5</version>
<version>1.21.10-60.0.0</version>
<version>1.20.1-47.4.10</version>
<version>1.21.10-60.0.1</version>
<version>1.21.10-60.0.3</version>
<version>1.21.10-60.0.4</version>
<version>1.21.10-60.0.5</version>
<version>1.21.10-60.0.6</version>
<version>1.21.10-60.0.7</version>
<version>1.21.10-60.0.8</version>
<version>1.21.10-60.0.9</version>
<version>1.21.1-52.1.6</version>
<version>1.21.10-60.0.10</version>
<version>1.21.10-60.0.11</version>
<version>1.21.10-60.0.12</version>
<version>1.21.10-60.0.13</version>
<version>1.21.10-60.0.14</version>
</versions>
<lastUpdated>20251031200755</lastUpdated>
</versioning>
</metadata>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>com.mumfrey</groupId>
<artifactId>liteloader</artifactId>
<versioning>
<latest>1.9.4-SNAPSHOT</latest>
<release></release>
<versions>
<version>1.8.9-SNAPSHOT</version>
<version>1.9-SNAPSHOT</version>
<version>1.9.4-SNAPSHOT</version>
<version>1.8-SNAPSHOT</version>
<version>1.10-SNAPSHOT</version>
<version>1.10.2-SNAPSHOT</version>
<version>1.11-SNAPSHOT</version>
<version>1.11.2-SNAPSHOT</version>
<version>1.12-SNAPSHOT</version>
<version>1.12.1-SNAPSHOT</version>
<version>1.12.2-SNAPSHOT</version>
</versions>
<lastUpdated>20171128144432</lastUpdated>
</versioning>
</metadata>

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>net.neoforged</groupId>
<artifactId>neoforge</artifactId>
<versioning>
<latest>21.10.43-beta</latest>
<release>21.10.43-beta</release>
<versions>
<version>21.10.5-beta</version>
<version>21.10.4-beta</version>
<version>21.10.3-beta</version>
<version>21.10.2-beta</version>
<version>21.10.1-beta</version>
<version>21.10.0-beta</version>
<version>21.9.16-beta</version>
<version>21.9.15-beta</version>
<version>21.9.14-beta</version>
<version>21.9.13-beta</version>
<version>21.9.12-beta</version>
<version>21.9.11-beta</version>
<version>21.9.10-beta</version>
<version>21.9.9-beta</version>
<version>21.9.8-beta</version>
<version>21.9.7-beta</version>
<version>21.9.6-beta</version>
<version>21.9.5-beta</version>
<version>21.9.4-beta</version>
<version>21.9.3-beta</version>
<version>21.9.2-beta</version>
<version>21.9.1-beta</version>
<version>21.9.0-beta</version>
<version>21.8.47</version>
<version>21.8.42</version>
<version>21.8.41</version>
<version>21.3.1-beta</version>
<version>21.3.0-beta</version>
<version>21.2.1-beta</version>
<version>21.2.0-beta</version>
<version>21.1.209</version>
<version>21.1.208</version>
<version>21.1.207</version>
<version>21.1.206</version>
<version>21.1.205</version>
<version>21.1.204</version>
<version>21.1.203</version>
<version>21.1.202</version>
<version>21.1.201</version>
<version>21.1.35</version>
<version>21.1.34</version>
<version>21.1.33</version>
<version>21.1.32</version>
<version>21.1.31</version>
<version>21.1.30</version>
<version>21.1.29</version>
<version>21.1.28</version>
<version>21.1.27</version>
<version>21.1.26</version>
<version>21.1.25</version>
<version>21.1.24</version>
<version>21.1.23</version>
<version>21.1.22</version>
<version>21.1.21</version>
<version>21.1.20</version>
<version>21.1.19</version>
<version>21.1.18</version>
<version>21.1.17</version>
<version>21.1.16</version>
<version>21.1.15</version>
<version>21.1.13</version>
<version>21.1.12</version>
<version>21.1.11</version>
<version>21.1.10</version>
<version>21.1.9</version>
<version>21.1.8</version>
<version>21.1.7</version>
<version>21.1.6</version>
<version>21.1.1</version>
<version>21.0.167</version>
<version>21.0.143</version>
<version>21.0.142-beta</version>
<version>21.0.138-beta</version>
<version>21.0.102-beta</version>
<version>21.0.100-beta</version>
<version>21.0.99-beta</version>
<version>21.0.92-beta</version>
<version>21.0.91-beta</version>
<version>21.0.90-beta</version>
<version>21.0.89-beta</version>
<version>21.0.41-beta</version>
<version>21.0.40-beta</version>
<version>21.0.39-beta</version>
<version>21.0.2-beta</version>
<version>21.0.1-beta</version>
<version>21.0.0-beta</version>
<version>20.6.138</version>
<version>20.6.115</version>
<version>20.6.114-beta</version>
<version>20.6.80-beta</version>
<version>20.6.79-beta</version>
<version>20.6.11-beta</version>
<version>20.6.10-beta</version>
<version>20.6.9-beta</version>
<version>20.6.8-beta</version>
<version>20.5.10-beta</version>
<version>20.5.9-beta</version>
<version>20.5.8-beta</version>
<version>20.5.7-beta</version>
<version>20.5.6-beta</version>
<version>20.5.5-beta</version>
<version>20.5.4-beta</version>
<version>20.5.3-beta</version>
<version>20.5.2-beta</version>
<version>20.5.1-beta</version>
<version>20.5.0-beta</version>
<version>20.4.250</version>
<version>20.4.249</version>
<version>20.4.167</version>
<version>20.4.166-beta</version>
<version>20.4.95-beta</version>
<version>20.4.44-beta</version>
<version>20.3.1-beta</version>
<version>20.2.93</version>
<version>20.2.92</version>
<version>20.2.91</version>
<version>20.2.90</version>
<version>20.2.89</version>
<version>20.2.88</version>
<version>20.2.86</version>
<version>20.2.85-beta</version>
<version>20.2.59-beta</version>
<version>20.2.30-beta</version>
<version>20.2.29-beta</version>
<version>20.2.8-beta</version>
<version>20.2.6-beta</version>
<version>20.2.5-beta</version>
<version>20.2.4-beta</version>
<version>20.2.3-beta</version>
<version>0.25w14craftmine.5-beta</version>
<version>0.25w14craftmine.4-beta</version>
<version>0.25w14craftmine.3-beta</version>
<version>21.10.6-beta</version>
<version>21.4.155</version>
<version>21.10.7-beta</version>
<version>21.10.8-beta</version>
<version>21.10.9-beta</version>
<version>21.10.10-beta</version>
<version>21.1.210</version>
<version>21.10.11-beta</version>
<version>21.10.12-beta</version>
<version>21.10.13-beta</version>
<version>21.10.14-beta</version>
<version>21.10.15-beta</version>
<version>21.1.211</version>
<version>21.10.16-beta</version>
<version>21.10.17-beta</version>
<version>21.10.18-beta</version>
<version>21.10.19-beta</version>
<version>21.10.20-beta</version>
<version>21.10.21-beta</version>
<version>21.10.22-beta</version>
<version>21.10.23-beta</version>
<version>21.10.24-beta</version>
<version>21.10.25-beta</version>
<version>21.1.212</version>
<version>21.8.48</version>
<version>21.10.28-beta</version>
<version>21.10.29-beta</version>
<version>21.1.213</version>
<version>20.4.251</version>
<version>20.6.139</version>
<version>21.3.94</version>
<version>21.10.30-beta</version>
<version>21.10.31-beta</version>
<version>21.10.32-beta</version>
<version>21.10.33-beta</version>
<version>21.8.49</version>
<version>21.10.34-beta</version>
<version>21.10.42-beta</version>
<version>21.10.43-beta</version>
</versions>
<lastUpdated>20251101100329</lastUpdated>
</versioning>
</metadata>

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>net.neoforged</groupId>
<artifactId>forge</artifactId>
<versioning>
<latest>1.20.1-47.1.106</latest>
<release>1.20.1-47.1.106</release>
<versions>
<version>1.20.1-47.1.7</version>
<version>1.20.1-47.1.5</version>
<version>1.20.1-47.1.8</version>
<version>1.20.1-47.1.9</version>
<version>1.20.1-47.1.11</version>
<version>1.20.1-47.1.12</version>
<version>1.20.1-47.1.23</version>
<version>1.20.1-47.1.25</version>
<version>1.20.1-47.1.26</version>
<version>1.20.1-47.1.27</version>
<version>1.20.1-47.1.28</version>
<version>1.20.1-47.1.54</version>
<version>1.20.1-47.1.55</version>
<version>1.20.1-47.1.56</version>
<version>1.20.1-47.1.57</version>
<version>1.20.1-47.1.58</version>
<version>1.20.1-47.1.59</version>
<version>1.20.1-47.1.60</version>
<version>1.20.1-47.1.61</version>
<version>1.20.1-47.1.62</version>
<version>1.20.1-47.1.63</version>
<version>1.20.1-47.1.64</version>
<version>1.20.1-47.1.65</version>
<version>1.20.1-47.1.66</version>
<version>1.20.1-47.1.67</version>
<version>1.20.1-47.1.69</version>
<version>1.20.1-47.1.70</version>
<version>1.20.1-47.1.71</version>
<version>1.20.1-47.1.72</version>
<version>1.20.1-47.1.73</version>
<version>1.20.1-47.1.74</version>
<version>1.20.1-47.1.75</version>
<version>1.20.1-47.1.76</version>
<version>1.20.1-47.1.77</version>
<version>1.20.1-47.1.78</version>
<version>1.20.1-47.1.79</version>
<version>1.20.1-47.1.80</version>
<version>1.20.1-47.1.81</version>
<version>47.1.82</version>
<version>1.20.1-47.1.83</version>
<version>1.20.1-47.1.84</version>
<version>1.20.1-47.1.85</version>
<version>1.20.1-47.1.86</version>
<version>1.20.1-47.1.87</version>
<version>1.20.1-47.1.88</version>
<version>1.20.1-47.1.90</version>
<version>1.20.1-47.1.91</version>
<version>1.20.1-47.1.89</version>
<version>1.20.1-47.1.92</version>
<version>1.20.1-47.1.93</version>
<version>1.20.1-47.1.94</version>
<version>1.20.1-47.1.95</version>
<version>1.20.1-47.1.96</version>
<version>1.20.1-47.1.97</version>
<version>1.20.1-47.1.98</version>
<version>1.20.1-47.1.99</version>
<version>1.20.1-47.1.100</version>
<version>1.20.1-47.1.101</version>
<version>1.20.1-47.1.102</version>
<version>1.20.1-47.1.103</version>
<version>1.20.1-47.1.104</version>
<version>1.20.1-47.1.105</version>
<version>1.20.1-47.1.106</version>
</versions>
<lastUpdated>20240528174429</lastUpdated>
</versioning>
</metadata>

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>org.quiltmc</groupId>
<artifactId>quilt-loader</artifactId>
<versioning>
<latest>0.29.3-beta.1</latest>
<release>0.29.3-beta.1</release>
<versions>
<version>0.16.0-beta.1</version>
<version>0.16.0-beta.2</version>
<version>0.16.0-beta.3</version>
<version>0.16.0-beta.5</version>
<version>0.16.0-beta.6</version>
<version>0.16.0-beta.7</version>
<version>0.16.0-beta.8</version>
<version>0.16.0-beta.9</version>
<version>0.18.1-beta.18</version>
<version>0.18.1-beta.19</version>
<version>0.17.7</version>
<version>0.18.1-beta.20</version>
<version>0.18.1-beta.21</version>
<version>0.18.1-beta.77</version>
<version>0.18.1-beta.78</version>
<version>0.18.1-beta.79</version>
<version>0.18.1</version>
<version>0.18.2</version>
<version>0.18.3-pre.1</version>
<version>0.18.3-pre.2</version>
<version>0.18.3</version>
<version>0.18.4-pre.1</version>
<version>0.18.4-pre.2</version>
<version>0.18.4-pre.3</version>
<version>0.18.4</version>
<version>0.18.5</version>
<version>0.19.0-beta.1</version>
<version>0.18.6-beta.1</version>
<version>0.19.0-beta.2</version>
<version>0.18.6</version>
<version>0.19.0-beta.3</version>
<version>0.18.7</version>
<version>0.19.0-beta.4</version>
<version>0.18.9</version>
<version>0.18.10</version>
<version>0.19.0-beta.12</version>
<version>0.19.0-beta.13</version>
<version>0.19.0-beta.16</version>
<version>0.19.3-beta.1</version>
<version>0.20.0-beta.4</version>
<version>0.20.0-beta.5</version>
<version>0.20.0-beta.6</version>
<version>0.20.0-beta.7</version>
<version>0.20.0-beta.8</version>
<version>0.20.0-beta.9</version>
<version>0.20.0-beta.10</version>
<version>0.20.0-beta.11</version>
<version>0.29.0-beta.4</version>
<version>0.29.0-beta.5</version>
<version>0.29.0-beta.6</version>
<version>0.29.0-beta.7</version>
<version>0.29.0-beta.8</version>
<version>0.29.0</version>
<version>0.29.1-beta.1</version>
<version>0.29.1</version>
<version>0.29.2-beta.1</version>
<version>0.29.2-beta.2</version>
<version>0.29.2-beta.4</version>
<version>0.29.2-beta.5</version>
<version>0.29.2</version>
<version>0.29.3-beta.1</version>
</versions>
<lastUpdated>20251025205845</lastUpdated>
</versioning>
</metadata>

View File

@@ -24,167 +24,248 @@ type MavenMetadata struct {
} `xml:"versioning"` } `xml:"versioning"`
} }
type ModLoaderComponent struct { type ModLoaderVersions struct {
Name string // All Versions of this modloader
FriendlyName string Versions []string
VersionListGetter func(mcVersion string) ([]string, string, error) // The Latest/preferred version for this modloader
Latest string
} }
var ModLoaders = map[string]ModLoaderComponent{ type ModLoaderComponent struct {
"fabric": { // An identifier for the modloader
Name string
// A user-friendly name
FriendlyName string
// Retrieves the list of all modloader versions. Modloader versions are always filtered to those compatible
// with a specific minecraft version.
VersionListGetter func(q VersionListQuery) (*ModLoaderVersions, error)
}
var modLoadersList = []ModLoaderComponent{
{
// There's no need to specify yarn version - yarn isn't used outside a dev environment, and intermediary corresponds to game version anyway // There's no need to specify yarn version - yarn isn't used outside a dev environment, and intermediary corresponds to game version anyway
Name: "fabric", Name: "fabric",
FriendlyName: "Fabric loader", FriendlyName: "Fabric loader",
VersionListGetter: FetchMavenVersionList("https://maven.fabricmc.net/net/fabricmc/fabric-loader/maven-metadata.xml"), VersionListGetter: func(q VersionListQuery) (*ModLoaderVersions, error) {
// Fabric loaders isn't locked to a mc version per se
return fetchVersionsFromMaven(q, "https://maven.fabricmc.net/net/fabricmc/fabric-loader/maven-metadata.xml")
}, },
"forge": { },
{
Name: "forge", Name: "forge",
FriendlyName: "Forge", FriendlyName: "Forge",
VersionListGetter: FetchMavenVersionPrefixedListStrip("https://files.minecraftforge.net/maven/net/minecraftforge/forge/maven-metadata.xml", "Forge"), VersionListGetter: fetchForForge,
}, },
"liteloader": { {
Name: "liteloader", Name: "liteloader",
FriendlyName: "LiteLoader", FriendlyName: "LiteLoader",
VersionListGetter: FetchMavenVersionPrefixedList("https://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/maven-metadata.xml", "LiteLoader"), VersionListGetter: func(q VersionListQuery) (*ModLoaderVersions, error) {
return fetchLiteloaderStyle(q, "https://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/maven-metadata.xml")
}, },
"quilt": { },
{
Name: "quilt", Name: "quilt",
FriendlyName: "Quilt loader", FriendlyName: "Quilt loader",
VersionListGetter: FetchMavenVersionList("https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/maven-metadata.xml"), VersionListGetter: func(q VersionListQuery) (*ModLoaderVersions, error) {
return fetchVersionsFromMaven(q, "https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/maven-metadata.xml")
}, },
"neoforge": { },
{
Name: "neoforge", Name: "neoforge",
FriendlyName: "NeoForge", FriendlyName: "NeoForge",
VersionListGetter: FetchNeoForge(), VersionListGetter: fetchForNeoForge,
}, },
} }
func FetchMavenVersionList(url string) func(mcVersion string) ([]string, string, error) { // A map containing information about all supported modloaders.
return func(mcVersion string) ([]string, string, error) { // Can be indexed by the [ModLoaderComponent]'s name, which serves as an identifier.
res, err := GetWithUA(url, "application/xml") var ModLoaders = createModloaderMap(modLoadersList)
if err != nil {
return []string{}, "", err func createModloaderMap(input []ModLoaderComponent) map[string]ModLoaderComponent {
var mlMap = make(map[string]ModLoaderComponent)
for _, loader := range input {
mlMap[loader.Name] = loader
} }
dec := xml.NewDecoder(res.Body) return mlMap
out := MavenMetadata{}
err = dec.Decode(&out)
if err != nil {
return []string{}, "", err
} }
return out.Versioning.Versions.Version, out.Versioning.Release, nil
type QueryType int
const (
// The Latest field will contain the last released loader version
Latest QueryType = iota
// The Latest field will contain the loader version recommended for use
Recommended
)
type VersionListQuery struct {
// Which loader to query versions for
Loader ModLoaderComponent
// Which minecraft version the returned loader versions should be compatible with
McVersion string
// Determines how the latest version is determined
QueryType QueryType
}
func MakeQuery(loader ModLoaderComponent, mcVersion string) VersionListQuery {
return VersionListQuery{
Loader: loader,
McVersion: mcVersion,
QueryType: Latest,
} }
} }
func FetchMavenVersionFiltered(url string, friendlyName string, filter func(version string, mcVersion string) bool) func(mcVersion string) ([]string, string, error) { func (in VersionListQuery) WithQueryType(queryType QueryType) VersionListQuery {
return func(mcVersion string) ([]string, string, error) { return VersionListQuery{
res, err := GetWithUA(url, "application/xml") Loader: in.Loader,
if err != nil { McVersion: in.McVersion,
return []string{}, "", err QueryType: queryType,
}
dec := xml.NewDecoder(res.Body)
out := MavenMetadata{}
err = dec.Decode(&out)
if err != nil {
return []string{}, "", err
}
allowedVersions := make([]string, 0, len(out.Versioning.Versions.Version))
for _, v := range out.Versioning.Versions.Version {
if filter(v, mcVersion) {
allowedVersions = append(allowedVersions, v)
}
}
if len(allowedVersions) == 0 {
return []string{}, "", errors.New("no " + friendlyName + " versions available for this Minecraft version")
}
if filter(out.Versioning.Release, mcVersion) {
return allowedVersions, out.Versioning.Release, nil
}
if filter(out.Versioning.Latest, mcVersion) {
return allowedVersions, out.Versioning.Latest, nil
}
// Sort list to get largest version
flexver.VersionSlice(allowedVersions).Sort()
return allowedVersions, allowedVersions[len(allowedVersions)-1], nil
} }
} }
func FetchMavenVersionPrefixedList(url string, friendlyName string) func(mcVersion string) ([]string, string, error) { // Queries the versions of a modloader
return FetchMavenVersionFiltered(url, friendlyName, hasPrefixSplitDash) func DoQuery(q VersionListQuery) (*ModLoaderVersions, error) {
return q.Loader.VersionListGetter(q)
} }
func FetchMavenVersionPrefixedListStrip(url string, friendlyName string) func(mcVersion string) ([]string, string, error) { // Retrieve a list of versions from maven, with no filtering or processing of the maven data
noStrip := FetchMavenVersionPrefixedList(url, friendlyName) func fetchVersionsFromMaven(q VersionListQuery, url string) (*ModLoaderVersions, error) {
return func(mcVersion string) ([]string, string, error) { identity_function := func(version string) *string { return &version }
versions, latestVersion, err := noStrip(mcVersion) return fetchMavenWithFilterMap(q, url, identity_function)
if err != nil {
return nil, "", err
}
for k, v := range versions {
versions[k] = removeMcVersion(v, mcVersion)
}
latestVersion = removeMcVersion(latestVersion, mcVersion)
return versions, latestVersion, nil
}
} }
func removeMcVersion(str string, mcVersion string) string { func fetchForgeStyle(q VersionListQuery, url string) (*ModLoaderVersions, error) {
components := strings.Split(str, "-") // Forge style:
newComponents := make([]string, 0) // each version is formatted like `mcVersion-forgeVersion`
for _, v := range components { // eg: `1.18.1-39.0.18`
if v != mcVersion { return fetchMavenWithFilterMap(q, url, func(version string) *string {
newComponents = append(newComponents, v) before, after, f := strings.Cut(version, "-")
if !f {
// The version didn't have a dash? Lets just reject it entirely
return nil
} }
if before != q.McVersion {
// The part before the dash should match the mc version we're looking for
return nil
} }
return strings.Join(newComponents, "-") // The part after the dash is the actual version, and the part we care about
return &after
})
} }
func hasPrefixSplitDash(str string, prefix string) bool { func fetchNeoForgeStyle(q VersionListQuery, url string) (*ModLoaderVersions, error) {
components := strings.Split(str, "-") // NeoForge style:
if len(components) > 1 && components[0] == prefix { // If minecraft versions are in the form of 1.a.b, then neoforge versions are in the form of a.b.x
return true
}
return false
}
func FetchNeoForge() func(mcVersion string) ([]string, string, error) {
// NeoForge reused Forge's versioning scheme for 1.20.1, but moved to their own versioning scheme for 1.20.2 and above
neoforgeOld := FetchMavenVersionPrefixedListStrip("https://maven.neoforged.net/releases/net/neoforged/forge/maven-metadata.xml", "NeoForge")
neoforgeNew := FetchMavenWithNeoForgeStyleVersions("https://maven.neoforged.net/releases/net/neoforged/neoforge/maven-metadata.xml", "NeoForge")
return func(mcVersion string) ([]string, string, error) {
if mcVersion == "1.20.1" {
return neoforgeOld(mcVersion)
} else {
return neoforgeNew(mcVersion)
}
}
}
func FetchMavenWithNeoForgeStyleVersions(url string, friendlyName string) func(mcVersion string) ([]string, string, error) {
return FetchMavenVersionFiltered(url, friendlyName, func(neoforgeVersion string, mcVersion string) bool {
// Minecraft versions are in the form of 1.a.b
// Neoforge versions are in the form of a.b.x
// Eg, for minecraft 1.20.6, neoforge version 20.6.2 and 20.6.83-beta would both be valid versions // Eg, for minecraft 1.20.6, neoforge version 20.6.2 and 20.6.83-beta would both be valid versions
// for minecraft 1.20.2, neoforge version 20.2.23-beta // for minecraft 1.20.2, neoforge version 20.2.23-beta
// for minecraft 1.21, neoforge version 21.0.143 would be valid // for minecraft 1.21, neoforge version 21.0.143 would be valid
var mcSplit = strings.Split(mcVersion, ".")
var mcSplit = strings.Split(q.McVersion, ".")
if len(mcSplit) < 2 { if len(mcSplit) < 2 {
// This does not appear to be a minecraft version that's formatted in a way that matches neoforge // This does not appear to be a minecraft version that's formatted in a way that matches neoforge
return false return nil, fmt.Errorf("packwiz cannot detect compatible %s versions for this Minecraft version (%s)", q.Loader.FriendlyName, q.McVersion)
} }
var mcMajor = mcSplit[1] var mcMajor = mcSplit[1]
var mcMinor = "0" var mcMinor = "0"
if len(mcSplit) > 2 { if len(mcSplit) > 2 {
mcMinor = mcSplit[2] mcMinor = mcSplit[2]
} }
// Note that the period at the end is significant, we don't want to match `21.10.43` as being for 1.21.1 (instead of 1.21.10)
// We can only accept an exact version number match, because otherwise 1.21.1 would pull in loader versions for 1.21.10.
var requiredPrefix = mcMajor + "." + mcMinor + "." var requiredPrefix = mcMajor + "." + mcMinor + "."
return strings.HasPrefix(neoforgeVersion, requiredPrefix) return fetchMavenWithFilterMap(q, url, func(version string) *string {
if !strings.HasPrefix(version, requiredPrefix) {
// Reject NeoForge versions that don't have the right prefix for this mc version
return nil
}
return &version
}) })
} }
func fetchLiteloaderStyle(q VersionListQuery, url string) (*ModLoaderVersions, error) {
// Liteloader style:
// each version is formatted like `mcVersion-SNAPSHOT`
// eg: `1.12.2-SNAPSHOT`
// (yes, it appears like liteloader only has a single version per mc version)
return fetchMavenWithFilterMap(q, url, func(version string) *string {
before, _, f := strings.Cut(version, "-")
// Check if the part before the dash matches the mc version we're looking for
if f && before == q.McVersion {
return &version
} else {
return nil
}
})
}
// Retrieves all versions through maven metadata, and then processes the using the provided `filterMap` function.
// When `filterMap` returns a string, the version will be renamed to the provided string. If `nil` is returned, the
// version is marked as invalid and will not be considered in the result.
func fetchMavenWithFilterMap(q VersionListQuery, url string, filterMap func(version string) *string) (*ModLoaderVersions, error) {
res, err := GetWithUA(url, "application/xml")
if err != nil {
return nil, err
}
dec := xml.NewDecoder(res.Body)
out := MavenMetadata{}
err = dec.Decode(&out)
if err != nil {
return nil, err
}
// Pass all of the versions listed in the maven through our filterMap
versions := make([]string, 0, len(out.Versioning.Versions.Version))
for _, v := range out.Versioning.Versions.Version {
mappedV := filterMap(v)
if mappedV != nil {
versions = append(versions, *mappedV)
}
}
if len(versions) == 0 {
return nil, errors.New("no " + q.Loader.FriendlyName + " versions available for " + q.McVersion)
}
// Determine the latest release
var latestRelease = ""
release := filterMap(out.Versioning.Release)
latest := filterMap(out.Versioning.Latest)
if release != nil {
latestRelease = *release
} else if latest != nil {
latestRelease = *latest
} else {
// Maven was useless, just rely on flexver sorting
flexver.VersionSlice(versions).Sort()
latestRelease = versions[len(versions)-1]
}
return &ModLoaderVersions{versions, latestRelease}, nil
}
func fetchForNeoForge(q VersionListQuery) (*ModLoaderVersions, error) {
// NeoForge reused Forge's versioning scheme for 1.20.1, but moved to their own versioning scheme for 1.20.2 and above
if q.McVersion == "1.20.1" {
return fetchForgeStyle(q, "https://maven.neoforged.net/releases/net/neoforged/forge/maven-metadata.xml")
} else {
return fetchNeoForgeStyle(q, "https://maven.neoforged.net/releases/net/neoforged/neoforge/maven-metadata.xml")
}
}
func fetchForForge(q VersionListQuery) (*ModLoaderVersions, error) {
result, err := fetchForgeStyle(q, "https://files.minecraftforge.net/maven/net/minecraftforge/forge/maven-metadata.xml")
if err != nil {
return nil, err
}
// Forge is the only loader which defines a special recommended version
if q.QueryType == Recommended {
recommended := getForgeRecommended(q)
if recommended != "" {
result.Latest = recommended
}
}
return result, nil
}
func ComponentToFriendlyName(component string) string { func ComponentToFriendlyName(component string) string {
if component == "minecraft" { if component == "minecraft" {
return "Minecraft" return "Minecraft"
@@ -215,8 +296,8 @@ type ForgeRecommended struct {
Versions map[string]string `json:"promos"` Versions map[string]string `json:"promos"`
} }
// GetForgeRecommended gets the recommended version of Forge for the given Minecraft version // getForgeRecommended gets the recommended version of Forge for the given Minecraft version
func GetForgeRecommended(mcVersion string) string { func getForgeRecommended(q VersionListQuery) string {
res, err := GetWithUA("https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json", "application/json") res, err := GetWithUA("https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json", "application/json")
if err != nil { if err != nil {
return "" return ""
@@ -230,11 +311,11 @@ func GetForgeRecommended(mcVersion string) string {
} }
// Get mcVersion-recommended, if it doesn't exist then get mcVersion-latest // Get mcVersion-recommended, if it doesn't exist then get mcVersion-latest
// If neither exist, return empty string // If neither exist, return empty string
recommendedString := fmt.Sprintf("%s-recommended", mcVersion) recommendedString := fmt.Sprintf("%s-recommended", q.McVersion)
if out.Versions[recommendedString] != "" { if out.Versions[recommendedString] != "" {
return out.Versions[recommendedString] return out.Versions[recommendedString]
} }
latestString := fmt.Sprintf("%s-latest", mcVersion) latestString := fmt.Sprintf("%s-latest", q.McVersion)
if out.Versions[latestString] != "" { if out.Versions[latestString] != "" {
return out.Versions[latestString] return out.Versions[latestString]
} }

129
core/versionutil_test.go Normal file
View File

@@ -0,0 +1,129 @@
package core
import (
"embed"
"os"
"slices"
"strings"
"testing"
"github.com/jarcoal/httpmock"
)
// For reproducability, we store a list of sample xml files for various endpoints
// these have been edited slightly to cut down on the number of entries, but are
// otherwise taken from the endpoints themselves
//go:embed version_test_files/*
var versionTestFiles embed.FS
func registerMock(url string, filename string) {
bytes, err := versionTestFiles.ReadFile("version_test_files/" + filename)
if err != nil {
println("Error " + filename + " not in version_test_files/")
os.Exit(1)
}
httpmock.RegisterResponder("GET", url, httpmock.NewBytesResponder(200, bytes))
}
func queryWithMock(t *testing.T, q VersionListQuery) *ModLoaderVersions {
httpmock.Activate(t)
registerMock("https://maven.fabricmc.net/net/fabricmc/fabric-loader/maven-metadata.xml", "fabric.xml")
registerMock("https://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/maven-metadata.xml", "liteloader.xml")
registerMock("https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-loader/maven-metadata.xml", "quilt.xml")
registerMock("https://files.minecraftforge.net/maven/net/minecraftforge/forge/maven-metadata.xml", "forge.xml")
registerMock("https://maven.neoforged.net/releases/net/neoforged/forge/maven-metadata.xml", "neoforge_old.xml")
registerMock("https://maven.neoforged.net/releases/net/neoforged/neoforge/maven-metadata.xml", "neoforge.xml")
versionData, err := DoQuery(q)
if err != nil {
t.Logf("Error fetching versions for %s: %s", q.Loader.FriendlyName, err)
if strings.Contains(err.Error(), "no responder found") {
t.Log("You likely need to register a mock for this url")
}
t.FailNow()
}
return versionData
}
func expectLatest(t *testing.T, loader string, version string, expectedLatest string) string {
loaderData, ok := ModLoaders[loader]
if !ok {
t.Fatal("Could not find loader")
}
versionData := queryWithMock(t, MakeQuery(loaderData, version))
if len(versionData.Versions) == 0 {
t.Error("There should be at least one version")
}
if versionData.Latest != expectedLatest {
t.Errorf("Expected latest version to be %s, found %s", expectedLatest, versionData.Latest)
}
return versionData.Latest
}
func expectValid(t *testing.T, loader string, version string, expectedValid string) {
loaderData, ok := ModLoaders[loader]
if !ok {
t.Fatal("Could not find loader")
}
versionData := queryWithMock(t, MakeQuery(loaderData, version))
if !slices.Contains(versionData.Versions, expectedValid) {
t.Errorf("Expected %s to be a valid version for %s. Valid versions:\n%s", expectedValid, loaderData.FriendlyName, versionData.Versions)
}
}
func expectInvalid(t *testing.T, loader string, version string, expectedValid string) {
loaderData, ok := ModLoaders[loader]
if !ok {
t.Fatal("Could not find loader")
}
versionData := queryWithMock(t, MakeQuery(loaderData, version))
if slices.Contains(versionData.Versions, expectedValid) {
t.Errorf("Expected %s not to be a valid version for %s. Valid versions:\n%s", expectedValid, loaderData.FriendlyName, versionData.Versions)
}
}
func TestFabric121(t *testing.T) {
expectLatest(t, "fabric", "1.21", "0.17.3")
}
func TestFabric010Valid(t *testing.T) {
expectValid(t, "fabric", "1.21", "0.10.6+build.214")
}
func TestQuilt121(t *testing.T) {
expectLatest(t, "quilt", "1.21", "0.29.3-beta.1")
}
func TestForge121(t *testing.T) {
expectLatest(t, "forge", "1.21", "51.0.33")
}
func TestLiteLoader112(t *testing.T) {
expectLatest(t, "liteloader", "1.12", "1.12-SNAPSHOT")
}
func TestNeoForge1201(t *testing.T) {
expectLatest(t, "neoforge", "1.20.1", "47.1.106")
}
func TestNeoForge121(t *testing.T) {
expectLatest(t, "neoforge", "1.21", "21.0.167")
}
func TestNeoForge1211(t *testing.T) {
expectLatest(t, "neoforge", "1.21.1", "21.1.213")
expectValid(t, "neoforge", "1.21.1", "21.1.201")
expectInvalid(t, "neoforge", "1.21.1", "21.10.43-beta")
}
func TestNeoForge1210(t *testing.T) {
expectLatest(t, "neoforge", "1.21.10", "21.10.43-beta")
}

1
go.mod
View File

@@ -39,6 +39,7 @@ require (
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jarcoal/httpmock v1.4.1
github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect

2
go.sum
View File

@@ -40,6 +40,8 @@ github.com/igorsobreira/titlecase v0.0.0-20140109233139-4156b5b858ac h1:AfRcPFr4
github.com/igorsobreira/titlecase v0.0.0-20140109233139-4156b5b858ac/go.mod h1:KOzUkqpWM2xArNm82cehGc5PBFYV1Qadzzt81aJi7F0= github.com/igorsobreira/titlecase v0.0.0-20140109233139-4156b5b858ac/go.mod h1:KOzUkqpWM2xArNm82cehGc5PBFYV1Qadzzt81aJi7F0=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A=
github.com/jarcoal/httpmock v1.4.1/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=

View File

@@ -40,12 +40,18 @@ var loaderCommand = &cobra.Command{
fmt.Printf("Error getting Minecraft version: %s\n", err) fmt.Printf("Error getting Minecraft version: %s\n", err)
os.Exit(1) os.Exit(1)
} }
if args[0] == "latest" { if args[0] == "latest" || args[0] == "recommended" {
fmt.Println("Updating to latest loader version") fmt.Printf("Updating to %s loader version\n", args[0])
queryType := core.Latest
if args[0] == "recommended" {
queryType = core.Recommended
}
// We'll be updating to the latest loader version // We'll be updating to the latest loader version
for _, loader := range currentLoaders { for _, loader := range currentLoaders {
_, latest, gottenLoader := getVersionsForLoader(loader, mcVersion) versionData, gottenLoader := getVersionsForLoader(loader, mcVersion, queryType)
if !updatePackToVersion(latest, modpack, gottenLoader) { if !updatePackToVersion(versionData.Latest, modpack, gottenLoader) {
continue continue
} }
// Write the pack to disk // Write the pack to disk
@@ -55,36 +61,14 @@ var loaderCommand = &cobra.Command{
continue continue
} }
} }
} else if args[0] == "recommended" {
// TODO: Figure out a way to get the recommended version, this is Forge only
// Ensure we're on Forge
if !slices.Contains(currentLoaders, "forge") {
fmt.Println("The recommended loader version is only available on Forge!")
os.Exit(1)
}
// We'll be updating to the recommended loader version
recommendedVer := core.GetForgeRecommended(mcVersion)
if recommendedVer == "" {
fmt.Println("Error getting recommended Forge version!")
os.Exit(1)
}
if ok := updatePackToVersion(recommendedVer, modpack, core.ModLoaders["forge"]); !ok {
os.Exit(1)
}
// Write the pack to disk
err = modpack.Write()
if err != nil {
fmt.Printf("Error writing pack.toml: %s", err)
os.Exit(1)
}
} else { } else {
fmt.Println("Updating to explicit loader version") fmt.Println("Updating to explicit loader version")
// This one is easy :D // This one is easy :D
versions, _, loader := getVersionsForLoader(currentLoaders[0], mcVersion) versionData, loader := getVersionsForLoader(currentLoaders[0], mcVersion, core.Latest)
// Check if the loader happens to be Forge/NeoForge, since there's two version formats // Check if the loader happens to be Forge/NeoForge, since there's two version formats
if loader.Name == "forge" || loader.Name == "neoforge" { if loader.Name == "forge" || loader.Name == "neoforge" {
wantedVersion := cmdshared.GetRawForgeVersion(args[0]) wantedVersion := cmdshared.GetRawForgeVersion(args[0])
validateVersion(versions, wantedVersion, loader) validateVersion(versionData.Versions, wantedVersion, loader)
_ = updatePackToVersion(wantedVersion, modpack, loader) _ = updatePackToVersion(wantedVersion, modpack, loader)
} else if loader.Name == "liteloader" { } else if loader.Name == "liteloader" {
// These are weird and just have a MC version // These are weird and just have a MC version
@@ -92,7 +76,7 @@ var loaderCommand = &cobra.Command{
os.Exit(0) os.Exit(0)
} else { } else {
// We're on Fabric or quilt // We're on Fabric or quilt
validateVersion(versions, args[0], loader) validateVersion(versionData.Versions, args[0], loader)
if ok := updatePackToVersion(args[0], modpack, loader); !ok { if ok := updatePackToVersion(args[0], modpack, loader); !ok {
os.Exit(1) os.Exit(1)
} }
@@ -111,18 +95,18 @@ func init() {
migrateCmd.AddCommand(loaderCommand) migrateCmd.AddCommand(loaderCommand)
} }
func getVersionsForLoader(loader, mcVersion string) ([]string, string, core.ModLoaderComponent) { func getVersionsForLoader(loader, mcVersion string, queryType core.QueryType) (*core.ModLoaderVersions, core.ModLoaderComponent) {
gottenLoader, ok := core.ModLoaders[loader] gottenLoader, ok := core.ModLoaders[loader]
if !ok { if !ok {
fmt.Printf("Unknown loader %s\n", loader) fmt.Printf("Unknown loader %s\n", loader)
os.Exit(1) os.Exit(1)
} }
versions, latestVersion, err := gottenLoader.VersionListGetter(mcVersion) versionData, err := core.DoQuery(core.MakeQuery(gottenLoader, mcVersion).WithQueryType(queryType))
if err != nil { if err != nil {
fmt.Printf("Error getting version list for %s: %s\n", gottenLoader.FriendlyName, err) fmt.Printf("Error getting version list for %s: %s\n", gottenLoader.FriendlyName, err)
os.Exit(1) os.Exit(1)
} }
return versions, latestVersion, gottenLoader return versionData, gottenLoader
} }
func validateVersion(versions []string, version string, gottenLoader core.ModLoaderComponent) { func validateVersion(versions []string, version string, gottenLoader core.ModLoaderComponent) {