feat: client and server-only mods (#71)
* feat: local registry database migrations * chore: store raw API responses in local registry * feat: update ficsit-resolver * feat: client and server-only mods * fix: remove mods that no longer support the current target
This commit is contained in:
parent
bf6d6b0850
commit
3640e5e708
11 changed files with 392 additions and 111 deletions
|
@ -429,7 +429,13 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate)
|
|||
var deleteWait errgroup.Group
|
||||
for _, entry := range dir {
|
||||
if entry.IsDir() {
|
||||
if _, ok := lockfile.Mods[entry.Name()]; !ok {
|
||||
modName := entry.Name()
|
||||
mod, hasMod := lockfile.Mods[modName]
|
||||
if hasMod {
|
||||
_, hasTarget := mod.Targets[platform.TargetName]
|
||||
hasMod = hasTarget
|
||||
}
|
||||
if !hasMod {
|
||||
modName := entry.Name()
|
||||
modDir := filepath.Join(modsDirectory, modName)
|
||||
deleteWait.Go(func() error {
|
||||
|
@ -493,7 +499,10 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate)
|
|||
|
||||
target, ok := version.Targets[platform.TargetName]
|
||||
if !ok {
|
||||
return fmt.Errorf("%s@%s not available for %s", modReference, version.Version, platform.TargetName)
|
||||
// The resolver validates that the resulting lockfile mods can be installed on the sides where they are required
|
||||
// so if the mod is missing this target, it means it is not required on this target
|
||||
slog.Info("skipping mod not available for target", slog.String("mod_reference", modReference), slog.String("version", version.Version), slog.String("target", platform.TargetName))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only install if a link is provided, otherwise assume mod is already installed
|
||||
|
|
106
cli/localregistry/migrations.go
Normal file
106
cli/localregistry/migrations.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
package localregistry
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var migrations = []func(*sql.Tx) error{
|
||||
initialSetup,
|
||||
addRequiredOnRemote,
|
||||
}
|
||||
|
||||
func applyMigrations(db *sql.DB) error {
|
||||
// user_version will store the 1-indexed migration that was last applied
|
||||
var nextMigration int
|
||||
err := db.QueryRow("PRAGMA user_version;").Scan(&nextMigration)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get user_version: %w", err)
|
||||
}
|
||||
|
||||
for i := nextMigration; i < len(migrations); i++ {
|
||||
err := applyMigration(db, i)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to apply migration %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyMigration(db *sql.DB, migrationIndex int) error {
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start transaction: %w", err)
|
||||
}
|
||||
// Will noop if the transaction was committed
|
||||
defer tx.Rollback() //nolint:errcheck
|
||||
|
||||
err = migrations[migrationIndex](tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(fmt.Sprintf("PRAGMA user_version = %d;", migrationIndex+1))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set user_version: %w", err)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to commit transaction: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initialSetup(tx *sql.Tx) error {
|
||||
// Create the initial user
|
||||
_, err := tx.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS "versions" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"mod_reference" TEXT NOT NULL,
|
||||
"version" TEXT NOT NULL,
|
||||
"game_version" TEXT NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS "mod_reference" ON "versions" ("mod_reference");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "mod_version" ON "versions" ("mod_reference", "version");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "dependencies" (
|
||||
"version_id" TEXT NOT NULL,
|
||||
"dependency" TEXT NOT NULL,
|
||||
"condition" TEXT NOT NULL,
|
||||
"optional" INT NOT NULL,
|
||||
FOREIGN KEY ("version_id") REFERENCES "versions" ("id") ON DELETE CASCADE,
|
||||
PRIMARY KEY ("version_id", "dependency")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "targets" (
|
||||
"version_id" TEXT NOT NULL,
|
||||
"target_name" TEXT NOT NULL,
|
||||
"link" TEXT NOT NULL,
|
||||
"hash" TEXT NOT NULL,
|
||||
"size" INT NOT NULL,
|
||||
FOREIGN KEY ("version_id") REFERENCES "versions" ("id") ON DELETE CASCADE,
|
||||
PRIMARY KEY ("version_id", "target_name")
|
||||
);
|
||||
`)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create initial tables: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRequiredOnRemote(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
ALTER TABLE "versions" ADD COLUMN "required_on_remote" INT NOT NULL DEFAULT 1;
|
||||
`)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add required_on_remote column: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -8,9 +8,10 @@ import (
|
|||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||
|
||||
// sqlite driver
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
@ -36,43 +37,20 @@ func Init() error {
|
|||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA foreign_keys = ON;
|
||||
PRAGMA busy_timeout = 5000;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "versions" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"mod_reference" TEXT NOT NULL,
|
||||
"version" TEXT NOT NULL,
|
||||
"game_version" TEXT NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS "mod_reference" ON "versions" ("mod_reference");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "mod_version" ON "versions" ("mod_reference", "version");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "dependencies" (
|
||||
"version_id" TEXT NOT NULL,
|
||||
"dependency" TEXT NOT NULL,
|
||||
"condition" TEXT NOT NULL,
|
||||
"optional" INT NOT NULL,
|
||||
FOREIGN KEY ("version_id") REFERENCES "versions" ("id") ON DELETE CASCADE,
|
||||
PRIMARY KEY ("version_id", "dependency")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "targets" (
|
||||
"version_id" TEXT NOT NULL,
|
||||
"target_name" TEXT NOT NULL,
|
||||
"link" TEXT NOT NULL,
|
||||
"hash" TEXT NOT NULL,
|
||||
"size" INT NOT NULL,
|
||||
FOREIGN KEY ("version_id") REFERENCES "versions" ("id") ON DELETE CASCADE,
|
||||
PRIMARY KEY ("version_id", "target_name")
|
||||
);
|
||||
`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to setup tables: %w", err)
|
||||
return fmt.Errorf("failed to setup connection pragmas: %w", err)
|
||||
}
|
||||
|
||||
err = applyMigrations(db)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to apply migrations: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Add(modReference string, modVersions []resolver.ModVersion) {
|
||||
func Add(modReference string, modVersions []ficsit.ModVersion) {
|
||||
dbWriteMutex.Lock()
|
||||
defer dbWriteMutex.Unlock()
|
||||
|
||||
|
@ -93,7 +71,7 @@ func Add(modReference string, modVersions []resolver.ModVersion) {
|
|||
for _, modVersion := range modVersions {
|
||||
l := slog.With(slog.String("mod", modReference), slog.String("version", modVersion.Version))
|
||||
|
||||
_, err = tx.Exec("INSERT INTO versions (id, mod_reference, version, game_version) VALUES (?, ?, ?, ?)", modVersion.ID, modReference, modVersion.Version, modVersion.GameVersion)
|
||||
_, err = tx.Exec("INSERT INTO versions (id, mod_reference, version, game_version, required_on_remote) VALUES (?, ?, ?, ?, ?)", modVersion.ID, modReference, modVersion.Version, modVersion.GameVersion, modVersion.RequiredOnRemote)
|
||||
if err != nil {
|
||||
l.Error("failed to insert mod version into local registry", slog.Any("err", err))
|
||||
return
|
||||
|
@ -121,17 +99,17 @@ func Add(modReference string, modVersions []resolver.ModVersion) {
|
|||
}
|
||||
}
|
||||
|
||||
func GetModVersions(modReference string) ([]resolver.ModVersion, error) {
|
||||
versionRows, err := db.Query("SELECT id, version, game_version FROM versions WHERE mod_reference = ?", modReference)
|
||||
func GetModVersions(modReference string) ([]ficsit.ModVersion, error) {
|
||||
versionRows, err := db.Query("SELECT id, version, game_version, required_on_remote FROM versions WHERE mod_reference = ?", modReference)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch mod versions from local registry: %w", err)
|
||||
}
|
||||
defer versionRows.Close()
|
||||
|
||||
var versions []resolver.ModVersion
|
||||
var versions []ficsit.ModVersion
|
||||
for versionRows.Next() {
|
||||
var version resolver.ModVersion
|
||||
err = versionRows.Scan(&version.ID, &version.Version, &version.GameVersion)
|
||||
var version ficsit.ModVersion
|
||||
err = versionRows.Scan(&version.ID, &version.Version, &version.GameVersion, &version.RequiredOnRemote)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan version row: %w", err)
|
||||
}
|
||||
|
@ -156,8 +134,8 @@ func GetModVersions(modReference string) ([]resolver.ModVersion, error) {
|
|||
return versions, nil
|
||||
}
|
||||
|
||||
func getVersionDependencies(versionID string) ([]resolver.Dependency, error) {
|
||||
var dependencies []resolver.Dependency
|
||||
func getVersionDependencies(versionID string) ([]ficsit.Dependency, error) {
|
||||
var dependencies []ficsit.Dependency
|
||||
dependencyRows, err := db.Query("SELECT dependency, condition, optional FROM dependencies WHERE version_id = ?", versionID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch dependencies from local registry: %w", err)
|
||||
|
@ -165,7 +143,7 @@ func getVersionDependencies(versionID string) ([]resolver.Dependency, error) {
|
|||
defer dependencyRows.Close()
|
||||
|
||||
for dependencyRows.Next() {
|
||||
var dependency resolver.Dependency
|
||||
var dependency ficsit.Dependency
|
||||
err = dependencyRows.Scan(&dependency.ModID, &dependency.Condition, &dependency.Optional)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan dependency row: %w", err)
|
||||
|
@ -176,8 +154,8 @@ func getVersionDependencies(versionID string) ([]resolver.Dependency, error) {
|
|||
return dependencies, nil
|
||||
}
|
||||
|
||||
func getVersionTargets(versionID string) ([]resolver.Target, error) {
|
||||
var targets []resolver.Target
|
||||
func getVersionTargets(versionID string) ([]ficsit.Target, error) {
|
||||
var targets []ficsit.Target
|
||||
targetRows, err := db.Query("SELECT target_name, link, hash, size FROM targets WHERE version_id = ?", versionID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch targets from local registry: %w", err)
|
||||
|
@ -185,7 +163,7 @@ func getVersionTargets(versionID string) ([]resolver.Target, error) {
|
|||
defer targetRows.Close()
|
||||
|
||||
for targetRows.Next() {
|
||||
var target resolver.Target
|
||||
var target ficsit.Target
|
||||
err = targetRows.Scan(&target.TargetName, &target.Link, &target.Hash, &target.Size)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan target row: %w", err)
|
||||
|
|
41
cli/provider/converter.go
Normal file
41
cli/provider/converter.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||
)
|
||||
|
||||
func convertFicsitVersionsToResolver(versions []ficsit.ModVersion) []resolver.ModVersion {
|
||||
modVersions := make([]resolver.ModVersion, len(versions))
|
||||
for i, modVersion := range versions {
|
||||
dependencies := make([]resolver.Dependency, len(modVersion.Dependencies))
|
||||
for j, dependency := range modVersion.Dependencies {
|
||||
dependencies[j] = resolver.Dependency{
|
||||
ModID: dependency.ModID,
|
||||
Condition: dependency.Condition,
|
||||
Optional: dependency.Optional,
|
||||
}
|
||||
}
|
||||
|
||||
targets := make([]resolver.Target, len(modVersion.Targets))
|
||||
for j, target := range modVersion.Targets {
|
||||
targets[j] = resolver.Target{
|
||||
TargetName: resolver.TargetName(target.TargetName),
|
||||
Link: viper.GetString("api-base") + target.Link,
|
||||
Hash: target.Hash,
|
||||
Size: target.Size,
|
||||
}
|
||||
}
|
||||
|
||||
modVersions[i] = resolver.ModVersion{
|
||||
Version: modVersion.Version,
|
||||
GameVersion: modVersion.GameVersion,
|
||||
Dependencies: dependencies,
|
||||
Targets: targets,
|
||||
RequiredOnRemote: modVersion.RequiredOnRemote,
|
||||
}
|
||||
}
|
||||
return modVersions
|
||||
}
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/Khan/genqlient/graphql"
|
||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/satisfactorymodding/ficsit-cli/cli/localregistry"
|
||||
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||
|
@ -40,39 +39,9 @@ func (p FicsitProvider) ModVersionsWithDependencies(_ context.Context, modID str
|
|||
return nil, errors.New(response.Error.Message)
|
||||
}
|
||||
|
||||
modVersions := make([]resolver.ModVersion, len(response.Data))
|
||||
for i, modVersion := range response.Data {
|
||||
dependencies := make([]resolver.Dependency, len(modVersion.Dependencies))
|
||||
for j, dependency := range modVersion.Dependencies {
|
||||
dependencies[j] = resolver.Dependency{
|
||||
ModID: dependency.ModID,
|
||||
Condition: dependency.Condition,
|
||||
Optional: dependency.Optional,
|
||||
}
|
||||
}
|
||||
localregistry.Add(modID, response.Data)
|
||||
|
||||
targets := make([]resolver.Target, len(modVersion.Targets))
|
||||
for j, target := range modVersion.Targets {
|
||||
targets[j] = resolver.Target{
|
||||
TargetName: resolver.TargetName(target.TargetName),
|
||||
Link: viper.GetString("api-base") + target.Link,
|
||||
Hash: target.Hash,
|
||||
Size: target.Size,
|
||||
}
|
||||
}
|
||||
|
||||
modVersions[i] = resolver.ModVersion{
|
||||
ID: modVersion.ID,
|
||||
Version: modVersion.Version,
|
||||
GameVersion: modVersion.GameVersion,
|
||||
Dependencies: dependencies,
|
||||
Targets: targets,
|
||||
}
|
||||
}
|
||||
|
||||
localregistry.Add(modID, modVersions)
|
||||
|
||||
return modVersions, err
|
||||
return convertFicsitVersionsToResolver(response.Data), nil
|
||||
}
|
||||
|
||||
func (p FicsitProvider) GetModName(context context.Context, modReference string) (*resolver.ModName, error) {
|
||||
|
|
|
@ -127,7 +127,7 @@ func (p LocalProvider) ModVersionsWithDependencies(_ context.Context, modID stri
|
|||
|
||||
// TODO: only list as available the versions that have at least one target cached
|
||||
|
||||
return modVersions, nil
|
||||
return convertFicsitVersionsToResolver(modVersions), nil
|
||||
}
|
||||
|
||||
func (p LocalProvider) GetModName(_ context.Context, modReference string) (*resolver.ModName, error) {
|
||||
|
|
|
@ -4,7 +4,9 @@ import (
|
|||
"log/slog"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/MarvinJWendt/testza"
|
||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||
|
@ -32,6 +34,108 @@ func installWatcher() chan<- InstallUpdate {
|
|||
return c
|
||||
}
|
||||
|
||||
func TestClientOnlyMod(t *testing.T) {
|
||||
ctx, err := InitCLI(false)
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
err = ctx.Wipe()
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
ctx.Provider = MockProvider{}
|
||||
|
||||
profileName := "ClientOnlyModTest"
|
||||
profile, err := ctx.Profiles.AddProfile(profileName)
|
||||
profile.RequiredTargets = []resolver.TargetName{resolver.TargetNameWindows, resolver.TargetNameWindowsServer, resolver.TargetNameLinuxServer}
|
||||
testza.AssertNoError(t, err)
|
||||
testza.AssertNoError(t, profile.AddMod("ClientOnlyMod", "<=0.0.1"))
|
||||
|
||||
serverLocation := os.Getenv("SF_DEDICATED_SERVER")
|
||||
if serverLocation != "" {
|
||||
time.Sleep(time.Second)
|
||||
testza.AssertNoError(t, os.RemoveAll(filepath.Join(serverLocation, "FactoryGame", "Mods")))
|
||||
time.Sleep(time.Second)
|
||||
|
||||
installation, err := ctx.Installations.AddInstallation(ctx, serverLocation, profileName)
|
||||
testza.AssertNoError(t, err)
|
||||
testza.AssertNotNil(t, installation)
|
||||
|
||||
err = installation.Install(ctx, installWatcher())
|
||||
testza.AssertNoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerOnlyMod(t *testing.T) {
|
||||
ctx, err := InitCLI(false)
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
err = ctx.Wipe()
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
ctx.Provider = MockProvider{}
|
||||
|
||||
profileName := "ServerOnlyModTest"
|
||||
profile, err := ctx.Profiles.AddProfile(profileName)
|
||||
profile.RequiredTargets = []resolver.TargetName{resolver.TargetNameWindows, resolver.TargetNameWindowsServer, resolver.TargetNameLinuxServer}
|
||||
testza.AssertNoError(t, err)
|
||||
testza.AssertNoError(t, profile.AddMod("ServerOnlyMod", "<=0.0.1"))
|
||||
|
||||
serverLocation := os.Getenv("SF_DEDICATED_SERVER")
|
||||
if serverLocation != "" {
|
||||
time.Sleep(time.Second)
|
||||
testza.AssertNoError(t, os.RemoveAll(filepath.Join(serverLocation, "FactoryGame", "Mods")))
|
||||
time.Sleep(time.Second)
|
||||
|
||||
installation, err := ctx.Installations.AddInstallation(ctx, serverLocation, profileName)
|
||||
testza.AssertNoError(t, err)
|
||||
testza.AssertNotNil(t, installation)
|
||||
|
||||
err = installation.Install(ctx, installWatcher())
|
||||
testza.AssertNoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveWhenNotSupported(t *testing.T) {
|
||||
ctx, err := InitCLI(false)
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
err = ctx.Wipe()
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
ctx.Provider = MockProvider{}
|
||||
|
||||
profileName := "ClientOnlyModTest"
|
||||
profile, err := ctx.Profiles.AddProfile(profileName)
|
||||
profile.RequiredTargets = []resolver.TargetName{resolver.TargetNameWindows, resolver.TargetNameWindowsServer, resolver.TargetNameLinuxServer}
|
||||
testza.AssertNoError(t, err)
|
||||
testza.AssertNoError(t, profile.AddMod("LaterClientOnlyMod", "0.0.1"))
|
||||
|
||||
serverLocation := os.Getenv("SF_DEDICATED_SERVER")
|
||||
if serverLocation != "" {
|
||||
time.Sleep(time.Second)
|
||||
testza.AssertNoError(t, os.RemoveAll(filepath.Join(serverLocation, "FactoryGame", "Mods")))
|
||||
time.Sleep(time.Second)
|
||||
|
||||
installation, err := ctx.Installations.AddInstallation(ctx, serverLocation, profileName)
|
||||
testza.AssertNoError(t, err)
|
||||
testza.AssertNotNil(t, installation)
|
||||
|
||||
err = installation.Install(ctx, installWatcher())
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
_, err = os.Stat(filepath.Join(serverLocation, "FactoryGame", "Mods", "LaterClientOnlyMod"))
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
testza.AssertNoError(t, profile.AddMod("LaterClientOnlyMod", "0.0.2"))
|
||||
|
||||
err = installation.Install(ctx, installWatcher())
|
||||
testza.AssertNoError(t, err)
|
||||
|
||||
_, err = os.Stat(filepath.Join(serverLocation, "FactoryGame", "Mods", "LaterClientOnlyMod"))
|
||||
testza.AssertNotNil(t, err)
|
||||
testza.AssertErrorIs(t, err, os.ErrNotExist)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateMods(t *testing.T) {
|
||||
ctx, err := InitCLI(false)
|
||||
testza.AssertNoError(t, err)
|
||||
|
|
|
@ -70,19 +70,28 @@ func (m MockProvider) Mods(_ context.Context, f ficsit.ModFilter) (*ficsit.ModsR
|
|||
}, nil
|
||||
}
|
||||
|
||||
var commonTargets = []resolver.Target{
|
||||
{
|
||||
var windowsTarget = resolver.Target{
|
||||
TargetName: "Windows",
|
||||
Link: "https://api.ficsit.dev/v1/version/7QcfNdo5QAAyoC/Windows/download",
|
||||
Hash: "698df20278b3de3ec30405569a22050c6721cc682389312258c14948bd8f38ae",
|
||||
},
|
||||
{
|
||||
}
|
||||
|
||||
var windowsServerTarget = resolver.Target{
|
||||
TargetName: "WindowsServer",
|
||||
Link: "https://api.ficsit.dev/v1/version/7QcfNdo5QAAyoC/WindowsServer/download",
|
||||
Hash: "7be01ed372e0cf3287a04f5cb32bb9dcf6f6e7a5b7603b7e43669ec4c6c1457f",
|
||||
},
|
||||
{
|
||||
}
|
||||
|
||||
var linuxServerTarget = resolver.Target{
|
||||
TargetName: "LinuxServer",
|
||||
Link: "https://api.ficsit.dev/v1/version/7QcfNdo5QAAyoC/LinuxServer/download",
|
||||
Hash: "bdbd4cb1b472a5316621939ae2fe270fd0e3c0f0a75666a9cbe74ff1313c3663",
|
||||
},
|
||||
}
|
||||
|
||||
var commonTargets = []resolver.Target{
|
||||
windowsTarget,
|
||||
windowsServerTarget,
|
||||
linuxServerTarget,
|
||||
}
|
||||
|
||||
func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID string) ([]resolver.ModVersion, error) {
|
||||
|
@ -90,7 +99,6 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
|||
case "AreaActions":
|
||||
return []resolver.ModVersion{
|
||||
{
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.6.7",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
|
@ -100,9 +108,9 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
|||
},
|
||||
},
|
||||
Targets: commonTargets,
|
||||
RequiredOnRemote: true,
|
||||
},
|
||||
{
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.6.6",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
|
@ -112,9 +120,9 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
|||
},
|
||||
},
|
||||
Targets: commonTargets,
|
||||
RequiredOnRemote: true,
|
||||
},
|
||||
{
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.6.5",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
|
@ -124,12 +132,12 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
|||
},
|
||||
},
|
||||
Targets: commonTargets,
|
||||
RequiredOnRemote: true,
|
||||
},
|
||||
}, nil
|
||||
case "FicsitRemoteMonitoring":
|
||||
return []resolver.ModVersion{
|
||||
{
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "0.10.1",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
|
@ -139,9 +147,9 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
|||
},
|
||||
},
|
||||
Targets: commonTargets,
|
||||
RequiredOnRemote: true,
|
||||
},
|
||||
{
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "0.10.0",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
|
@ -151,9 +159,9 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
|||
},
|
||||
},
|
||||
Targets: commonTargets,
|
||||
RequiredOnRemote: true,
|
||||
},
|
||||
{
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "0.9.8",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
|
@ -163,6 +171,71 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
|||
},
|
||||
},
|
||||
Targets: commonTargets,
|
||||
RequiredOnRemote: true,
|
||||
},
|
||||
}, nil
|
||||
case "ClientOnlyMod":
|
||||
return []resolver.ModVersion{
|
||||
{
|
||||
Version: "0.0.1",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
},
|
||||
Targets: []resolver.Target{
|
||||
windowsTarget,
|
||||
},
|
||||
RequiredOnRemote: false,
|
||||
},
|
||||
}, nil
|
||||
case "ServerOnlyMod":
|
||||
return []resolver.ModVersion{
|
||||
{
|
||||
Version: "0.0.1",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
},
|
||||
Targets: []resolver.Target{
|
||||
windowsServerTarget,
|
||||
linuxServerTarget,
|
||||
},
|
||||
RequiredOnRemote: false,
|
||||
},
|
||||
}, nil
|
||||
case "LaterClientOnlyMod":
|
||||
return []resolver.ModVersion{
|
||||
{
|
||||
Version: "0.0.1",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
},
|
||||
Targets: commonTargets,
|
||||
RequiredOnRemote: true,
|
||||
},
|
||||
{
|
||||
Version: "0.0.2",
|
||||
Dependencies: []resolver.Dependency{
|
||||
{
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
},
|
||||
Targets: []resolver.Target{
|
||||
windowsTarget,
|
||||
},
|
||||
RequiredOnRemote: false,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ type ModVersion struct {
|
|||
GameVersion string `json:"game_version"`
|
||||
Dependencies []Dependency `json:"dependencies"`
|
||||
Targets []Target `json:"targets"`
|
||||
RequiredOnRemote bool `json:"required_on_remote"`
|
||||
}
|
||||
|
||||
type Dependency struct {
|
||||
|
|
2
go.mod
2
go.mod
|
@ -26,7 +26,7 @@ require (
|
|||
github.com/puzpuzpuz/xsync/v3 v3.0.2
|
||||
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f
|
||||
github.com/samber/slog-multi v1.0.2
|
||||
github.com/satisfactorymodding/ficsit-resolver v0.0.3
|
||||
github.com/satisfactorymodding/ficsit-resolver v0.0.6
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/viper v1.18.1
|
||||
goftp.io/server/v2 v2.0.1
|
||||
|
|
4
go.sum
4
go.sum
|
@ -215,8 +215,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
|||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/samber/slog-multi v1.0.2 h1:6BVH9uHGAsiGkbbtQgAOQJMpKgV8unMrHhhJaw+X1EQ=
|
||||
github.com/samber/slog-multi v1.0.2/go.mod h1:uLAvHpGqbYgX4FSL0p1ZwoLuveIAJvBECtE07XmYvFo=
|
||||
github.com/satisfactorymodding/ficsit-resolver v0.0.3 h1:Q+BV1w1S42accsHbew9BmwcYdbAtSYfeVlQpRJiBhGg=
|
||||
github.com/satisfactorymodding/ficsit-resolver v0.0.3/go.mod h1:ckKMmMvDoYbbkEbWXEsMes608uvv6EKphXPhHX8LKSc=
|
||||
github.com/satisfactorymodding/ficsit-resolver v0.0.6 h1:4iCIHOg3z+AvwSVeWtu+k9aysLOL9+FIszCbiKOG2oo=
|
||||
github.com/satisfactorymodding/ficsit-resolver v0.0.6/go.mod h1:ckKMmMvDoYbbkEbWXEsMes608uvv6EKphXPhHX8LKSc=
|
||||
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
|
||||
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
|
|
Loading…
Reference in a new issue