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 <mircearoatapalade@gmail.com>
This commit is contained in:
Vilsol 2023-12-07 18:57:31 +02:00 committed by GitHub
parent 6088d1e8eb
commit 5f2e60a9e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 824 additions and 397 deletions

View file

@ -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 ./...

View file

@ -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:

View file

@ -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)
}

19
cli/cache/cache.go vendored
View file

@ -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
}

View file

@ -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)

View file

@ -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

View file

@ -14,7 +14,7 @@ type GlobalContext struct {
Installations *Installations
Profiles *Profiles
APIClient graphql.Client
Provider *provider.MixedProvider
Provider provider.Provider
}
var globalContext *GlobalContext

View file

@ -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
}

View file

@ -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)

View file

@ -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 != "" {

View file

@ -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
}

View file

@ -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",
},
}

View file

@ -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 {

View file

@ -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)
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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
}

View file

@ -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)

444
cli/test_helpers.go Normal file
View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -18,12 +18,14 @@ ficsit installation add <path> [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 <path> [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

View file

@ -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

View file

@ -18,12 +18,14 @@ ficsit installation remove <path> [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 <path> [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

View file

@ -18,12 +18,14 @@ ficsit installation set-profile <path> <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 <path> <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

View file

@ -0,0 +1,39 @@
## ficsit installation set-vanilla
Set the installation to vanilla mode or not
```
ficsit installation set-vanilla <path> [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

View file

@ -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

View file

@ -18,12 +18,14 @@ ficsit profile delete <name> [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 <name> [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

View file

@ -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

View file

@ -18,12 +18,14 @@ ficsit profile mods <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 profile mods <profile> [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

View file

@ -18,12 +18,14 @@ ficsit profile new <name> [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 <name> [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

View file

@ -18,12 +18,14 @@ ficsit profile rename <old> <name> [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 <old> <name> [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

View file

@ -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

View file

@ -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

View file

@ -20,12 +20,14 @@ ficsit smr upload [flags] <mod-id> <file> <changelog...>
--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] <mod-id> <file> <changelog...>
* [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

View file

@ -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

View file

@ -14,6 +14,11 @@ query ModVersionsWithDependencies (
condition
optional
}
targets {
targetName
link
hash
}
}
}
}

View file

@ -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
}
}
}
}

View file

@ -6,6 +6,10 @@ query SMLVersions {
id
version
satisfactory_version
targets {
targetName
link
}
}
}
}

View file

@ -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
}
}
}
}

View file

@ -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")
}

View file

@ -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)

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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-]+)*))?$`)