From 5f2e60a9e2d5bbf16d520a0a2dcacdef54efd73f Mon Sep 17 00:00:00 2001 From: Vilsol Date: Thu, 7 Dec 2023 18:57:31 +0200 Subject: [PATCH] feat: multi targets (#44) * feat: use mod version targets * chore: lint * chore: remove unused * chore: target dev on ci * fix: rename WindowsNoEditor target to Windows fix: close file reader * fix: ensure closure of downloaded mod * fix: ensure all important events are sent * fix: lock adding files to cache --------- Co-authored-by: mircearoata --- .github/workflows/push.yaml | 6 +- .github/workflows/release.yml | 2 +- cfg/test_defaults.go | 2 +- cli/cache/cache.go | 19 +- cli/cache/download.go | 8 +- cli/cache/integrity.go | 18 +- cli/context.go | 2 +- cli/dependency_resolver.go | 51 +- cli/installations.go | 39 +- cli/installations_test.go | 4 +- cli/lockfile.go | 54 ++- cli/platforms.go | 4 + cli/profiles.go | 2 +- cli/provider/ficsit.go | 4 - cli/provider/local.go | 82 +--- cli/provider/mixed.go | 11 +- cli/provider/provider.go | 3 +- cli/resolving_test.go | 37 +- cli/test_helpers.go | 444 ++++++++++++++++++ cli/types.go | 8 +- docs/ficsit.md | 4 +- docs/ficsit_apply.md | 4 +- docs/ficsit_cli.md | 4 +- docs/ficsit_installation.md | 5 +- docs/ficsit_installation_add.md | 4 +- docs/ficsit_installation_ls.md | 4 +- docs/ficsit_installation_remove.md | 4 +- docs/ficsit_installation_set-profile.md | 4 +- docs/ficsit_installation_set-vanilla.md | 39 ++ docs/ficsit_profile.md | 4 +- docs/ficsit_profile_delete.md | 4 +- docs/ficsit_profile_ls.md | 4 +- docs/ficsit_profile_mods.md | 4 +- docs/ficsit_profile_new.md | 4 +- docs/ficsit_profile_rename.md | 4 +- docs/ficsit_search.md | 4 +- docs/ficsit_smr.md | 4 +- docs/ficsit_smr_upload.md | 4 +- docs/ficsit_version.md | 4 +- .../mod_versions_with_dependencies.graphql | 5 + .../queries/resolve_mod_dependencies.graphql | 17 - ficsit/queries/sml_versions.graphql | 4 + ficsit/types.go | 266 ++++------- tea/components/header.go | 2 +- tea/components/types.go | 2 +- tea/root.go | 2 +- tea/scenes/mods/update_mods.go | 4 +- utils/io.go | 5 +- utils/version.go | 2 +- 49 files changed, 824 insertions(+), 397 deletions(-) create mode 100644 cli/test_helpers.go create mode 100644 docs/ficsit_installation_set-vanilla.md delete mode 100644 ficsit/queries/resolve_mod_dependencies.graphql diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index 47b3bf8..0884643 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v2 - name: Download GQL schema - run: "npx graphqurl https://api.ficsit.app/v2/query --introspect -H 'content-type: application/json' > schema.graphql" + run: "npx graphqurl https://api.ficsit.dev/v2/query --introspect -H 'content-type: application/json' > schema.graphql" - name: Go Generate run: go generate -tags tools -x ./... @@ -39,7 +39,7 @@ jobs: uses: actions/checkout@v2 - name: Download GQL schema - run: "npx graphqurl https://api.ficsit.app/v2/query --introspect -H 'content-type: application/json' > schema.graphql" + run: "npx graphqurl https://api.ficsit.dev/v2/query --introspect -H 'content-type: application/json' > schema.graphql" - name: Go Generate run: go generate -tags tools -x ./... @@ -82,7 +82,7 @@ jobs: run: tree /F - name: Download GQL schema - run: "npx graphqurl https://api.ficsit.app/v2/query --introspect -H 'content-type: application/json' > schema.graphql" + run: "npx graphqurl https://api.ficsit.dev/v2/query --introspect -H 'content-type: application/json' > schema.graphql" - name: Go Generate run: go generate -tags tools -x ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ae203c7..b90c90a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: fetch-depth: 0 - name: Download GQL schema - run: "npx graphqurl https://api.ficsit.app/v2/query --introspect -H 'content-type: application/json' > schema.graphql" + run: "npx graphqurl https://api.ficsit.dev/v2/query --introspect -H 'content-type: application/json' > schema.graphql" - uses: kielabokkie/ssh-key-and-known-hosts-action@v1 with: diff --git a/cfg/test_defaults.go b/cfg/test_defaults.go index 1e71690..d6ac288 100644 --- a/cfg/test_defaults.go +++ b/cfg/test_defaults.go @@ -15,7 +15,7 @@ func SetDefaults() { viper.SetDefault("profiles-file", "profiles.json") viper.SetDefault("installations-file", "installations.json") viper.SetDefault("dry-run", false) - viper.SetDefault("api-base", "https://api.ficsit.app") + viper.SetDefault("api-base", "https://api.ficsit.dev") viper.SetDefault("graphql-api", "/v2/query") viper.SetDefault("concurrent-downloads", 5) } diff --git a/cli/cache/cache.go b/cli/cache/cache.go index 8dee8bb..89fdc35 100644 --- a/cli/cache/cache.go +++ b/cli/cache/cache.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/pkg/errors" + "github.com/puzpuzpuz/xsync/v3" "github.com/rs/zerolog/log" "github.com/spf13/viper" ) @@ -24,9 +25,9 @@ type File struct { Size int64 } -var loadedCache map[string][]File +var loadedCache *xsync.MapOf[string, []File] -func GetCache() (map[string][]File, error) { +func GetCache() (*xsync.MapOf[string, []File], error) { if loadedCache != nil { return loadedCache, nil } @@ -38,14 +39,15 @@ func GetCacheMod(mod string) ([]File, error) { if err != nil { return nil, err } - return cache[mod], nil + value, _ := cache.Load(mod) + return value, nil } -func LoadCache() (map[string][]File, error) { - loadedCache = map[string][]File{} +func LoadCache() (*xsync.MapOf[string, []File], error) { + loadedCache = xsync.NewMapOf[string, []File]() downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache") if _, err := os.Stat(downloadCache); os.IsNotExist(err) { - return map[string][]File{}, nil + return loadedCache, nil } items, err := os.ReadDir(downloadCache) @@ -75,7 +77,10 @@ func addFileToCache(filename string) (*File, error) { return nil, errors.Wrap(err, "failed to read cache file") } - loadedCache[cacheFile.ModReference] = append(loadedCache[cacheFile.ModReference], *cacheFile) + loadedCache.Compute(cacheFile.ModReference, func(oldValue []File, _ bool) ([]File, bool) { + return append(oldValue, *cacheFile), false + }) + return cacheFile, nil } diff --git a/cli/cache/download.go b/cli/cache/download.go index 98b2bec..4f6774c 100644 --- a/cli/cache/download.go +++ b/cli/cache/download.go @@ -13,7 +13,7 @@ import ( "github.com/satisfactorymodding/ficsit-cli/utils" ) -func DownloadOrCache(cacheKey string, hash string, url string, updates chan<- utils.GenericProgress, downloadSemaphore chan int) (io.ReaderAt, int64, error) { +func DownloadOrCache(cacheKey string, hash string, url string, updates chan<- utils.GenericProgress, downloadSemaphore chan int) (*os.File, int64, error) { if updates != nil { defer close(updates) } @@ -36,6 +36,7 @@ func DownloadOrCache(cacheKey string, hash string, url string, updates chan<- ut if err != nil { return nil, 0, errors.Wrap(err, "failed to open file: "+location) } + defer f.Close() existingHash, err = utils.SHA256Data(f) if err != nil { @@ -106,10 +107,7 @@ func DownloadOrCache(cacheKey string, hash string, url string, updates chan<- ut } if updates != nil { - select { - case updates <- utils.GenericProgress{Completed: resp.ContentLength, Total: resp.ContentLength}: - default: - } + updates <- utils.GenericProgress{Completed: resp.ContentLength, Total: resp.ContentLength} } _, err = addFileToCache(cacheKey) diff --git a/cli/cache/integrity.go b/cli/cache/integrity.go index 4c35976..6e9ea64 100644 --- a/cli/cache/integrity.go +++ b/cli/cache/integrity.go @@ -8,6 +8,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/puzpuzpuz/xsync/v3" "github.com/rs/zerolog/log" "github.com/spf13/viper" @@ -20,7 +21,7 @@ type hashInfo struct { Size int64 } -var hashCache map[string]hashInfo +var hashCache *xsync.MapOf[string, hashInfo] var integrityFilename = ".integrity" @@ -28,7 +29,7 @@ func getFileHash(file string) (string, error) { if hashCache == nil { loadHashCache() } - cachedHash, ok := hashCache[file] + cachedHash, ok := hashCache.Load(file) if !ok { return cacheFileHash(file) } @@ -58,17 +59,17 @@ func cacheFileHash(file string) (string, error) { if err != nil { return "", errors.Wrap(err, "failed to hash file") } - hashCache[file] = hashInfo{ + hashCache.Store(file, hashInfo{ Hash: hash, Size: stat.Size(), Modified: stat.ModTime(), - } + }) saveHashCache() return hash, nil } func loadHashCache() { - hashCache = map[string]hashInfo{} + hashCache = xsync.NewMapOf[string, hashInfo]() cacheFile := filepath.Join(viper.GetString("cache-dir"), "downloadCache", integrityFilename) if _, err := os.Stat(cacheFile); os.IsNotExist(err) { return @@ -94,7 +95,12 @@ func loadHashCache() { func saveHashCache() { cacheFile := filepath.Join(viper.GetString("cache-dir"), "downloadCache", integrityFilename) - hashCacheJSON, err := json.Marshal(hashCache) + plainCache := make(map[string]hashInfo, hashCache.Size()) + hashCache.Range(func(k string, v hashInfo) bool { + plainCache[k] = v + return true + }) + hashCacheJSON, err := json.Marshal(plainCache) if err != nil { log.Warn().Err(err).Msg("failed to marshal hash cache") return diff --git a/cli/context.go b/cli/context.go index 0bf1ed7..90df643 100644 --- a/cli/context.go +++ b/cli/context.go @@ -14,7 +14,7 @@ type GlobalContext struct { Installations *Installations Profiles *Profiles APIClient graphql.Client - Provider *provider.MixedProvider + Provider provider.Provider } var globalContext *GlobalContext diff --git a/cli/dependency_resolver.go b/cli/dependency_resolver.go index e5158d2..a0b7c7a 100644 --- a/cli/dependency_resolver.go +++ b/cli/dependency_resolver.go @@ -16,7 +16,11 @@ import ( "github.com/satisfactorymodding/ficsit-cli/ficsit" ) -const smlDownloadTemplate = `https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v%s/SML.zip` +const ( + rootPkg = "$$root$$" + smlPkg = "SML" + factoryGamePkg = "FactoryGame" +) type DependencyResolver struct { provider provider.Provider @@ -26,12 +30,6 @@ func NewDependencyResolver(provider provider.Provider) DependencyResolver { return DependencyResolver{provider} } -var ( - rootPkg = "$$root$$" - smlPkg = "SML" - factoryGamePkg = "FactoryGame" -) - type ficsitAPISource struct { provider provider.Provider lockfile *LockFile @@ -106,7 +104,7 @@ func (f *ficsitAPISource) GetPackageVersions(pkg string) ([]pubgrub.PackageVersi func (f *ficsitAPISource) PickVersion(pkg string, versions []semver.Version) semver.Version { if f.lockfile != nil { - if existing, ok := (*f.lockfile)[pkg]; ok { + if existing, ok := f.lockfile.Mods[pkg]; ok { v, err := semver.NewVersion(existing.Version) if err == nil { if slices.ContainsFunc(versions, func(version semver.Version) bool { @@ -120,7 +118,7 @@ func (f *ficsitAPISource) PickVersion(pkg string, versions []semver.Version) sem return helpers.StandardVersionPriority(versions) } -func (d DependencyResolver) ResolveModDependencies(constraints map[string]string, lockFile *LockFile, gameVersion int) (LockFile, error) { +func (d DependencyResolver) ResolveModDependencies(constraints map[string]string, lockFile *LockFile, gameVersion int) (*LockFile, error) { smlVersionsDB, err := d.provider.SMLVersions(context.TODO()) if err != nil { return nil, errors.Wrap(err, "failed fetching SML versions") @@ -161,24 +159,43 @@ func (d DependencyResolver) ResolveModDependencies(constraints map[string]string delete(result, rootPkg) delete(result, factoryGamePkg) - outputLock := make(LockFile, len(result)) + outputLock := MakeLockfile() for k, v := range result { if k == smlPkg { - outputLock[k] = LockedMod{ - Version: v.String(), - Hash: "", - Link: fmt.Sprintf(smlDownloadTemplate, v.String()), + for _, version := range ficsitSource.smlVersions { + if version.Version == v.String() { + targets := make(map[string]LockedModTarget) + for _, target := range version.Targets { + targets[string(target.TargetName)] = LockedModTarget{ + Link: target.Link, + } + } + + outputLock.Mods[k] = LockedMod{ + Version: v.String(), + Targets: targets, + } + break + } } continue } + value, _ := ficsitSource.modVersionInfo.Load(k) versions := value.Mod.Versions for _, ver := range versions { if ver.Version == v.RawString() { - outputLock[k] = LockedMod{ + targets := make(map[string]LockedModTarget) + for _, target := range ver.Targets { + targets[string(target.TargetName)] = LockedModTarget{ + Link: viper.GetString("api-base") + target.Link, + Hash: target.Hash, + } + } + + outputLock.Mods[k] = LockedMod{ Version: v.String(), - Hash: ver.Hash, - Link: viper.GetString("api-base") + ver.Link, + Targets: targets, } break } diff --git a/cli/installations.go b/cli/installations.go index d0fc083..428545c 100644 --- a/cli/installations.go +++ b/cli/installations.go @@ -283,7 +283,7 @@ func (i *Installation) LockFile(ctx *GlobalContext) (*LockFile, error) { return lockFile, nil } -func (i *Installation) WriteLockFile(ctx *GlobalContext, lockfile LockFile) error { +func (i *Installation) WriteLockFile(ctx *GlobalContext, lockfile *LockFile) error { lockfilePath, err := i.LockFilePath(ctx) if err != nil { return err @@ -327,7 +327,7 @@ func (i *Installation) Wipe() error { return nil } -func (i *Installation) ResolveProfile(ctx *GlobalContext) (LockFile, error) { +func (i *Installation) ResolveProfile(ctx *GlobalContext) (*LockFile, error) { lockFile, err := i.LockFile(ctx) if err != nil { return nil, err @@ -377,7 +377,12 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate) return errors.Wrap(err, "failed to validate installation") } - lockfile := make(LockFile) + platform, err := i.GetPlatform(ctx) + if err != nil { + return errors.Wrap(err, "failed to detect platform") + } + + lockfile := MakeLockfile() if !i.Vanilla { var err error @@ -404,7 +409,7 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate) for _, entry := range dir { if entry.IsDir() { - if _, ok := lockfile[entry.Name()]; !ok { + if _, ok := lockfile.Mods[entry.Name()]; !ok { modDir := filepath.Join(modsDirectory, entry.Name()) err := d.Exists(filepath.Join(modDir, ".smm")) if err == nil { @@ -438,7 +443,7 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate) Type: InstallUpdateTypeOverall, Progress: utils.GenericProgress{ Completed: int64(completed), - Total: int64(len(lockfile)), + Total: int64(len(lockfile.Mods)), }, } updates <- overallUpdate @@ -446,15 +451,21 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate) }() } - for modReference, version := range lockfile { + for modReference, version := range lockfile.Mods { channelUsers.Add(1) modReference := modReference version := version errg.Go(func() error { defer channelUsers.Done() + + target, ok := version.Targets[platform.TargetName] + if !ok { + return errors.Errorf("%s@%s not available for %s", modReference, version.Version, platform.TargetName) + } + // Only install if a link is provided, otherwise assume mod is already installed - if version.Link != "" { - err := downloadAndExtractMod(modReference, version.Version, version.Link, version.Hash, modsDirectory, updates, downloadSemaphore, d) + if target.Link != "" { + err := downloadAndExtractMod(modReference, version.Version, target.Link, target.Hash, modsDirectory, updates, downloadSemaphore, d) if err != nil { return errors.Wrapf(err, "failed to install %s@%s", modReference, version.Version) } @@ -546,6 +557,8 @@ func downloadAndExtractMod(modReference string, version string, link string, has return errors.Wrap(err, "failed to download "+modReference+" from: "+link) } + defer reader.Close() + var extractUpdates chan utils.GenericProgress var wg sync.WaitGroup @@ -557,16 +570,13 @@ func downloadAndExtractMod(modReference string, version string, link string, has go func() { defer wg.Done() for up := range extractUpdates { - select { - case updates <- InstallUpdate{ + updates <- InstallUpdate{ Item: InstallUpdateItem{ Mod: modReference, Version: version, }, Type: InstallUpdateTypeModExtract, Progress: up, - }: - default: } } }() @@ -578,15 +588,12 @@ func downloadAndExtractMod(modReference string, version string, link string, has } if updates != nil { - select { - case updates <- InstallUpdate{ + updates <- InstallUpdate{ Type: InstallUpdateTypeModComplete, Item: InstallUpdateItem{ Mod: modReference, Version: version, }, - }: - default: } close(extractUpdates) diff --git a/cli/installations_test.go b/cli/installations_test.go index b0e0f28..6a5b275 100644 --- a/cli/installations_test.go +++ b/cli/installations_test.go @@ -23,11 +23,13 @@ func TestAddInstallation(t *testing.T) { ctx, err := InitCLI(false) testza.AssertNoError(t, err) + ctx.Provider = MockProvider{} + profileName := "InstallationTest" profile, err := ctx.Profiles.AddProfile(profileName) testza.AssertNoError(t, err) testza.AssertNoError(t, profile.AddMod("AreaActions", ">=1.6.5")) - testza.AssertNoError(t, profile.AddMod("ArmorModules__Modpack_All", ">=1.4.1")) + testza.AssertNoError(t, profile.AddMod("RefinedPower", ">=3.2.10")) serverLocation := os.Getenv("SF_DEDICATED_SERVER") if serverLocation != "" { diff --git a/cli/lockfile.go b/cli/lockfile.go index f68e2d7..fb9c312 100644 --- a/cli/lockfile.go +++ b/cli/lockfile.go @@ -1,26 +1,54 @@ package cli -type LockFile map[string]LockedMod +type LockfileVersion int -type LockedMod struct { - Dependencies map[string]string `json:"dependencies"` - Version string `json:"version"` - Hash string `json:"hash"` - Link string `json:"link"` +const ( + InitialLockfileVersion = LockfileVersion(iota) + + ModTargetsLockfileVersion + + // Always last + nextLockfileVersion + CurrentLockfileVersion = nextLockfileVersion - 1 +) + +type LockFile struct { + Mods map[string]LockedMod `json:"mods"` + Version LockfileVersion `json:"version"` } -func (l LockFile) Clone() LockFile { - lockFile := make(LockFile) - for k, v := range l { - lockFile[k] = v +type LockedMod struct { + Dependencies map[string]string `json:"dependencies"` + Targets map[string]LockedModTarget `json:"targets"` + Version string `json:"version"` +} + +type LockedModTarget struct { + Hash string `json:"hash"` + Link string `json:"link"` +} + +func MakeLockfile() *LockFile { + return &LockFile{ + Mods: make(map[string]LockedMod), + Version: CurrentLockfileVersion, + } +} + +func (l *LockFile) Clone() *LockFile { + lockFile := &LockFile{ + Mods: make(map[string]LockedMod), + Version: l.Version, + } + for k, v := range l.Mods { + lockFile.Mods[k] = v } return lockFile } func (l *LockFile) Remove(modID ...string) *LockFile { - out := *l for _, s := range modID { - delete(out, s) + delete(l.Mods, s) } - return &out + return l } diff --git a/cli/platforms.go b/cli/platforms.go index 304bd40..3182f2a 100644 --- a/cli/platforms.go +++ b/cli/platforms.go @@ -5,19 +5,23 @@ import "path/filepath" type Platform struct { VersionPath string LockfilePath string + TargetName string } var platforms = []Platform{ { VersionPath: filepath.Join("Engine", "Binaries", "Linux", "UnrealServer-Linux-Shipping.version"), LockfilePath: filepath.Join("FactoryGame", "Mods"), + TargetName: "LinuxServer", }, { VersionPath: filepath.Join("Engine", "Binaries", "Win64", "UnrealServer-Win64-Shipping.version"), LockfilePath: filepath.Join("FactoryGame", "Mods"), + TargetName: "WindowsServer", }, { VersionPath: filepath.Join("Engine", "Binaries", "Win64", "FactoryGame-Win64-Shipping.version"), LockfilePath: filepath.Join("FactoryGame", "Mods"), + TargetName: "Windows", }, } diff --git a/cli/profiles.go b/cli/profiles.go index 8f0a334..f532784 100644 --- a/cli/profiles.go +++ b/cli/profiles.go @@ -288,7 +288,7 @@ func (p *Profile) HasMod(reference string) bool { // An optional lockfile can be passed if one exists. // // Returns an error if resolution is impossible. -func (p *Profile) Resolve(resolver DependencyResolver, lockFile *LockFile, gameVersion int) (LockFile, error) { +func (p *Profile) Resolve(resolver DependencyResolver, lockFile *LockFile, gameVersion int) (*LockFile, error) { toResolve := make(map[string]string) for modReference, mod := range p.Mods { if mod.Enabled { diff --git a/cli/provider/ficsit.go b/cli/provider/ficsit.go index 7c28520..fa95459 100644 --- a/cli/provider/ficsit.go +++ b/cli/provider/ficsit.go @@ -34,10 +34,6 @@ func (p ficsitProvider) SMLVersions(context context.Context) (*ficsit.SMLVersion return ficsit.SMLVersions(context, p.client) } -func (p ficsitProvider) ResolveModDependencies(context context.Context, filter []ficsit.ModVersionConstraint) (*ficsit.ResolveModDependenciesResponse, error) { - return ficsit.ResolveModDependencies(context, p.client, filter) -} - func (p ficsitProvider) ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) { return ficsit.ModVersionsWithDependencies(context, p.client, modID) } diff --git a/cli/provider/local.go b/cli/provider/local.go index 8a1b83b..1423f5c 100644 --- a/cli/provider/local.go +++ b/cli/provider/local.go @@ -5,7 +5,6 @@ import ( "strings" "time" - "github.com/Masterminds/semver/v3" "github.com/pkg/errors" "github.com/satisfactorymodding/ficsit-cli/cli/cache" @@ -26,9 +25,9 @@ func (p localProvider) Mods(_ context.Context, filter ficsit.ModFilter) (*ficsit mods := make([]ficsit.ModsModsGetModsModsMod, 0) - for modReference, files := range cachedMods { + cachedMods.Range(func(modReference string, files []cache.File) bool { if modReference == "SML" { - continue + return true } if len(filter.References) > 0 { @@ -42,7 +41,7 @@ func (p localProvider) Mods(_ context.Context, filter ficsit.ModFilter) (*ficsit } if skip { - continue + return true } } @@ -56,7 +55,9 @@ func (p localProvider) Mods(_ context.Context, filter ficsit.ModFilter) (*ficsit Popularity: 0, Hotness: 0, }) - } + + return true + }) if filter.Limit == 0 { filter.Limit = 25 @@ -175,77 +176,6 @@ func (p localProvider) SMLVersions(_ context.Context) (*ficsit.SMLVersionsRespon }, nil } -func (p localProvider) ResolveModDependencies(_ context.Context, filter []ficsit.ModVersionConstraint) (*ficsit.ResolveModDependenciesResponse, error) { - cachedMods, err := cache.GetCache() - if err != nil { - return nil, errors.Wrap(err, "failed to get cache") - } - - mods := make([]ficsit.ResolveModDependenciesModsModVersion, 0) - - constraintMap := make(map[string]string) - - for _, constraint := range filter { - constraintMap[constraint.ModIdOrReference] = constraint.Version - } - - for modReference, modFiles := range cachedMods { - constraint, ok := constraintMap[modReference] - if !ok { - continue - } - - semverConstraint, err := semver.NewConstraint(constraint) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse constraint for %s", modReference) - } - - versions := make([]ficsit.ResolveModDependenciesModsModVersionVersionsVersion, 0) - - for _, modFile := range modFiles { - semverVersion, err := semver.NewVersion(modFile.Plugin.SemVersion) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse version for %s", modReference) - } - - if !semverConstraint.Check(semverVersion) { - continue - } - - dependencies := make([]ficsit.ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency, 0) - - for _, dependency := range modFile.Plugin.Plugins { - if dependency.BasePlugin { - continue - } - dependencies = append(dependencies, ficsit.ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency{ - Mod_id: dependency.Name, - Condition: dependency.SemVersion, - Optional: dependency.Optional, - }) - } - - versions = append(versions, ficsit.ResolveModDependenciesModsModVersionVersionsVersion{ - Id: modReference + ":" + modFile.Plugin.SemVersion, - Version: modFile.Plugin.SemVersion, - Link: "", - Hash: modFile.Hash, - Dependencies: dependencies, - }) - } - - mods = append(mods, ficsit.ResolveModDependenciesModsModVersion{ - Id: modReference, - Mod_reference: modReference, - Versions: versions, - }) - } - - return &ficsit.ResolveModDependenciesResponse{ - Mods: mods, - }, nil -} - func (p localProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) { cachedModFiles, err := cache.GetCacheMod(modID) if err != nil { diff --git a/cli/provider/mixed.go b/cli/provider/mixed.go index c488ac4..0081f0c 100644 --- a/cli/provider/mixed.go +++ b/cli/provider/mixed.go @@ -50,13 +50,6 @@ func (p MixedProvider) SMLVersions(context context.Context) (*ficsit.SMLVersions return p.ficsitProvider.SMLVersions(context) } -func (p MixedProvider) ResolveModDependencies(context context.Context, filter []ficsit.ModVersionConstraint) (*ficsit.ResolveModDependenciesResponse, error) { - if p.Offline { - return p.localProvider.ResolveModDependencies(context, filter) - } - return p.ficsitProvider.ResolveModDependencies(context, filter) -} - func (p MixedProvider) ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) { if p.Offline { return p.localProvider.ModVersionsWithDependencies(context, modID) @@ -70,3 +63,7 @@ func (p MixedProvider) GetModName(context context.Context, modReference string) } return p.ficsitProvider.GetModName(context, modReference) } + +func (p MixedProvider) IsOffline() bool { + return p.Offline +} diff --git a/cli/provider/provider.go b/cli/provider/provider.go index f6aaae6..1e211db 100644 --- a/cli/provider/provider.go +++ b/cli/provider/provider.go @@ -11,8 +11,7 @@ type Provider interface { GetMod(context context.Context, modReference string) (*ficsit.GetModResponse, error) ModVersions(context context.Context, modReference string, filter ficsit.VersionFilter) (*ficsit.ModVersionsResponse, error) SMLVersions(context context.Context) (*ficsit.SMLVersionsResponse, error) - ResolveModDependencies(context context.Context, filter []ficsit.ModVersionConstraint) (*ficsit.ResolveModDependenciesResponse, error) - ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) GetModName(context context.Context, modReference string) (*ficsit.GetModNameResponse, error) + IsOffline() bool } diff --git a/cli/resolving_test.go b/cli/resolving_test.go index 51439c7..9f0bfbb 100644 --- a/cli/resolving_test.go +++ b/cli/resolving_test.go @@ -16,12 +16,7 @@ func init() { } func profilesGetResolver() DependencyResolver { - ctx, err := InitCLI(false) - if err != nil { - panic(err) - } - - return NewDependencyResolver(ctx.Provider) + return NewDependencyResolver(MockProvider{}) } func installWatcher() chan<- InstallUpdate { @@ -47,7 +42,7 @@ func TestProfileResolution(t *testing.T) { Name: DefaultProfileName, Mods: map[string]ProfileMod{ "RefinedPower": { - Version: "3.0.9", + Version: "3.2.10", Enabled: true, }, }, @@ -55,7 +50,7 @@ func TestProfileResolution(t *testing.T) { testza.AssertNoError(t, err) testza.AssertNotNil(t, resolved) - testza.AssertLen(t, resolved, 4) + testza.AssertLen(t, resolved.Mods, 4) } func TestProfileRequiredOlderVersion(t *testing.T) { @@ -65,17 +60,17 @@ func TestProfileRequiredOlderVersion(t *testing.T) { Name: DefaultProfileName, Mods: map[string]ProfileMod{ "RefinedPower": { - Version: "3.0.9", + Version: "3.2.11", Enabled: true, }, "RefinedRDLib": { - Version: "1.0.6", + Version: "1.1.5", Enabled: true, }, }, }).Resolve(resolver, nil, math.MaxInt) - testza.AssertEqual(t, "failed resolving profile dependencies: failed to solve dependencies: Because installing Refined Power (RefinedPower) \"3.0.9\" and Refined Power (RefinedPower) \"3.0.9\" depends on RefinedRDLib \"^1.0.7\", installing RefinedRDLib \"^1.0.7\".\nSo, because installing RefinedRDLib \"1.0.6\", version solving failed.", err.Error()) + testza.AssertEqual(t, "failed resolving profile dependencies: failed to solve dependencies: Because installing Refined Power (RefinedPower) \"3.2.11\" and Refined Power (RefinedPower) \"3.2.11\" depends on RefinedRDLib \"^1.1.6\", installing RefinedRDLib \"^1.1.6\".\nSo, because installing RefinedRDLib \"1.1.5\", version solving failed.", err.Error()) } func TestResolutionNonExistentMod(t *testing.T) { @@ -101,13 +96,15 @@ func TestUpdateMods(t *testing.T) { err = ctx.Wipe() testza.AssertNoError(t, err) + ctx.Provider = MockProvider{} + resolver := NewDependencyResolver(ctx.Provider) oldLockfile, err := (&Profile{ Name: DefaultProfileName, Mods: map[string]ProfileMod{ - "AreaActions": { - Version: "1.6.5", + "FicsitRemoteMonitoring": { + Version: "0.9.8", Enabled: true, }, }, @@ -115,12 +112,12 @@ func TestUpdateMods(t *testing.T) { testza.AssertNoError(t, err) testza.AssertNotNil(t, oldLockfile) - testza.AssertLen(t, oldLockfile, 2) + testza.AssertLen(t, oldLockfile.Mods, 2) profileName := "UpdateTest" profile, err := ctx.Profiles.AddProfile(profileName) testza.AssertNoError(t, err) - testza.AssertNoError(t, profile.AddMod("AreaActions", "<=1.6.6")) + testza.AssertNoError(t, profile.AddMod("FicsitRemoteMonitoring", "<=0.10.0")) serverLocation := os.Getenv("SF_DEDICATED_SERVER") if serverLocation != "" { @@ -137,17 +134,17 @@ func TestUpdateMods(t *testing.T) { lockFile, err := installation.LockFile(ctx) testza.AssertNoError(t, err) - testza.AssertEqual(t, 2, len(*lockFile)) - testza.AssertEqual(t, "1.6.5", (*lockFile)["AreaActions"].Version) + testza.AssertEqual(t, 2, len(lockFile.Mods)) + testza.AssertEqual(t, "0.9.8", (lockFile.Mods)["FicsitRemoteMonitoring"].Version) - err = installation.UpdateMods(ctx, []string{"AreaActions"}) + err = installation.UpdateMods(ctx, []string{"FicsitRemoteMonitoring"}) testza.AssertNoError(t, err) lockFile, err = installation.LockFile(ctx) testza.AssertNoError(t, err) - testza.AssertEqual(t, 2, len(*lockFile)) - testza.AssertEqual(t, "1.6.6", (*lockFile)["AreaActions"].Version) + testza.AssertEqual(t, 2, len(lockFile.Mods)) + testza.AssertEqual(t, "0.10.0", (lockFile.Mods)["FicsitRemoteMonitoring"].Version) err = installation.Install(ctx, installWatcher()) testza.AssertNoError(t, err) diff --git a/cli/test_helpers.go b/cli/test_helpers.go new file mode 100644 index 0000000..c0102f3 --- /dev/null +++ b/cli/test_helpers.go @@ -0,0 +1,444 @@ +package cli + +import ( + "context" + + "github.com/satisfactorymodding/ficsit-cli/cli/provider" + "github.com/satisfactorymodding/ficsit-cli/ficsit" +) + +var _ provider.Provider = (*MockProvider)(nil) + +type MockProvider struct{} + +func (m MockProvider) Mods(_ context.Context, _ ficsit.ModFilter) (*ficsit.ModsResponse, error) { + // Currently used only by TUI + return nil, nil +} + +func (m MockProvider) GetMod(_ context.Context, _ string) (*ficsit.GetModResponse, error) { + // Currently used only by TUI + return nil, nil +} + +func (m MockProvider) ModVersions(_ context.Context, modReference string, _ ficsit.VersionFilter) (*ficsit.ModVersionsResponse, error) { + switch modReference { + //nolint + case "RefinedPower": + return &ficsit.ModVersionsResponse{Mod: ficsit.ModVersionsMod{ + Id: "DGiLzB3ZErWu2V", + Versions: []ficsit.ModVersionsModVersionsVersion{ + {Id: "Eqgr4VcB8y1z9a", Version: "3.2.13"}, + {Id: "BwVKMJNP8doDLg", Version: "3.2.11"}, + {Id: "4XTjMpqFngbu9r", Version: "3.2.10"}, + }, + }}, nil + //nolint + case "RefinedRDLib": + return &ficsit.ModVersionsResponse{Mod: ficsit.ModVersionsMod{ + Id: "B24emzbs6xVZQr", + Versions: []ficsit.ModVersionsModVersionsVersion{ + {Id: "2XcE6RUzGhZW7p", Version: "1.1.7"}, + {Id: "52RMLEigqT5Ksn", Version: "1.1.6"}, + {Id: "F4HY9eP4D5XjWQ", Version: "1.1.5"}, + }, + }}, nil + } + + panic("ModVersions: " + modReference) +} + +func (m MockProvider) SMLVersions(_ context.Context) (*ficsit.SMLVersionsResponse, error) { + return &ficsit.SMLVersionsResponse{ + SmlVersions: ficsit.SMLVersionsSmlVersionsGetSMLVersions{ + Count: 4, + Sml_versions: []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion{ + { + Id: "v2.2.1", + Version: "2.2.1", + Satisfactory_version: 125236, + Targets: []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget{}, + }, + { + Id: "v3.3.2", + Version: "3.3.2", + Satisfactory_version: 194714, + Targets: []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget{ + { + TargetName: ficsit.TargetNameWindows, + Link: "https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v3.3.2/SML.zip", + }, + }, + }, + { + Id: "v3.6.0", + Version: "3.6.0", + Satisfactory_version: 264901, + Targets: []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget{ + { + TargetName: ficsit.TargetNameWindows, + Link: "https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v3.6.0/SML.zip", + }, + { + TargetName: ficsit.TargetNameWindowsserver, + Link: "https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v3.6.0/SML.zip", + }, + { + TargetName: ficsit.TargetNameLinuxserver, + Link: "https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v3.6.0/SML.zip", + }, + }, + }, + { + Id: "v3.6.1", + Version: "3.6.1", + Satisfactory_version: 264901, + Targets: []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget{ + { + TargetName: ficsit.TargetNameWindows, + Link: "https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v3.6.1/SML.zip", + }, + { + TargetName: ficsit.TargetNameWindowsserver, + Link: "https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v3.6.1/SML.zip", + }, + { + TargetName: ficsit.TargetNameLinuxserver, + Link: "https://github.com/satisfactorymodding/SatisfactoryModLoader/releases/download/v3.6.1/SML.zip", + }, + }, + }, + }, + }, + }, nil +} + +var commonTargets = []ficsit.ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget{ + { + TargetName: ficsit.TargetNameWindows, + Link: "/v1/version/7QcfNdo5QAAyoC/Windows/download", + Hash: "62f5c84eca8480b3ffe7d6c90f759e3b463f482530e27d854fd48624fdd3acc9", + }, + { + TargetName: ficsit.TargetNameWindowsserver, + Link: "/v1/version/7QcfNdo5QAAyoC/WindowsServer/download", + Hash: "8a83fcd4abece4192038769cc672fff6764d72c32fb6c7a8c58d66156bb07917", + }, + { + TargetName: ficsit.TargetNameLinuxserver, + Link: "/v1/version/7QcfNdo5QAAyoC/LinuxServer/download", + Hash: "8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85", + }, +} + +func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) { + switch modID { + case "RefinedPower": + return &ficsit.ModVersionsWithDependenciesResponse{ + Mod: ficsit.ModVersionsWithDependenciesMod{ + Id: "DGiLzB3ZErWu2V", + Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{ + { + Id: "Eqgr4VcB8y1z9a", + Version: "3.2.13", + Link: "/v1/version/Eqgr4VcB8y1z9a/download", + Hash: "8cabf9245e3f2a01b95cd3d39d98e407cfeccf355c19f1538fcbf868f81de008", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "ModularUI", + Condition: "^2.1.11", + Optional: false, + }, + { + Mod_id: "RefinedRDLib", + Condition: "^1.1.7", + Optional: false, + }, + { + Mod_id: "SML", + Condition: "^3.6.1", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "BwVKMJNP8doDLg", + Version: "3.2.11", + Link: "/v1/version/BwVKMJNP8doDLg/download", + Hash: "b64aa7b3a4766295323eac47d432e0d857d042c9cfb1afdd16330483b0476c89", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "ModularUI", + Condition: "^2.1.10", + Optional: false, + }, + { + Mod_id: "RefinedRDLib", + Condition: "^1.1.6", + Optional: false, + }, + { + Mod_id: "SML", + Condition: "^3.6.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "4XTjMpqFngbu9r", + Version: "3.2.10", + Link: "/v1/version/4XTjMpqFngbu9r/download", + Hash: "093f92c6d52c853bade386d5bc79cf103b27fb6e9d6f806850929b866ff98222", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "ModularUI", + Condition: "^2.1.9", + Optional: false, + }, + { + Mod_id: "RefinedRDLib", + Condition: "^1.1.5", + Optional: false, + }, + { + Mod_id: "SML", + Condition: "^3.6.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + }, + }, + }, nil + case "AreaActions": + return &ficsit.ModVersionsWithDependenciesResponse{ + Mod: ficsit.ModVersionsWithDependenciesMod{ + Id: "6vQ6ckVYFiidDh", + Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{ + { + Id: "5KMXBkdAz5YJe", + Version: "1.6.7", + Link: "/v1/version/5KMXBkdAz5YJe/download", + Hash: "0baa673eea245b8ec5fe203a70b98deb666d85e27fb6ce9201e3c0fa3aaedcbe", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.4.1", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "EtEbwJj3smMn3o", + Version: "1.6.6", + Link: "/v1/version/EtEbwJj3smMn3o/download", + Hash: "b64aa7b3a4766295323eac47d432e0d857d042c9cfb1afdd16330483b0476c89", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.2.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "9uw1eDwgrQs279", + Version: "1.6.5", + Link: "/v1/version/9uw1eDwgrQs279/download", + Hash: "427a93383fe8a8557096666b7e81bf5fb25f54a5428248904f52adc4dc34d60c", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.0.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + }, + }, + }, nil + case "RefinedRDLib": + return &ficsit.ModVersionsWithDependenciesResponse{ + Mod: ficsit.ModVersionsWithDependenciesMod{ + Id: "B24emzbs6xVZQr", + Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{ + { + Id: "2XcE6RUzGhZW7p", + Version: "1.1.7", + Link: "/v1/version/2XcE6RUzGhZW7p/download", + Hash: "034f3a7862d0153768e1a95d29d47a9d08ebcb7ff0fc8f9f2cb59147b09f16dd", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.6.1", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "52RMLEigqT5Ksn", + Version: "1.1.6", + Link: "/v1/version/52RMLEigqT5Ksn/download", + Hash: "9577e401e1a12a29657c8e3ed0cff34815009504dc62fc1a335b1e7a3b6fed12", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.6.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "F4HY9eP4D5XjWQ", + Version: "1.1.5", + Link: "/v1/version/F4HY9eP4D5XjWQ/download", + Hash: "9cbeae078e28a661ebe15642e6d8f652c6c40c50dabd79a0781e25b84ed9bddf", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.6.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + }, + }, + }, nil + case "ModularUI": + return &ficsit.ModVersionsWithDependenciesResponse{ + Mod: ficsit.ModVersionsWithDependenciesMod{ + Id: "As2uJmQLLxjXLG", + Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{ + { + Id: "7ay11W9MAv6MHs", + Version: "2.1.12", + Link: "/v1/version/7ay11W9MAv6MHs/download", + Hash: "a0de64c02448f9e37903e7569cc6ceee67f8e018f2774aac9cf295704b9e4696", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.6.1", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "4YuL9UbCDdzm68", + Version: "2.1.11", + Link: "/v1/version/4YuL9UbCDdzm68/download", + Hash: "b70658bfa74c132530046bee886c3c0f0277b95339b4fc67da6207cbd2cd422d", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.6.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "5yY2zmx5nTyhWv", + Version: "2.1.10", + Link: "/v1/version/5yY2zmx5nTyhWv/download", + Hash: "7c523c9e6263a0b182ed42fe4d4de40aada10c17b1b344219618cd39055870bd", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.6.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + }, + }, + }, nil + case "ThisModDoesNotExist$$$": + return &ficsit.ModVersionsWithDependenciesResponse{}, nil + case "FicsitRemoteMonitoring": + return &ficsit.ModVersionsWithDependenciesResponse{ + Mod: ficsit.ModVersionsWithDependenciesMod{ + Id: "9LguyCdDUrpT9N", + Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{ + { + Id: "7ay11W9MAv6MHs", + Version: "0.10.1", + Link: "/v1/version/9LguyCdDUrpT9N/download", + Hash: "9278b37653ad33dd859875929b15cd1f8aba88d0ea65879df2db1ae8808029d4", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.6.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "DYvfwan5tYqZKE", + Version: "0.10.0", + Link: "/v1/version/DYvfwan5tYqZKE/download", + Hash: "8666b37b24188c3f56b1dad6f1d437c1127280381172a1046e85142e7cb81c64", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.5.0", + Optional: false, + }, + }, + Targets: commonTargets, + }, + { + Id: "918KMrX94xFpVw", + Version: "0.9.8", + Link: "/v1/version/918KMrX94xFpVw/download", + Hash: "d4fed641b6ecb25b9191f4dd7210576e9bd7bc644abcb3ca592200ccfd08fc44", + Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{ + { + Mod_id: "SML", + Condition: "^3.4.1", + Optional: false, + }, + }, + Targets: commonTargets, + }, + }, + }, + }, nil + } + + panic("ModVersionsWithDependencies: " + modID) +} + +func (m MockProvider) GetModName(_ context.Context, modReference string) (*ficsit.GetModNameResponse, error) { + switch modReference { + case "RefinedPower": + return &ficsit.GetModNameResponse{Mod: ficsit.GetModNameMod{ + Id: "DGiLzB3ZErWu2V", + Mod_reference: "RefinedPower", + Name: "Refined Power", + }}, nil + case "RefinedRDLib": + return &ficsit.GetModNameResponse{Mod: ficsit.GetModNameMod{ + Id: "B24emzbs6xVZQr", + Mod_reference: "RefinedRDLib", + Name: "RefinedRDLib", + }}, nil + } + + panic("GetModName: " + modReference) +} + +func (m MockProvider) IsOffline() bool { + return false +} diff --git a/cli/types.go b/cli/types.go index bee4c11..6440bbf 100644 --- a/cli/types.go +++ b/cli/types.go @@ -3,11 +3,15 @@ package cli type ModVersion struct { ID string Version string - Link string - Hash string + Targets map[string]VersionTarget Dependencies []VersionDependency } +type VersionTarget struct { + Link string + Hash string +} + type VersionDependency struct { ModReference string Constraint string diff --git a/docs/ficsit.md b/docs/ficsit.md index eb94b8c..1f6160c 100644 --- a/docs/ficsit.md +++ b/docs/ficsit.md @@ -8,6 +8,7 @@ cli mod manager for satisfactory --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") -h, --help help for ficsit @@ -15,6 +16,7 @@ cli mod manager for satisfactory --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -30,4 +32,4 @@ cli mod manager for satisfactory * [ficsit smr](ficsit_smr.md) - Manage mods on SMR * [ficsit version](ficsit_version.md) - Print current version information -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_apply.md b/docs/ficsit_apply.md index 96575f6..7285c79 100644 --- a/docs/ficsit_apply.md +++ b/docs/ficsit_apply.md @@ -18,12 +18,14 @@ ficsit apply [installation] ... [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit apply [installation] ... [flags] * [ficsit](ficsit.md) - cli mod manager for satisfactory -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_cli.md b/docs/ficsit_cli.md index a3a279e..2ad9277 100644 --- a/docs/ficsit_cli.md +++ b/docs/ficsit_cli.md @@ -18,12 +18,14 @@ ficsit cli [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit cli [flags] * [ficsit](ficsit.md) - cli mod manager for satisfactory -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_installation.md b/docs/ficsit_installation.md index 65a0281..6aba002 100644 --- a/docs/ficsit_installation.md +++ b/docs/ficsit_installation.md @@ -14,12 +14,14 @@ Manage installations --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -32,5 +34,6 @@ Manage installations * [ficsit installation ls](ficsit_installation_ls.md) - List all installations * [ficsit installation remove](ficsit_installation_remove.md) - Remove an installation * [ficsit installation set-profile](ficsit_installation_set-profile.md) - Change the profile of an installation +* [ficsit installation set-vanilla](ficsit_installation_set-vanilla.md) - Set the installation to vanilla mode or not -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_installation_add.md b/docs/ficsit_installation_add.md index b8f8daf..331114a 100644 --- a/docs/ficsit_installation_add.md +++ b/docs/ficsit_installation_add.md @@ -18,12 +18,14 @@ ficsit installation add [profile] [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit installation add [profile] [flags] * [ficsit installation](ficsit_installation.md) - Manage installations -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_installation_ls.md b/docs/ficsit_installation_ls.md index af46f71..4f65428 100644 --- a/docs/ficsit_installation_ls.md +++ b/docs/ficsit_installation_ls.md @@ -18,12 +18,14 @@ ficsit installation ls [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit installation ls [flags] * [ficsit installation](ficsit_installation.md) - Manage installations -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_installation_remove.md b/docs/ficsit_installation_remove.md index 057a894..fed7e9a 100644 --- a/docs/ficsit_installation_remove.md +++ b/docs/ficsit_installation_remove.md @@ -18,12 +18,14 @@ ficsit installation remove [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit installation remove [flags] * [ficsit installation](ficsit_installation.md) - Manage installations -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_installation_set-profile.md b/docs/ficsit_installation_set-profile.md index 2cea0c7..eda139d 100644 --- a/docs/ficsit_installation_set-profile.md +++ b/docs/ficsit_installation_set-profile.md @@ -18,12 +18,14 @@ ficsit installation set-profile [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit installation set-profile [flags] * [ficsit installation](ficsit_installation.md) - Manage installations -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_installation_set-vanilla.md b/docs/ficsit_installation_set-vanilla.md new file mode 100644 index 0000000..862f730 --- /dev/null +++ b/docs/ficsit_installation_set-vanilla.md @@ -0,0 +1,39 @@ +## ficsit installation set-vanilla + +Set the installation to vanilla mode or not + +``` +ficsit installation set-vanilla [flags] +``` + +### Options + +``` + -h, --help help for set-vanilla + -o, --off Disable vanilla +``` + +### Options inherited from parent commands + +``` + --api-base string URL for API (default "https://api.ficsit.app") + --api-key string API key to use when sending requests + --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) + --dry-run Dry-run. Do not save any changes + --graphql-api string Path for GraphQL API (default "/v2/query") + --installations-file string The installations file (default "installations.json") + --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") + --log string The log level to output (default "info") + --log-file string File to output logs to + --offline Whether to only use local data + --pretty Whether to render pretty terminal output (default true) + --profiles-file string The profiles file (default "profiles.json") + --quiet Do not log anything to console +``` + +### SEE ALSO + +* [ficsit installation](ficsit_installation.md) - Manage installations + +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_profile.md b/docs/ficsit_profile.md index 1a89828..4cd53fa 100644 --- a/docs/ficsit_profile.md +++ b/docs/ficsit_profile.md @@ -14,12 +14,14 @@ Manage profiles --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -34,4 +36,4 @@ Manage profiles * [ficsit profile new](ficsit_profile_new.md) - Create a new profile * [ficsit profile rename](ficsit_profile_rename.md) - Rename a profile -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_profile_delete.md b/docs/ficsit_profile_delete.md index c5d4890..6f3dee6 100644 --- a/docs/ficsit_profile_delete.md +++ b/docs/ficsit_profile_delete.md @@ -18,12 +18,14 @@ ficsit profile delete [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit profile delete [flags] * [ficsit profile](ficsit_profile.md) - Manage profiles -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_profile_ls.md b/docs/ficsit_profile_ls.md index a7ac91f..34026ee 100644 --- a/docs/ficsit_profile_ls.md +++ b/docs/ficsit_profile_ls.md @@ -18,12 +18,14 @@ ficsit profile ls [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit profile ls [flags] * [ficsit profile](ficsit_profile.md) - Manage profiles -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_profile_mods.md b/docs/ficsit_profile_mods.md index ffa33f5..9f992c1 100644 --- a/docs/ficsit_profile_mods.md +++ b/docs/ficsit_profile_mods.md @@ -18,12 +18,14 @@ ficsit profile mods [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit profile mods [flags] * [ficsit profile](ficsit_profile.md) - Manage profiles -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_profile_new.md b/docs/ficsit_profile_new.md index 3ad929e..780343e 100644 --- a/docs/ficsit_profile_new.md +++ b/docs/ficsit_profile_new.md @@ -18,12 +18,14 @@ ficsit profile new [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit profile new [flags] * [ficsit profile](ficsit_profile.md) - Manage profiles -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_profile_rename.md b/docs/ficsit_profile_rename.md index 717fe1f..de4441b 100644 --- a/docs/ficsit_profile_rename.md +++ b/docs/ficsit_profile_rename.md @@ -18,12 +18,14 @@ ficsit profile rename [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit profile rename [flags] * [ficsit profile](ficsit_profile.md) - Manage profiles -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_search.md b/docs/ficsit_search.md index 1f4ab30..3a10dcf 100644 --- a/docs/ficsit_search.md +++ b/docs/ficsit_search.md @@ -23,12 +23,14 @@ ficsit search [query] [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -38,4 +40,4 @@ ficsit search [query] [flags] * [ficsit](ficsit.md) - cli mod manager for satisfactory -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_smr.md b/docs/ficsit_smr.md index 03dd8cd..0591a43 100644 --- a/docs/ficsit_smr.md +++ b/docs/ficsit_smr.md @@ -14,12 +14,14 @@ Manage mods on SMR --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -30,4 +32,4 @@ Manage mods on SMR * [ficsit](ficsit.md) - cli mod manager for satisfactory * [ficsit smr upload](ficsit_smr_upload.md) - Upload a new mod version -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_smr_upload.md b/docs/ficsit_smr_upload.md index 3bcba72..e105949 100644 --- a/docs/ficsit_smr_upload.md +++ b/docs/ficsit_smr_upload.md @@ -20,12 +20,14 @@ ficsit smr upload [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -35,4 +37,4 @@ ficsit smr upload [flags] * [ficsit smr](ficsit_smr.md) - Manage mods on SMR -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/docs/ficsit_version.md b/docs/ficsit_version.md index dc0f80b..73da4d3 100644 --- a/docs/ficsit_version.md +++ b/docs/ficsit_version.md @@ -18,12 +18,14 @@ ficsit version [flags] --api-base string URL for API (default "https://api.ficsit.app") --api-key string API key to use when sending requests --cache-dir string The cache directory (default "/home/vilsol/.cache/ficsit") + --concurrent-downloads int Maximum number of concurrent downloads (default 5) --dry-run Dry-run. Do not save any changes --graphql-api string Path for GraphQL API (default "/v2/query") --installations-file string The installations file (default "installations.json") --local-dir string The local directory (default "/home/vilsol/.local/share/ficsit") --log string The log level to output (default "info") --log-file string File to output logs to + --offline Whether to only use local data --pretty Whether to render pretty terminal output (default true) --profiles-file string The profiles file (default "profiles.json") --quiet Do not log anything to console @@ -33,4 +35,4 @@ ficsit version [flags] * [ficsit](ficsit.md) - cli mod manager for satisfactory -###### Auto generated by spf13/cobra on 14-Oct-2022 +###### Auto generated by spf13/cobra on 7-Dec-2023 diff --git a/ficsit/queries/mod_versions_with_dependencies.graphql b/ficsit/queries/mod_versions_with_dependencies.graphql index 3695a6f..34ef967 100644 --- a/ficsit/queries/mod_versions_with_dependencies.graphql +++ b/ficsit/queries/mod_versions_with_dependencies.graphql @@ -14,6 +14,11 @@ query ModVersionsWithDependencies ( condition optional } + targets { + targetName + link + hash + } } } } \ No newline at end of file diff --git a/ficsit/queries/resolve_mod_dependencies.graphql b/ficsit/queries/resolve_mod_dependencies.graphql deleted file mode 100644 index e124a12..0000000 --- a/ficsit/queries/resolve_mod_dependencies.graphql +++ /dev/null @@ -1,17 +0,0 @@ -query ResolveModDependencies ($filter: [ModVersionConstraint!]!) { - mods: resolveModVersions(filter: $filter) { - id - mod_reference - versions { - id - version - link - hash - dependencies { - condition - mod_id - optional - } - } - } -} \ No newline at end of file diff --git a/ficsit/queries/sml_versions.graphql b/ficsit/queries/sml_versions.graphql index 13264a5..d102708 100644 --- a/ficsit/queries/sml_versions.graphql +++ b/ficsit/queries/sml_versions.graphql @@ -6,6 +6,10 @@ query SMLVersions { id version satisfactory_version + targets { + targetName + link + } } } } \ No newline at end of file diff --git a/ficsit/types.go b/ficsit/types.go index aba37a4..f316cef 100644 --- a/ficsit/types.go +++ b/ficsit/types.go @@ -245,66 +245,55 @@ type ModFields string const ( ModFieldsCreatedAt ModFields = "created_at" - ModFieldsUpdatedAt ModFields = "updated_at" - ModFieldsName ModFields = "name" - ModFieldsViews ModFields = "views" ModFieldsDownloads ModFields = "downloads" ModFieldsHotness ModFields = "hotness" - ModFieldsPopularity ModFields = "popularity" ModFieldsLastVersionDate ModFields = "last_version_date" + ModFieldsName ModFields = "name" + ModFieldsPopularity ModFields = "popularity" ModFieldsSearch ModFields = "search" + ModFieldsUpdatedAt ModFields = "updated_at" + ModFieldsViews ModFields = "views" ) type ModFilter struct { + Hidden bool `json:"hidden,omitempty"` + Ids []string `json:"ids,omitempty"` Limit int `json:"limit,omitempty"` Offset int `json:"offset,omitempty"` - Order_by ModFields `json:"order_by,omitempty"` Order Order `json:"order,omitempty"` - Search string `json:"search,omitempty"` - Ids []string `json:"ids,omitempty"` + Order_by ModFields `json:"order_by,omitempty"` References []string `json:"references,omitempty"` - Hidden bool `json:"hidden,omitempty"` + Search string `json:"search,omitempty"` TagIDs []string `json:"tagIDs,omitempty"` } +// GetHidden returns ModFilter.Hidden, and is useful for accessing the field via an interface. +func (v *ModFilter) GetHidden() bool { return v.Hidden } + +// GetIds returns ModFilter.Ids, and is useful for accessing the field via an interface. +func (v *ModFilter) GetIds() []string { return v.Ids } + // GetLimit returns ModFilter.Limit, and is useful for accessing the field via an interface. func (v *ModFilter) GetLimit() int { return v.Limit } // GetOffset returns ModFilter.Offset, and is useful for accessing the field via an interface. func (v *ModFilter) GetOffset() int { return v.Offset } -// GetOrder_by returns ModFilter.Order_by, and is useful for accessing the field via an interface. -func (v *ModFilter) GetOrder_by() ModFields { return v.Order_by } - // GetOrder returns ModFilter.Order, and is useful for accessing the field via an interface. func (v *ModFilter) GetOrder() Order { return v.Order } -// GetSearch returns ModFilter.Search, and is useful for accessing the field via an interface. -func (v *ModFilter) GetSearch() string { return v.Search } - -// GetIds returns ModFilter.Ids, and is useful for accessing the field via an interface. -func (v *ModFilter) GetIds() []string { return v.Ids } +// GetOrder_by returns ModFilter.Order_by, and is useful for accessing the field via an interface. +func (v *ModFilter) GetOrder_by() ModFields { return v.Order_by } // GetReferences returns ModFilter.References, and is useful for accessing the field via an interface. func (v *ModFilter) GetReferences() []string { return v.References } -// GetHidden returns ModFilter.Hidden, and is useful for accessing the field via an interface. -func (v *ModFilter) GetHidden() bool { return v.Hidden } +// GetSearch returns ModFilter.Search, and is useful for accessing the field via an interface. +func (v *ModFilter) GetSearch() string { return v.Search } // GetTagIDs returns ModFilter.TagIDs, and is useful for accessing the field via an interface. func (v *ModFilter) GetTagIDs() []string { return v.TagIDs } -type ModVersionConstraint struct { - ModIdOrReference string `json:"modIdOrReference"` - Version string `json:"version"` -} - -// GetModIdOrReference returns ModVersionConstraint.ModIdOrReference, and is useful for accessing the field via an interface. -func (v *ModVersionConstraint) GetModIdOrReference() string { return v.ModIdOrReference } - -// GetVersion returns ModVersionConstraint.Version, and is useful for accessing the field via an interface. -func (v *ModVersionConstraint) GetVersion() string { return v.Version } - // ModVersionsMod includes the requested fields of the GraphQL type Mod. type ModVersionsMod struct { Id string `json:"id"` @@ -358,6 +347,7 @@ type ModVersionsWithDependenciesModVersionsVersion struct { Link string `json:"link"` Hash string `json:"hash"` Dependencies []ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency `json:"dependencies"` + Targets []ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget `json:"targets"` } // GetId returns ModVersionsWithDependenciesModVersionsVersion.Id, and is useful for accessing the field via an interface. @@ -377,6 +367,11 @@ func (v *ModVersionsWithDependenciesModVersionsVersion) GetDependencies() []ModV return v.Dependencies } +// GetTargets returns ModVersionsWithDependenciesModVersionsVersion.Targets, and is useful for accessing the field via an interface. +func (v *ModVersionsWithDependenciesModVersionsVersion) GetTargets() []ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget { + return v.Targets +} + // ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency includes the requested fields of the GraphQL type VersionDependency. type ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency struct { Mod_id string `json:"mod_id"` @@ -399,6 +394,28 @@ func (v *ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDepende return v.Optional } +// ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget includes the requested fields of the GraphQL type VersionTarget. +type ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget struct { + TargetName TargetName `json:"targetName"` + Link string `json:"link"` + Hash string `json:"hash"` +} + +// GetTargetName returns ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget.TargetName, and is useful for accessing the field via an interface. +func (v *ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget) GetTargetName() TargetName { + return v.TargetName +} + +// GetLink returns ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget.Link, and is useful for accessing the field via an interface. +func (v *ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget) GetLink() string { + return v.Link +} + +// GetHash returns ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget.Hash, and is useful for accessing the field via an interface. +func (v *ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget) GetHash() string { + return v.Hash +} + // ModVersionsWithDependenciesResponse is returned by ModVersionsWithDependencies on success. type ModVersionsWithDependenciesResponse struct { Mod ModVersionsWithDependenciesMod `json:"mod"` @@ -597,82 +614,6 @@ const ( OrderDesc Order = "desc" ) -// ResolveModDependenciesModsModVersion includes the requested fields of the GraphQL type ModVersion. -type ResolveModDependenciesModsModVersion struct { - Id string `json:"id"` - Mod_reference string `json:"mod_reference"` - Versions []ResolveModDependenciesModsModVersionVersionsVersion `json:"versions"` -} - -// GetId returns ResolveModDependenciesModsModVersion.Id, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersion) GetId() string { return v.Id } - -// GetMod_reference returns ResolveModDependenciesModsModVersion.Mod_reference, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersion) GetMod_reference() string { return v.Mod_reference } - -// GetVersions returns ResolveModDependenciesModsModVersion.Versions, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersion) GetVersions() []ResolveModDependenciesModsModVersionVersionsVersion { - return v.Versions -} - -// ResolveModDependenciesModsModVersionVersionsVersion includes the requested fields of the GraphQL type Version. -type ResolveModDependenciesModsModVersionVersionsVersion struct { - Id string `json:"id"` - Version string `json:"version"` - Link string `json:"link"` - Hash string `json:"hash"` - Dependencies []ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency `json:"dependencies"` -} - -// GetId returns ResolveModDependenciesModsModVersionVersionsVersion.Id, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersion) GetId() string { return v.Id } - -// GetVersion returns ResolveModDependenciesModsModVersionVersionsVersion.Version, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersion) GetVersion() string { return v.Version } - -// GetLink returns ResolveModDependenciesModsModVersionVersionsVersion.Link, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersion) GetLink() string { return v.Link } - -// GetHash returns ResolveModDependenciesModsModVersionVersionsVersion.Hash, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersion) GetHash() string { return v.Hash } - -// GetDependencies returns ResolveModDependenciesModsModVersionVersionsVersion.Dependencies, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersion) GetDependencies() []ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency { - return v.Dependencies -} - -// ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency includes the requested fields of the GraphQL type VersionDependency. -type ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency struct { - Condition string `json:"condition"` - Mod_id string `json:"mod_id"` - Optional bool `json:"optional"` -} - -// GetCondition returns ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency.Condition, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency) GetCondition() string { - return v.Condition -} - -// GetMod_id returns ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency.Mod_id, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency) GetMod_id() string { - return v.Mod_id -} - -// GetOptional returns ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency.Optional, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesModsModVersionVersionsVersionDependenciesVersionDependency) GetOptional() bool { - return v.Optional -} - -// ResolveModDependenciesResponse is returned by ResolveModDependencies on success. -type ResolveModDependenciesResponse struct { - Mods []ResolveModDependenciesModsModVersion `json:"mods"` -} - -// GetMods returns ResolveModDependenciesResponse.Mods, and is useful for accessing the field via an interface. -func (v *ResolveModDependenciesResponse) GetMods() []ResolveModDependenciesModsModVersion { - return v.Mods -} - // SMLVersionsResponse is returned by SMLVersions on success. type SMLVersionsResponse struct { SmlVersions SMLVersionsSmlVersionsGetSMLVersions `json:"smlVersions"` @@ -699,9 +640,10 @@ func (v *SMLVersionsSmlVersionsGetSMLVersions) GetSml_versions() []SMLVersionsSm // SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion includes the requested fields of the GraphQL type SMLVersion. type SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion struct { - Id string `json:"id"` - Version string `json:"version"` - Satisfactory_version int `json:"satisfactory_version"` + Id string `json:"id"` + Version string `json:"version"` + Satisfactory_version int `json:"satisfactory_version"` + Targets []SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget `json:"targets"` } // GetId returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion.Id, and is useful for accessing the field via an interface. @@ -717,41 +659,70 @@ func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion) GetSatisfac return v.Satisfactory_version } +// GetTargets returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion.Targets, and is useful for accessing the field via an interface. +func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion) GetTargets() []SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget { + return v.Targets +} + +// SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget includes the requested fields of the GraphQL type SMLVersionTarget. +type SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget struct { + TargetName TargetName `json:"targetName"` + Link string `json:"link"` +} + +// GetTargetName returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget.TargetName, and is useful for accessing the field via an interface. +func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget) GetTargetName() TargetName { + return v.TargetName +} + +// GetLink returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget.Link, and is useful for accessing the field via an interface. +func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget) GetLink() string { + return v.Link +} + +type TargetName string + +const ( + TargetNameLinuxserver TargetName = "LinuxServer" + TargetNameWindows TargetName = "Windows" + TargetNameWindowsserver TargetName = "WindowsServer" +) + type VersionFields string const ( VersionFieldsCreatedAt VersionFields = "created_at" - VersionFieldsUpdatedAt VersionFields = "updated_at" VersionFieldsDownloads VersionFields = "downloads" + VersionFieldsUpdatedAt VersionFields = "updated_at" ) type VersionFilter struct { + Ids []string `json:"ids,omitempty"` Limit int `json:"limit,omitempty"` Offset int `json:"offset,omitempty"` - Order_by VersionFields `json:"order_by,omitempty"` Order Order `json:"order,omitempty"` + Order_by VersionFields `json:"order_by,omitempty"` Search string `json:"search,omitempty"` - Ids []string `json:"ids,omitempty"` } +// GetIds returns VersionFilter.Ids, and is useful for accessing the field via an interface. +func (v *VersionFilter) GetIds() []string { return v.Ids } + // GetLimit returns VersionFilter.Limit, and is useful for accessing the field via an interface. func (v *VersionFilter) GetLimit() int { return v.Limit } // GetOffset returns VersionFilter.Offset, and is useful for accessing the field via an interface. func (v *VersionFilter) GetOffset() int { return v.Offset } -// GetOrder_by returns VersionFilter.Order_by, and is useful for accessing the field via an interface. -func (v *VersionFilter) GetOrder_by() VersionFields { return v.Order_by } - // GetOrder returns VersionFilter.Order, and is useful for accessing the field via an interface. func (v *VersionFilter) GetOrder() Order { return v.Order } +// GetOrder_by returns VersionFilter.Order_by, and is useful for accessing the field via an interface. +func (v *VersionFilter) GetOrder_by() VersionFields { return v.Order_by } + // GetSearch returns VersionFilter.Search, and is useful for accessing the field via an interface. func (v *VersionFilter) GetSearch() string { return v.Search } -// GetIds returns VersionFilter.Ids, and is useful for accessing the field via an interface. -func (v *VersionFilter) GetIds() []string { return v.Ids } - // VersionMod includes the requested fields of the GraphQL type Mod. type VersionMod struct { Id string `json:"id"` @@ -880,14 +851,6 @@ type __ModsInput struct { // GetFilter returns __ModsInput.Filter, and is useful for accessing the field via an interface. func (v *__ModsInput) GetFilter() ModFilter { return v.Filter } -// __ResolveModDependenciesInput is used internally by genqlient -type __ResolveModDependenciesInput struct { - Filter []ModVersionConstraint `json:"filter"` -} - -// GetFilter returns __ResolveModDependenciesInput.Filter, and is useful for accessing the field via an interface. -func (v *__ResolveModDependenciesInput) GetFilter() []ModVersionConstraint { return v.Filter } - // __VersionInput is used internally by genqlient type __VersionInput struct { ModId string `json:"modId,omitempty"` @@ -1139,6 +1102,11 @@ query ModVersionsWithDependencies ($modId: String!) { condition optional } + targets { + targetName + link + hash + } } } } @@ -1204,50 +1172,6 @@ query Mods ($filter: ModFilter) { return &data, err } -func ResolveModDependencies( - ctx context.Context, - client graphql.Client, - filter []ModVersionConstraint, -) (*ResolveModDependenciesResponse, error) { - req := &graphql.Request{ - OpName: "ResolveModDependencies", - Query: ` -query ResolveModDependencies ($filter: [ModVersionConstraint!]!) { - mods: resolveModVersions(filter: $filter) { - id - mod_reference - versions { - id - version - link - hash - dependencies { - condition - mod_id - optional - } - } - } -} -`, - Variables: &__ResolveModDependenciesInput{ - Filter: filter, - }, - } - var err error - - var data ResolveModDependenciesResponse - resp := &graphql.Response{Data: &data} - - err = client.MakeRequest( - ctx, - req, - resp, - ) - - return &data, err -} - func SMLVersions( ctx context.Context, client graphql.Client, @@ -1262,6 +1186,10 @@ query SMLVersions { id version satisfactory_version + targets { + targetName + link + } } } } diff --git a/tea/components/header.go b/tea/components/header.go index 3c65d4f..bc920ec 100644 --- a/tea/components/header.go +++ b/tea/components/header.go @@ -57,7 +57,7 @@ func (h headerComponent) View() string { out += "N/A" } - if h.root.GetProvider().Offline { + if h.root.GetProvider().IsOffline() { out += "\n" out += h.labelStyle.Render("Offline") } diff --git a/tea/components/types.go b/tea/components/types.go index f0e120f..ba1cb6a 100644 --- a/tea/components/types.go +++ b/tea/components/types.go @@ -18,7 +18,7 @@ type RootModel interface { SetCurrentInstallation(installation *cli.Installation) error GetAPIClient() graphql.Client - GetProvider() *provider.MixedProvider + GetProvider() provider.Provider Size() tea.WindowSizeMsg SetSize(size tea.WindowSizeMsg) diff --git a/tea/root.go b/tea/root.go index 4a98079..87adcbf 100644 --- a/tea/root.go +++ b/tea/root.go @@ -64,7 +64,7 @@ func (m *rootModel) GetAPIClient() graphql.Client { return m.global.APIClient } -func (m *rootModel) GetProvider() *provider.MixedProvider { +func (m *rootModel) GetProvider() provider.Provider { return m.global.Provider } diff --git a/tea/scenes/mods/update_mods.go b/tea/scenes/mods/update_mods.go index d691a0b..b0de81e 100644 --- a/tea/scenes/mods/update_mods.go +++ b/tea/scenes/mods/update_mods.go @@ -120,9 +120,9 @@ func (m updateModsList) LoadModData() { items := make([]list.Item, 0) i := 0 - for reference, currentLockedMod := range *currentLockfile { + for reference, currentLockedMod := range currentLockfile.Mods { r := reference - updatedLockedMod, ok := updatedLockfile[reference] + updatedLockedMod, ok := updatedLockfile.Mods[reference] if !ok { continue } diff --git a/utils/io.go b/utils/io.go index 39c8eff..b93b5b9 100644 --- a/utils/io.go +++ b/utils/io.go @@ -148,10 +148,7 @@ func ExtractMod(f io.ReaderAt, size int64, location string, hash string, updates } if updates != nil { - select { - case updates <- GenericProgress{Completed: totalSize, Total: totalSize}: - default: - } + updates <- GenericProgress{Completed: totalSize, Total: totalSize} } return nil diff --git a/utils/version.go b/utils/version.go index c209acd..f062df2 100644 --- a/utils/version.go +++ b/utils/version.go @@ -2,4 +2,4 @@ package utils import "regexp" -var SemVerRegex = regexp.MustCompile(`^(<=|<|>|>=|\^)?(0|[1-9]\d*)\.(0|[1-9]d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) +var SemVerRegex = regexp.MustCompile(`^(<=|<|>|>=|\^)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`)