feat: parallel apply view (#47)
* feat: parallel apply view * chore: cleaner readme * chore: lint * chore: remove debug logging * chore: lint
This commit is contained in:
parent
98b7c99e74
commit
b6592fe185
23 changed files with 575 additions and 369 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
BIN
.github/screenshot.png
vendored
Normal file
BIN
.github/screenshot.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
8
.github/workflows/push.yaml
vendored
8
.github/workflows/push.yaml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.21
|
go-version: 1.21.4
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
@ -33,7 +33,7 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.21
|
go-version: 1.21.4
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
@ -47,7 +47,7 @@ jobs:
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
with:
|
with:
|
||||||
version: v1.54
|
version: v1.55.2
|
||||||
skip-pkg-cache: true
|
skip-pkg-cache: true
|
||||||
skip-build-cache: true
|
skip-build-cache: true
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.21
|
go-version: 1.21.4
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -127,4 +127,5 @@ dist/
|
||||||
/testdata
|
/testdata
|
||||||
/.graphqlconfig
|
/.graphqlconfig
|
||||||
schema.graphql
|
schema.graphql
|
||||||
*.log
|
*.log
|
||||||
|
.direnv
|
|
@ -50,7 +50,6 @@ linters:
|
||||||
- contextcheck
|
- contextcheck
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- errorlint
|
- errorlint
|
||||||
- goconst
|
|
||||||
- goimports
|
- goimports
|
||||||
- revive
|
- revive
|
||||||
- misspell
|
- misspell
|
||||||
|
|
13
README.md
13
README.md
|
@ -1,7 +1,11 @@
|
||||||
|
<img align="right" width="310" src="./.github/screenshot.png" />
|
||||||
|
|
||||||
# ficsit-cli [![push](https://github.com/Vilsol/ficsit-cli/actions/workflows/push.yaml/badge.svg)](https://github.com/Vilsol/ficsit-cli/actions/workflows/push.yaml) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/vilsol/ficsit-cli) ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/vilsol/ficsit-cli) [![GitHub license](https://img.shields.io/github/license/Vilsol/ficsit-cli)](https://github.com/Vilsol/ficsit-cli/blob/master/LICENSE) ![GitHub all releases](https://img.shields.io/github/downloads/vilsol/ficsit-cli/total)
|
# ficsit-cli [![push](https://github.com/Vilsol/ficsit-cli/actions/workflows/push.yaml/badge.svg)](https://github.com/Vilsol/ficsit-cli/actions/workflows/push.yaml) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/vilsol/ficsit-cli) ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/vilsol/ficsit-cli) [![GitHub license](https://img.shields.io/github/license/Vilsol/ficsit-cli)](https://github.com/Vilsol/ficsit-cli/blob/master/LICENSE) ![GitHub all releases](https://img.shields.io/github/downloads/vilsol/ficsit-cli/total)
|
||||||
|
|
||||||
A CLI tool for managing mods for the game Satisfactory
|
A CLI tool for managing mods for the game Satisfactory
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
@ -49,6 +53,14 @@ A CLI tool for managing mods for the game Satisfactory
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_armv7.apk">armv7</a></td>
|
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_armv7.apk">armv7</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le.apk">ppc64le</a></td>
|
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le.apk">ppc64le</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Linux</th>
|
||||||
|
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_amd64">amd64</a></td>
|
||||||
|
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_386">386</a></td>
|
||||||
|
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_arm64">arm64</a></td>
|
||||||
|
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_armv7">armv7</a></td>
|
||||||
|
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le">ppc64le</a></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>macOS</th>
|
<th>macOS</th>
|
||||||
<td colspan="4" style="text-align: center"><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_darwin_all">darwin_all</a></td>
|
<td colspan="4" style="text-align: center"><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_darwin_all">darwin_all</a></td>
|
||||||
|
@ -56,7 +68,6 @@ A CLI tool for managing mods for the game Satisfactory
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Interactive CLI
|
### Interactive CLI
|
||||||
|
|
4
cli/cache/download.go
vendored
4
cli/cache/download.go
vendored
|
@ -14,10 +14,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func DownloadOrCache(cacheKey string, hash string, url string, updates chan<- utils.GenericProgress, downloadSemaphore chan int) (*os.File, 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
||||||
if err := os.MkdirAll(downloadCache, 0o777); err != nil {
|
if err := os.MkdirAll(downloadCache, 0o777); err != nil {
|
||||||
if !os.IsExist(err) {
|
if !os.IsExist(err) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ type ficsitAPISource struct {
|
||||||
provider provider.Provider
|
provider provider.Provider
|
||||||
lockfile *LockFile
|
lockfile *LockFile
|
||||||
toInstall map[string]semver.Constraint
|
toInstall map[string]semver.Constraint
|
||||||
modVersionInfo *xsync.MapOf[string, ficsit.ModVersionsWithDependenciesResponse]
|
modVersionInfo *xsync.MapOf[string, ficsit.AllVersionsResponse]
|
||||||
gameVersion semver.Version
|
gameVersion semver.Version
|
||||||
smlVersions []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion
|
smlVersions []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,15 @@ func (f *ficsitAPISource) GetPackageVersions(pkg string) ([]pubgrub.PackageVersi
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to fetch mod %s", pkg)
|
return nil, errors.Wrapf(err, "failed to fetch mod %s", pkg)
|
||||||
}
|
}
|
||||||
if response.Mod.Id == "" {
|
if !response.Success {
|
||||||
|
if response.Error != nil {
|
||||||
|
return nil, errors.Errorf("mod %s not found: %s", pkg, response.Error.Message)
|
||||||
|
}
|
||||||
return nil, errors.Errorf("mod %s not found", pkg)
|
return nil, errors.Errorf("mod %s not found", pkg)
|
||||||
}
|
}
|
||||||
f.modVersionInfo.Store(pkg, *response)
|
f.modVersionInfo.Store(pkg, *response)
|
||||||
versions := make([]pubgrub.PackageVersion, len(response.Mod.Versions))
|
versions := make([]pubgrub.PackageVersion, len(response.Data))
|
||||||
for i, modVersion := range response.Mod.Versions {
|
for i, modVersion := range response.Data {
|
||||||
v, err := semver.NewVersion(modVersion.Version)
|
v, err := semver.NewVersion(modVersion.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to parse version %s", modVersion.Version)
|
return nil, errors.Wrapf(err, "failed to parse version %s", modVersion.Version)
|
||||||
|
@ -88,9 +91,9 @@ func (f *ficsitAPISource) GetPackageVersions(pkg string) ([]pubgrub.PackageVersi
|
||||||
return nil, errors.Wrapf(err, "failed to parse constraint %s", dependency.Condition)
|
return nil, errors.Wrapf(err, "failed to parse constraint %s", dependency.Condition)
|
||||||
}
|
}
|
||||||
if dependency.Optional {
|
if dependency.Optional {
|
||||||
optionalDependencies[dependency.Mod_id] = c
|
optionalDependencies[dependency.ModID] = c
|
||||||
} else {
|
} else {
|
||||||
dependencies[dependency.Mod_id] = c
|
dependencies[dependency.ModID] = c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
versions[i] = pubgrub.PackageVersion{
|
versions[i] = pubgrub.PackageVersion{
|
||||||
|
@ -144,7 +147,7 @@ func (d DependencyResolver) ResolveModDependencies(constraints map[string]string
|
||||||
gameVersion: gameVersionSemver,
|
gameVersion: gameVersionSemver,
|
||||||
lockfile: lockFile,
|
lockfile: lockFile,
|
||||||
toInstall: toInstall,
|
toInstall: toInstall,
|
||||||
modVersionInfo: xsync.NewMapOf[string, ficsit.ModVersionsWithDependenciesResponse](),
|
modVersionInfo: xsync.NewMapOf[string, ficsit.AllVersionsResponse](),
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := pubgrub.Solve(helpers.NewCachingSource(ficsitSource), rootPkg)
|
result, err := pubgrub.Solve(helpers.NewCachingSource(ficsitSource), rootPkg)
|
||||||
|
@ -182,13 +185,13 @@ func (d DependencyResolver) ResolveModDependencies(constraints map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
value, _ := ficsitSource.modVersionInfo.Load(k)
|
value, _ := ficsitSource.modVersionInfo.Load(k)
|
||||||
versions := value.Mod.Versions
|
versions := value.Data
|
||||||
for _, ver := range versions {
|
for _, ver := range versions {
|
||||||
if ver.Version == v.RawString() {
|
if ver.Version == v.RawString() {
|
||||||
targets := make(map[string]LockedModTarget)
|
targets := make(map[string]LockedModTarget)
|
||||||
for _, target := range ver.Targets {
|
for _, target := range ver.Targets {
|
||||||
targets[string(target.TargetName)] = LockedModTarget{
|
targets[target.TargetName] = LockedModTarget{
|
||||||
Link: viper.GetString("api-base") + target.Link,
|
Link: viper.GetString("api-base") + "/v1/version/" + ver.ID + "/" + target.TargetName + "/download",
|
||||||
Hash: target.Hash,
|
Hash: target.Hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -588,6 +588,9 @@ func downloadAndExtractMod(modReference string, version string, link string, has
|
||||||
}
|
}
|
||||||
|
|
||||||
if updates != nil {
|
if updates != nil {
|
||||||
|
close(downloadUpdates)
|
||||||
|
close(extractUpdates)
|
||||||
|
|
||||||
updates <- InstallUpdate{
|
updates <- InstallUpdate{
|
||||||
Type: InstallUpdateTypeModComplete,
|
Type: InstallUpdateTypeModComplete,
|
||||||
Item: InstallUpdateItem{
|
Item: InstallUpdateItem{
|
||||||
|
@ -595,8 +598,6 @@ func downloadAndExtractMod(modReference string, version string, link string, has
|
||||||
Version: version,
|
Version: version,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
close(extractUpdates)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
|
@ -34,8 +34,8 @@ func (p ficsitProvider) SMLVersions(context context.Context) (*ficsit.SMLVersion
|
||||||
return ficsit.SMLVersions(context, p.client)
|
return ficsit.SMLVersions(context, p.client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p ficsitProvider) ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) {
|
func (p ficsitProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.AllVersionsResponse, error) {
|
||||||
return ficsit.ModVersionsWithDependencies(context, p.client, modID)
|
return ficsit.GetAllModVersions(modID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p ficsitProvider) GetModName(context context.Context, modReference string) (*ficsit.GetModNameResponse, error) {
|
func (p ficsitProvider) GetModName(context context.Context, modReference string) (*ficsit.GetModNameResponse, error) {
|
||||||
|
|
|
@ -176,26 +176,24 @@ func (p localProvider) SMLVersions(_ context.Context) (*ficsit.SMLVersionsRespon
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p localProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) {
|
func (p localProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.AllVersionsResponse, error) {
|
||||||
cachedModFiles, err := cache.GetCacheMod(modID)
|
cachedModFiles, err := cache.GetCacheMod(modID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to get cache")
|
return nil, errors.Wrap(err, "failed to get cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
versions := make([]ficsit.ModVersionsWithDependenciesModVersionsVersion, 0)
|
versions := make([]ficsit.ModVersion, 0)
|
||||||
|
|
||||||
for _, modFile := range cachedModFiles {
|
for _, modFile := range cachedModFiles {
|
||||||
versions = append(versions, ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
versions = append(versions, ficsit.ModVersion{
|
||||||
Id: modID + ":" + modFile.Plugin.SemVersion,
|
ID: modID + ":" + modFile.Plugin.SemVersion,
|
||||||
Version: modFile.Plugin.SemVersion,
|
Version: modFile.Plugin.SemVersion,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
return &ficsit.AllVersionsResponse{
|
||||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
Success: true,
|
||||||
Id: modID,
|
Data: versions,
|
||||||
Versions: versions,
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ func (p MixedProvider) SMLVersions(context context.Context) (*ficsit.SMLVersions
|
||||||
return p.ficsitProvider.SMLVersions(context)
|
return p.ficsitProvider.SMLVersions(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p MixedProvider) ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) {
|
func (p MixedProvider) ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.AllVersionsResponse, error) {
|
||||||
if p.Offline {
|
if p.Offline {
|
||||||
return p.localProvider.ModVersionsWithDependencies(context, modID)
|
return p.localProvider.ModVersionsWithDependencies(context, modID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ type Provider interface {
|
||||||
GetMod(context context.Context, modReference string) (*ficsit.GetModResponse, error)
|
GetMod(context context.Context, modReference string) (*ficsit.GetModResponse, error)
|
||||||
ModVersions(context context.Context, modReference string, filter ficsit.VersionFilter) (*ficsit.ModVersionsResponse, error)
|
ModVersions(context context.Context, modReference string, filter ficsit.VersionFilter) (*ficsit.ModVersionsResponse, error)
|
||||||
SMLVersions(context context.Context) (*ficsit.SMLVersionsResponse, error)
|
SMLVersions(context context.Context) (*ficsit.SMLVersionsResponse, error)
|
||||||
ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error)
|
ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.AllVersionsResponse, error)
|
||||||
GetModName(context context.Context, modReference string) (*ficsit.GetModNameResponse, error)
|
GetModName(context context.Context, modReference string) (*ficsit.GetModNameResponse, error)
|
||||||
IsOffline() bool
|
IsOffline() bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ func TestResolutionNonExistentMod(t *testing.T) {
|
||||||
},
|
},
|
||||||
}).Resolve(resolver, nil, math.MaxInt)
|
}).Resolve(resolver, nil, math.MaxInt)
|
||||||
|
|
||||||
testza.AssertEqual(t, "failed resolving profile dependencies: failed to solve dependencies: failed to make decision: failed to get package versions: mod ThisModDoesNotExist$$$ not found", err.Error())
|
testza.AssertEqual(t, "failed resolving profile dependencies: failed to solve dependencies: failed to make decision: failed to get package versions: mod ThisModDoesNotExist$$$ not found: mod not found", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateMods(t *testing.T) {
|
func TestUpdateMods(t *testing.T) {
|
||||||
|
|
|
@ -163,305 +163,268 @@ func (m MockProvider) SMLVersions(_ context.Context) (*ficsit.SMLVersionsRespons
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var commonTargets = []ficsit.ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget{
|
var commonTargets = []ficsit.Target{
|
||||||
{
|
{
|
||||||
TargetName: ficsit.TargetNameWindows,
|
TargetName: "Windows",
|
||||||
Link: "/v1/version/7QcfNdo5QAAyoC/Windows/download",
|
|
||||||
Hash: "62f5c84eca8480b3ffe7d6c90f759e3b463f482530e27d854fd48624fdd3acc9",
|
Hash: "62f5c84eca8480b3ffe7d6c90f759e3b463f482530e27d854fd48624fdd3acc9",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TargetName: ficsit.TargetNameWindowsserver,
|
TargetName: "WindowsServer",
|
||||||
Link: "/v1/version/7QcfNdo5QAAyoC/WindowsServer/download",
|
|
||||||
Hash: "8a83fcd4abece4192038769cc672fff6764d72c32fb6c7a8c58d66156bb07917",
|
Hash: "8a83fcd4abece4192038769cc672fff6764d72c32fb6c7a8c58d66156bb07917",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TargetName: ficsit.TargetNameLinuxserver,
|
TargetName: "LinuxServer",
|
||||||
Link: "/v1/version/7QcfNdo5QAAyoC/LinuxServer/download",
|
|
||||||
Hash: "8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85",
|
Hash: "8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) {
|
func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.AllVersionsResponse, error) {
|
||||||
switch modID {
|
switch modID {
|
||||||
case "RefinedPower":
|
case "RefinedPower":
|
||||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
return &ficsit.AllVersionsResponse{
|
||||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
Success: true,
|
||||||
Id: "DGiLzB3ZErWu2V",
|
Data: []ficsit.ModVersion{
|
||||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
{
|
||||||
{
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Id: "Eqgr4VcB8y1z9a",
|
Version: "3.2.13",
|
||||||
Version: "3.2.13",
|
Dependencies: []ficsit.Dependency{
|
||||||
Link: "/v1/version/Eqgr4VcB8y1z9a/download",
|
{
|
||||||
Hash: "8cabf9245e3f2a01b95cd3d39d98e407cfeccf355c19f1538fcbf868f81de008",
|
ModID: "ModularUI",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Condition: "^2.1.11",
|
||||||
{
|
Optional: false,
|
||||||
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,
|
{
|
||||||
},
|
ModID: "RefinedRDLib",
|
||||||
{
|
Condition: "^1.1.7",
|
||||||
Id: "BwVKMJNP8doDLg",
|
Optional: false,
|
||||||
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,
|
{
|
||||||
},
|
ModID: "SML",
|
||||||
{
|
Condition: "^3.6.1",
|
||||||
Id: "4XTjMpqFngbu9r",
|
Optional: false,
|
||||||
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,
|
|
||||||
},
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "7QcfNdo5QAAyoC",
|
||||||
|
Version: "3.2.11",
|
||||||
|
Dependencies: []ficsit.Dependency{
|
||||||
|
{
|
||||||
|
ModID: "ModularUI",
|
||||||
|
Condition: "^2.1.10",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ModID: "RefinedRDLib",
|
||||||
|
Condition: "^1.1.6",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ModID: "SML",
|
||||||
|
Condition: "^3.6.0",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "7QcfNdo5QAAyoC",
|
||||||
|
Version: "3.2.10",
|
||||||
|
Dependencies: []ficsit.Dependency{
|
||||||
|
{
|
||||||
|
ModID: "ModularUI",
|
||||||
|
Condition: "^2.1.9",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ModID: "RefinedRDLib",
|
||||||
|
Condition: "^1.1.5",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ModID: "SML",
|
||||||
|
Condition: "^3.6.0",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case "AreaActions":
|
case "AreaActions":
|
||||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
return &ficsit.AllVersionsResponse{
|
||||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
Success: true,
|
||||||
Id: "6vQ6ckVYFiidDh",
|
Data: []ficsit.ModVersion{
|
||||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
{
|
||||||
{
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Id: "5KMXBkdAz5YJe",
|
Version: "1.6.7",
|
||||||
Version: "1.6.7",
|
Dependencies: []ficsit.Dependency{
|
||||||
Link: "/v1/version/5KMXBkdAz5YJe/download",
|
{
|
||||||
Hash: "0baa673eea245b8ec5fe203a70b98deb666d85e27fb6ce9201e3c0fa3aaedcbe",
|
ModID: "SML",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Condition: "^3.4.1",
|
||||||
{
|
Optional: false,
|
||||||
Mod_id: "SML",
|
|
||||||
Condition: "^3.4.1",
|
|
||||||
Optional: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "EtEbwJj3smMn3o",
|
},
|
||||||
Version: "1.6.6",
|
{
|
||||||
Link: "/v1/version/EtEbwJj3smMn3o/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "b64aa7b3a4766295323eac47d432e0d857d042c9cfb1afdd16330483b0476c89",
|
Version: "1.6.6",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.2.0",
|
Condition: "^3.2.0",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "9uw1eDwgrQs279",
|
},
|
||||||
Version: "1.6.5",
|
{
|
||||||
Link: "/v1/version/9uw1eDwgrQs279/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "427a93383fe8a8557096666b7e81bf5fb25f54a5428248904f52adc4dc34d60c",
|
Version: "1.6.5",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.0.0",
|
Condition: "^3.0.0",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case "RefinedRDLib":
|
case "RefinedRDLib":
|
||||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
return &ficsit.AllVersionsResponse{
|
||||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
Success: true,
|
||||||
Id: "B24emzbs6xVZQr",
|
Data: []ficsit.ModVersion{
|
||||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
{
|
||||||
{
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Id: "2XcE6RUzGhZW7p",
|
Version: "1.1.7",
|
||||||
Version: "1.1.7",
|
Dependencies: []ficsit.Dependency{
|
||||||
Link: "/v1/version/2XcE6RUzGhZW7p/download",
|
{
|
||||||
Hash: "034f3a7862d0153768e1a95d29d47a9d08ebcb7ff0fc8f9f2cb59147b09f16dd",
|
ModID: "SML",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Condition: "^3.6.1",
|
||||||
{
|
Optional: false,
|
||||||
Mod_id: "SML",
|
|
||||||
Condition: "^3.6.1",
|
|
||||||
Optional: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "52RMLEigqT5Ksn",
|
},
|
||||||
Version: "1.1.6",
|
{
|
||||||
Link: "/v1/version/52RMLEigqT5Ksn/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "9577e401e1a12a29657c8e3ed0cff34815009504dc62fc1a335b1e7a3b6fed12",
|
Version: "1.1.6",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.6.0",
|
Condition: "^3.6.0",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "F4HY9eP4D5XjWQ",
|
},
|
||||||
Version: "1.1.5",
|
{
|
||||||
Link: "/v1/version/F4HY9eP4D5XjWQ/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "9cbeae078e28a661ebe15642e6d8f652c6c40c50dabd79a0781e25b84ed9bddf",
|
Version: "1.1.5",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.6.0",
|
Condition: "^3.6.0",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case "ModularUI":
|
case "ModularUI":
|
||||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
return &ficsit.AllVersionsResponse{
|
||||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
Success: true,
|
||||||
Id: "As2uJmQLLxjXLG",
|
Data: []ficsit.ModVersion{
|
||||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
{
|
||||||
{
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Id: "7ay11W9MAv6MHs",
|
Version: "2.1.12",
|
||||||
Version: "2.1.12",
|
Dependencies: []ficsit.Dependency{
|
||||||
Link: "/v1/version/7ay11W9MAv6MHs/download",
|
{
|
||||||
Hash: "a0de64c02448f9e37903e7569cc6ceee67f8e018f2774aac9cf295704b9e4696",
|
ModID: "SML",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Condition: "^3.6.1",
|
||||||
{
|
Optional: false,
|
||||||
Mod_id: "SML",
|
|
||||||
Condition: "^3.6.1",
|
|
||||||
Optional: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "4YuL9UbCDdzm68",
|
},
|
||||||
Version: "2.1.11",
|
{
|
||||||
Link: "/v1/version/4YuL9UbCDdzm68/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "b70658bfa74c132530046bee886c3c0f0277b95339b4fc67da6207cbd2cd422d",
|
Version: "2.1.11",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.6.0",
|
Condition: "^3.6.0",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "5yY2zmx5nTyhWv",
|
},
|
||||||
Version: "2.1.10",
|
{
|
||||||
Link: "/v1/version/5yY2zmx5nTyhWv/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "7c523c9e6263a0b182ed42fe4d4de40aada10c17b1b344219618cd39055870bd",
|
Version: "2.1.10",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.6.0",
|
Condition: "^3.6.0",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case "ThisModDoesNotExist$$$":
|
case "ThisModDoesNotExist$$$":
|
||||||
return &ficsit.ModVersionsWithDependenciesResponse{}, nil
|
return &ficsit.AllVersionsResponse{
|
||||||
|
Success: false,
|
||||||
|
Error: &ficsit.Error{
|
||||||
|
Message: "mod not found",
|
||||||
|
Code: 200,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
case "FicsitRemoteMonitoring":
|
case "FicsitRemoteMonitoring":
|
||||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
return &ficsit.AllVersionsResponse{
|
||||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
Success: true,
|
||||||
Id: "9LguyCdDUrpT9N",
|
Data: []ficsit.ModVersion{
|
||||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
{
|
||||||
{
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Id: "7ay11W9MAv6MHs",
|
Version: "0.10.1",
|
||||||
Version: "0.10.1",
|
Dependencies: []ficsit.Dependency{
|
||||||
Link: "/v1/version/9LguyCdDUrpT9N/download",
|
{
|
||||||
Hash: "9278b37653ad33dd859875929b15cd1f8aba88d0ea65879df2db1ae8808029d4",
|
ModID: "SML",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Condition: "^3.6.0",
|
||||||
{
|
Optional: false,
|
||||||
Mod_id: "SML",
|
|
||||||
Condition: "^3.6.0",
|
|
||||||
Optional: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "DYvfwan5tYqZKE",
|
},
|
||||||
Version: "0.10.0",
|
{
|
||||||
Link: "/v1/version/DYvfwan5tYqZKE/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "8666b37b24188c3f56b1dad6f1d437c1127280381172a1046e85142e7cb81c64",
|
Version: "0.10.0",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.5.0",
|
Condition: "^3.5.0",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
{
|
Targets: commonTargets,
|
||||||
Id: "918KMrX94xFpVw",
|
},
|
||||||
Version: "0.9.8",
|
{
|
||||||
Link: "/v1/version/918KMrX94xFpVw/download",
|
ID: "7QcfNdo5QAAyoC",
|
||||||
Hash: "d4fed641b6ecb25b9191f4dd7210576e9bd7bc644abcb3ca592200ccfd08fc44",
|
Version: "0.9.8",
|
||||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
Dependencies: []ficsit.Dependency{
|
||||||
{
|
{
|
||||||
Mod_id: "SML",
|
ModID: "SML",
|
||||||
Condition: "^3.4.1",
|
Condition: "^3.4.1",
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
|
||||||
},
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
|
33
ficsit/rest.go
Normal file
33
ficsit/rest.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package ficsit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const allVersionEndpoint = `/v1/mod/%s/versions/all`
|
||||||
|
|
||||||
|
func GetAllModVersions(modID string) (*AllVersionsResponse, error) {
|
||||||
|
response, err := http.DefaultClient.Get(viper.GetString("api-base") + fmt.Sprintf(allVersionEndpoint, modID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed fetching all versions: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed reading response body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
allVersions := AllVersionsResponse{}
|
||||||
|
if err := json.Unmarshal(body, &allVersions); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed parsing json: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &allVersions, nil
|
||||||
|
}
|
32
ficsit/types_rest.go
Normal file
32
ficsit/types_rest.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package ficsit
|
||||||
|
|
||||||
|
type AllVersionsResponse struct {
|
||||||
|
Error *Error `json:"error,omitempty"`
|
||||||
|
Data []ModVersion `json:"data,omitempty"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModVersion struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Dependencies []Dependency `json:"dependencies"`
|
||||||
|
Targets []Target `json:"targets"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dependency struct {
|
||||||
|
ModID string `json:"mod_id"`
|
||||||
|
Condition string `json:"condition"`
|
||||||
|
Optional bool `json:"optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Target struct {
|
||||||
|
VersionID string `json:"version_id"`
|
||||||
|
TargetName string `json:"target_name"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Code int64 `json:"code"`
|
||||||
|
}
|
75
flake.lock
Normal file
75
flake.lock
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694529238,
|
||||||
|
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1700014976,
|
||||||
|
"narHash": "sha256-dSGpS2YeJrXW5aH9y7Abd235gGufY3RuZFth6vuyVtU=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-unstable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701040486,
|
||||||
|
"narHash": "sha256-vawYwoHA5CwvjfqaT3A5CT9V36Eq43gxdwpux32Qkjw=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "45827faa2132b8eade424f6bdd48d8828754341a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"nixpkgs-unstable": "nixpkgs-unstable"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
19
flake.nix
Normal file
19
flake.nix
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
description = "smr-cli";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
nixpkgs-unstable.url = "flake:nixpkgs/nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils, nixpkgs-unstable }:
|
||||||
|
flake-utils.lib.eachDefaultSystem
|
||||||
|
(system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
unstable = nixpkgs-unstable.legacyPackages.${system}; in
|
||||||
|
{
|
||||||
|
devShells.default = import ./shell.nix { inherit pkgs unstable; };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
2
go.mod
2
go.mod
|
@ -2,6 +2,8 @@ module github.com/satisfactorymodding/ficsit-cli
|
||||||
|
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
|
toolchain go1.21.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/JohannesKaufmann/html-to-markdown v1.4.2
|
github.com/JohannesKaufmann/html-to-markdown v1.4.2
|
||||||
github.com/Khan/genqlient v0.6.0
|
github.com/Khan/genqlient v0.6.0
|
||||||
|
|
8
shell.nix
Normal file
8
shell.nix
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{ pkgs, unstable }:
|
||||||
|
|
||||||
|
pkgs.mkShell {
|
||||||
|
nativeBuildInputs = with pkgs.buildPackages; [
|
||||||
|
unstable.go_1_21
|
||||||
|
unstable.golangci-lint
|
||||||
|
];
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package scenes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/progress"
|
"github.com/charmbracelet/bubbles/progress"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
@ -32,57 +33,70 @@ type status struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type apply struct {
|
type apply struct {
|
||||||
root components.RootModel
|
root components.RootModel
|
||||||
parent tea.Model
|
parent tea.Model
|
||||||
error *components.ErrorComponent
|
error *components.ErrorComponent
|
||||||
installChannel chan string
|
updateChannel chan applyUpdate
|
||||||
updateChannel chan cli.InstallUpdate
|
doneChannel chan bool
|
||||||
doneChannel chan bool
|
errorChannel chan error
|
||||||
errorChannel chan error
|
cancelChannel chan bool
|
||||||
cancelChannel chan bool
|
title string
|
||||||
title string
|
status map[string]status
|
||||||
status status
|
overall progress.Model
|
||||||
overall progress.Model
|
sub progress.Model
|
||||||
sub progress.Model
|
cancelled bool
|
||||||
cancelled bool
|
done bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type applyUpdate struct {
|
||||||
|
Installation *cli.Installation
|
||||||
|
Update cli.InstallUpdate
|
||||||
|
Done bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApply(root components.RootModel, parent tea.Model) tea.Model {
|
func NewApply(root components.RootModel, parent tea.Model) tea.Model {
|
||||||
overall := progress.New(progress.WithSolidFill("118"))
|
overall := progress.New(progress.WithSolidFill("118"))
|
||||||
sub := progress.New(progress.WithSolidFill("202"))
|
sub := progress.New(progress.WithSolidFill("202"))
|
||||||
|
|
||||||
installChannel := make(chan string)
|
updateChannel := make(chan applyUpdate)
|
||||||
updateChannel := make(chan cli.InstallUpdate)
|
|
||||||
doneChannel := make(chan bool, 1)
|
doneChannel := make(chan bool, 1)
|
||||||
errorChannel := make(chan error)
|
errorChannel := make(chan error)
|
||||||
cancelChannel := make(chan bool, 1)
|
cancelChannel := make(chan bool, 1)
|
||||||
|
|
||||||
model := &apply{
|
model := &apply{
|
||||||
root: root,
|
root: root,
|
||||||
parent: parent,
|
parent: parent,
|
||||||
title: teaUtils.NonListTitleStyle.MarginTop(1).MarginBottom(1).Render("Applying Changes"),
|
title: teaUtils.NonListTitleStyle.MarginTop(1).MarginBottom(1).Render("Applying Changes"),
|
||||||
overall: overall,
|
overall: overall,
|
||||||
sub: sub,
|
sub: sub,
|
||||||
status: status{
|
status: make(map[string]status),
|
||||||
installName: "",
|
updateChannel: updateChannel,
|
||||||
done: false,
|
doneChannel: doneChannel,
|
||||||
},
|
errorChannel: errorChannel,
|
||||||
installChannel: installChannel,
|
cancelChannel: cancelChannel,
|
||||||
updateChannel: updateChannel,
|
|
||||||
doneChannel: doneChannel,
|
|
||||||
errorChannel: errorChannel,
|
|
||||||
cancelChannel: cancelChannel,
|
|
||||||
cancelled: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
var wg sync.WaitGroup
|
||||||
for _, installation := range root.GetGlobal().Installations.Installations {
|
|
||||||
installChannel <- installation.Path
|
for _, installation := range root.GetGlobal().Installations.Installations {
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
model.status[installation.Path] = status{
|
||||||
|
modProgresses: make(map[string]modProgress),
|
||||||
|
installName: installation.Path,
|
||||||
|
overallProgress: utils.GenericProgress{},
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(installation *cli.Installation) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
installUpdateChannel := make(chan cli.InstallUpdate)
|
installUpdateChannel := make(chan cli.InstallUpdate)
|
||||||
go func() {
|
go func() {
|
||||||
for update := range installUpdateChannel {
|
for update := range installUpdateChannel {
|
||||||
updateChannel <- update
|
updateChannel <- applyUpdate{
|
||||||
|
Installation: installation,
|
||||||
|
Update: update,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -91,18 +105,15 @@ func NewApply(root components.RootModel, parent tea.Model) tea.Model {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
stop := false
|
updateChannel <- applyUpdate{
|
||||||
select {
|
Installation: installation,
|
||||||
case <-cancelChannel:
|
Done: true,
|
||||||
stop = true
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
}(installation)
|
||||||
|
}
|
||||||
|
|
||||||
if stop {
|
go func() {
|
||||||
break
|
wg.Wait()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
doneChannel <- true
|
doneChannel <- true
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -122,6 +133,13 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
case keys.KeyQ:
|
case keys.KeyQ:
|
||||||
fallthrough
|
fallthrough
|
||||||
case keys.KeyEscape:
|
case keys.KeyEscape:
|
||||||
|
if m.done {
|
||||||
|
if m.parent != nil {
|
||||||
|
return m.parent, m.parent.Init()
|
||||||
|
}
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
|
||||||
m.cancelled = true
|
m.cancelled = true
|
||||||
|
|
||||||
if m.error != nil {
|
if m.error != nil {
|
||||||
|
@ -134,7 +152,7 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
m.cancelChannel <- true
|
m.cancelChannel <- true
|
||||||
return m, nil
|
return m, nil
|
||||||
case keys.KeyEnter:
|
case keys.KeyEnter:
|
||||||
if m.status.done || m.error != nil {
|
if m.done || m.error != nil {
|
||||||
if m.parent != nil {
|
if m.parent != nil {
|
||||||
return m.parent, m.parent.Init()
|
return m.parent, m.parent.Init()
|
||||||
}
|
}
|
||||||
|
@ -149,35 +167,37 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
case teaUtils.TickMsg:
|
case teaUtils.TickMsg:
|
||||||
select {
|
select {
|
||||||
case <-m.doneChannel:
|
case <-m.doneChannel:
|
||||||
m.status.done = true
|
m.done = true
|
||||||
m.status.installName = ""
|
|
||||||
break
|
|
||||||
case installName := <-m.installChannel:
|
|
||||||
m.status.installName = installName
|
|
||||||
m.status.modProgresses = make(map[string]modProgress)
|
|
||||||
m.status.overallProgress = utils.GenericProgress{}
|
|
||||||
break
|
break
|
||||||
case update := <-m.updateChannel:
|
case update := <-m.updateChannel:
|
||||||
switch update.Type {
|
s := m.status[update.Installation.Path]
|
||||||
case cli.InstallUpdateTypeOverall:
|
|
||||||
m.status.overallProgress = update.Progress
|
if update.Done {
|
||||||
case cli.InstallUpdateTypeModDownload:
|
s.done = true
|
||||||
m.status.modProgresses[update.Item.Mod] = modProgress{
|
} else {
|
||||||
downloadProgress: update.Progress,
|
switch update.Update.Type {
|
||||||
downloading: true,
|
case cli.InstallUpdateTypeOverall:
|
||||||
complete: false,
|
s.overallProgress = update.Update.Progress
|
||||||
}
|
case cli.InstallUpdateTypeModDownload:
|
||||||
case cli.InstallUpdateTypeModExtract:
|
s.modProgresses[update.Update.Item.Mod] = modProgress{
|
||||||
m.status.modProgresses[update.Item.Mod] = modProgress{
|
downloadProgress: update.Update.Progress,
|
||||||
extractProgress: update.Progress,
|
downloading: true,
|
||||||
downloading: false,
|
complete: false,
|
||||||
complete: false,
|
}
|
||||||
}
|
case cli.InstallUpdateTypeModExtract:
|
||||||
case cli.InstallUpdateTypeModComplete:
|
s.modProgresses[update.Update.Item.Mod] = modProgress{
|
||||||
m.status.modProgresses[update.Item.Mod] = modProgress{
|
extractProgress: update.Update.Progress,
|
||||||
complete: true,
|
downloading: false,
|
||||||
|
complete: false,
|
||||||
|
}
|
||||||
|
case cli.InstallUpdateTypeModComplete:
|
||||||
|
s.modProgresses[update.Update.Item.Mod] = modProgress{
|
||||||
|
complete: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.status[update.Installation.Path] = s
|
||||||
break
|
break
|
||||||
case err := <-m.errorChannel:
|
case err := <-m.errorChannel:
|
||||||
wrappedErrMessage := wrap.String(err.Error(), int(float64(m.root.Size().Width)*0.8))
|
wrappedErrMessage := wrap.String(err.Error(), int(float64(m.root.Size().Width)*0.8))
|
||||||
|
@ -197,33 +217,77 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
func (m apply) View() string {
|
func (m apply) View() string {
|
||||||
strs := make([]string, 0)
|
strs := make([]string, 0)
|
||||||
|
|
||||||
if m.status.installName != "" {
|
installationList := make([]string, len(m.status))
|
||||||
strs = append(strs, lipgloss.NewStyle().Render(m.status.installName))
|
i := 0
|
||||||
strs = append(strs, lipgloss.NewStyle().MarginBottom(1).Render(m.overall.ViewAs(m.status.overallProgress.Percentage())))
|
for key := range m.status {
|
||||||
|
installationList[i] = key
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
modReferences := make([]string, 0)
|
sort.Strings(installationList)
|
||||||
for k := range m.status.modProgresses {
|
|
||||||
modReferences = append(modReferences, k)
|
|
||||||
}
|
|
||||||
sort.Strings(modReferences)
|
|
||||||
|
|
||||||
for _, modReference := range modReferences {
|
totalHeight := 3 + 3 // Header + Footer
|
||||||
p := m.status.modProgresses[modReference]
|
totalHeight += len(installationList) * 2 // Bottom Margin + Overall progress per-install
|
||||||
if p.complete {
|
|
||||||
strs = append(strs, lipgloss.NewStyle().Foreground(lipgloss.Color("22")).Render("✓ ")+modReference)
|
bottomMargins := 1
|
||||||
} else {
|
if m.root.Size().Height < totalHeight {
|
||||||
if p.downloading {
|
bottomMargins = 0
|
||||||
strs = append(strs, lipgloss.NewStyle().Render(modReference+" (Downloading)"))
|
}
|
||||||
strs = append(strs, m.sub.ViewAs(p.downloadProgress.Percentage()))
|
|
||||||
} else {
|
totalHeight += len(installationList) // Top margin
|
||||||
strs = append(strs, lipgloss.NewStyle().Render(modReference+" (Extracting)"))
|
|
||||||
strs = append(strs, m.sub.ViewAs(p.extractProgress.Percentage()))
|
topMargins := 1
|
||||||
|
if m.root.Size().Height < totalHeight {
|
||||||
|
topMargins = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, installPath := range installationList {
|
||||||
|
totalHeight += len(m.status[installPath].modProgresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, installPath := range installationList {
|
||||||
|
s := m.status[installPath]
|
||||||
|
|
||||||
|
strs = append(strs, lipgloss.NewStyle().Margin(topMargins, 0, bottomMargins, 1).Render(lipgloss.JoinHorizontal(
|
||||||
|
lipgloss.Left,
|
||||||
|
m.overall.ViewAs(s.overallProgress.Percentage()),
|
||||||
|
" - ",
|
||||||
|
lipgloss.NewStyle().Render(installPath),
|
||||||
|
)))
|
||||||
|
|
||||||
|
modReferences := make([]string, 0)
|
||||||
|
for k := range s.modProgresses {
|
||||||
|
modReferences = append(modReferences, k)
|
||||||
|
}
|
||||||
|
sort.Strings(modReferences)
|
||||||
|
|
||||||
|
if m.root.Size().Height > totalHeight {
|
||||||
|
for _, modReference := range modReferences {
|
||||||
|
p := s.modProgresses[modReference]
|
||||||
|
if p.complete || s.done {
|
||||||
|
strs = append(strs, lipgloss.NewStyle().Foreground(lipgloss.Color("22")).Render("✓ ")+modReference)
|
||||||
|
} else {
|
||||||
|
if p.downloading {
|
||||||
|
strs = append(strs, lipgloss.JoinHorizontal(
|
||||||
|
lipgloss.Left,
|
||||||
|
m.sub.ViewAs(p.downloadProgress.Percentage()),
|
||||||
|
" - ",
|
||||||
|
lipgloss.NewStyle().Render(modReference+" (Downloading)"),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
strs = append(strs, lipgloss.JoinHorizontal(
|
||||||
|
lipgloss.Left,
|
||||||
|
m.sub.ViewAs(p.extractProgress.Percentage()),
|
||||||
|
" - ",
|
||||||
|
lipgloss.NewStyle().Render(modReference+" (Extracting)"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.status.done {
|
if m.done {
|
||||||
if m.cancelled {
|
if m.cancelled {
|
||||||
strs = append(strs, teaUtils.LabelStyle.Copy().Foreground(lipgloss.Color("196")).Padding(0).Margin(1).Render("Cancelled! Press Enter to return"))
|
strs = append(strs, teaUtils.LabelStyle.Copy().Foreground(lipgloss.Color("196")).Padding(0).Margin(1).Render("Cancelled! Press Enter to return"))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -228,6 +228,6 @@ func (m mainMenu) View() string {
|
||||||
return lipgloss.JoinVertical(lipgloss.Left, header, err, m.list.View())
|
return lipgloss.JoinVertical(lipgloss.Left, header, err, m.list.View())
|
||||||
}
|
}
|
||||||
|
|
||||||
m.list.SetSize(m.list.Width(), m.root.Size().Height-lipgloss.Height(header)-1)
|
m.list.SetSize(m.list.Width(), m.root.Size().Height-lipgloss.Height(header))
|
||||||
return lipgloss.JoinVertical(lipgloss.Left, header, m.list.View())
|
return lipgloss.JoinVertical(lipgloss.Left, header, m.list.View())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue