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
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21
|
||||
go-version: 1.21.4
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
@ -33,7 +33,7 @@ jobs:
|
|||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21
|
||||
go-version: 1.21.4
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
@ -47,7 +47,7 @@ jobs:
|
|||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: v1.54
|
||||
version: v1.55.2
|
||||
skip-pkg-cache: true
|
||||
skip-build-cache: true
|
||||
|
||||
|
@ -62,7 +62,7 @@ jobs:
|
|||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21
|
||||
go-version: 1.21.4
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -128,3 +128,4 @@ dist/
|
|||
/.graphqlconfig
|
||||
schema.graphql
|
||||
*.log
|
||||
.direnv
|
|
@ -50,7 +50,6 @@ linters:
|
|||
- contextcheck
|
||||
- durationcheck
|
||||
- errorlint
|
||||
- goconst
|
||||
- goimports
|
||||
- revive
|
||||
- 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)
|
||||
|
||||
A CLI tool for managing mods for the game Satisfactory
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
<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_ppc64le.apk">ppc64le</a></td>
|
||||
</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>
|
||||
<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>
|
||||
|
@ -56,7 +68,6 @@ A CLI tool for managing mods for the game Satisfactory
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### 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) {
|
||||
if updates != nil {
|
||||
defer close(updates)
|
||||
}
|
||||
|
||||
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
||||
if err := os.MkdirAll(downloadCache, 0o777); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
|
|
|
@ -34,7 +34,7 @@ type ficsitAPISource struct {
|
|||
provider provider.Provider
|
||||
lockfile *LockFile
|
||||
toInstall map[string]semver.Constraint
|
||||
modVersionInfo *xsync.MapOf[string, ficsit.ModVersionsWithDependenciesResponse]
|
||||
modVersionInfo *xsync.MapOf[string, ficsit.AllVersionsResponse]
|
||||
gameVersion semver.Version
|
||||
smlVersions []ficsit.SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion
|
||||
}
|
||||
|
@ -70,12 +70,15 @@ func (f *ficsitAPISource) GetPackageVersions(pkg string) ([]pubgrub.PackageVersi
|
|||
if err != nil {
|
||||
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)
|
||||
}
|
||||
f.modVersionInfo.Store(pkg, *response)
|
||||
versions := make([]pubgrub.PackageVersion, len(response.Mod.Versions))
|
||||
for i, modVersion := range response.Mod.Versions {
|
||||
versions := make([]pubgrub.PackageVersion, len(response.Data))
|
||||
for i, modVersion := range response.Data {
|
||||
v, err := semver.NewVersion(modVersion.Version)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
if dependency.Optional {
|
||||
optionalDependencies[dependency.Mod_id] = c
|
||||
optionalDependencies[dependency.ModID] = c
|
||||
} else {
|
||||
dependencies[dependency.Mod_id] = c
|
||||
dependencies[dependency.ModID] = c
|
||||
}
|
||||
}
|
||||
versions[i] = pubgrub.PackageVersion{
|
||||
|
@ -144,7 +147,7 @@ func (d DependencyResolver) ResolveModDependencies(constraints map[string]string
|
|||
gameVersion: gameVersionSemver,
|
||||
lockfile: lockFile,
|
||||
toInstall: toInstall,
|
||||
modVersionInfo: xsync.NewMapOf[string, ficsit.ModVersionsWithDependenciesResponse](),
|
||||
modVersionInfo: xsync.NewMapOf[string, ficsit.AllVersionsResponse](),
|
||||
}
|
||||
|
||||
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)
|
||||
versions := value.Mod.Versions
|
||||
versions := value.Data
|
||||
for _, ver := range versions {
|
||||
if ver.Version == v.RawString() {
|
||||
targets := make(map[string]LockedModTarget)
|
||||
for _, target := range ver.Targets {
|
||||
targets[string(target.TargetName)] = LockedModTarget{
|
||||
Link: viper.GetString("api-base") + target.Link,
|
||||
targets[target.TargetName] = LockedModTarget{
|
||||
Link: viper.GetString("api-base") + "/v1/version/" + ver.ID + "/" + target.TargetName + "/download",
|
||||
Hash: target.Hash,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -588,6 +588,9 @@ func downloadAndExtractMod(modReference string, version string, link string, has
|
|||
}
|
||||
|
||||
if updates != nil {
|
||||
close(downloadUpdates)
|
||||
close(extractUpdates)
|
||||
|
||||
updates <- InstallUpdate{
|
||||
Type: InstallUpdateTypeModComplete,
|
||||
Item: InstallUpdateItem{
|
||||
|
@ -595,8 +598,6 @@ func downloadAndExtractMod(modReference string, version string, link string, has
|
|||
Version: version,
|
||||
},
|
||||
}
|
||||
|
||||
close(extractUpdates)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
|
|
@ -34,8 +34,8 @@ func (p ficsitProvider) SMLVersions(context context.Context) (*ficsit.SMLVersion
|
|||
return ficsit.SMLVersions(context, p.client)
|
||||
}
|
||||
|
||||
func (p ficsitProvider) ModVersionsWithDependencies(context context.Context, modID string) (*ficsit.ModVersionsWithDependenciesResponse, error) {
|
||||
return ficsit.ModVersionsWithDependencies(context, p.client, modID)
|
||||
func (p ficsitProvider) ModVersionsWithDependencies(_ context.Context, modID string) (*ficsit.AllVersionsResponse, error) {
|
||||
return ficsit.GetAllModVersions(modID)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get cache")
|
||||
}
|
||||
|
||||
versions := make([]ficsit.ModVersionsWithDependenciesModVersionsVersion, 0)
|
||||
versions := make([]ficsit.ModVersion, 0)
|
||||
|
||||
for _, modFile := range cachedModFiles {
|
||||
versions = append(versions, ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
||||
Id: modID + ":" + modFile.Plugin.SemVersion,
|
||||
versions = append(versions, ficsit.ModVersion{
|
||||
ID: modID + ":" + modFile.Plugin.SemVersion,
|
||||
Version: modFile.Plugin.SemVersion,
|
||||
})
|
||||
}
|
||||
|
||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
||||
Id: modID,
|
||||
Versions: versions,
|
||||
},
|
||||
return &ficsit.AllVersionsResponse{
|
||||
Success: true,
|
||||
Data: versions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ func (p MixedProvider) SMLVersions(context context.Context) (*ficsit.SMLVersions
|
|||
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 {
|
||||
return p.localProvider.ModVersionsWithDependencies(context, modID)
|
||||
}
|
||||
|
|
|
@ -11,7 +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)
|
||||
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)
|
||||
IsOffline() bool
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ func TestResolutionNonExistentMod(t *testing.T) {
|
|||
},
|
||||
}).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) {
|
||||
|
|
|
@ -163,49 +163,43 @@ func (m MockProvider) SMLVersions(_ context.Context) (*ficsit.SMLVersionsRespons
|
|||
}, nil
|
||||
}
|
||||
|
||||
var commonTargets = []ficsit.ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget{
|
||||
var commonTargets = []ficsit.Target{
|
||||
{
|
||||
TargetName: ficsit.TargetNameWindows,
|
||||
Link: "/v1/version/7QcfNdo5QAAyoC/Windows/download",
|
||||
TargetName: "Windows",
|
||||
Hash: "62f5c84eca8480b3ffe7d6c90f759e3b463f482530e27d854fd48624fdd3acc9",
|
||||
},
|
||||
{
|
||||
TargetName: ficsit.TargetNameWindowsserver,
|
||||
Link: "/v1/version/7QcfNdo5QAAyoC/WindowsServer/download",
|
||||
TargetName: "WindowsServer",
|
||||
Hash: "8a83fcd4abece4192038769cc672fff6764d72c32fb6c7a8c58d66156bb07917",
|
||||
},
|
||||
{
|
||||
TargetName: ficsit.TargetNameLinuxserver,
|
||||
Link: "/v1/version/7QcfNdo5QAAyoC/LinuxServer/download",
|
||||
TargetName: "LinuxServer",
|
||||
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 {
|
||||
case "RefinedPower":
|
||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
||||
Id: "DGiLzB3ZErWu2V",
|
||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
||||
return &ficsit.AllVersionsResponse{
|
||||
Success: true,
|
||||
Data: []ficsit.ModVersion{
|
||||
{
|
||||
Id: "Eqgr4VcB8y1z9a",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "3.2.13",
|
||||
Link: "/v1/version/Eqgr4VcB8y1z9a/download",
|
||||
Hash: "8cabf9245e3f2a01b95cd3d39d98e407cfeccf355c19f1538fcbf868f81de008",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "ModularUI",
|
||||
ModID: "ModularUI",
|
||||
Condition: "^2.1.11",
|
||||
Optional: false,
|
||||
},
|
||||
{
|
||||
Mod_id: "RefinedRDLib",
|
||||
ModID: "RefinedRDLib",
|
||||
Condition: "^1.1.7",
|
||||
Optional: false,
|
||||
},
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.1",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -213,23 +207,21 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "BwVKMJNP8doDLg",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "3.2.11",
|
||||
Link: "/v1/version/BwVKMJNP8doDLg/download",
|
||||
Hash: "b64aa7b3a4766295323eac47d432e0d857d042c9cfb1afdd16330483b0476c89",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "ModularUI",
|
||||
ModID: "ModularUI",
|
||||
Condition: "^2.1.10",
|
||||
Optional: false,
|
||||
},
|
||||
{
|
||||
Mod_id: "RefinedRDLib",
|
||||
ModID: "RefinedRDLib",
|
||||
Condition: "^1.1.6",
|
||||
Optional: false,
|
||||
},
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -237,23 +229,21 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "4XTjMpqFngbu9r",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "3.2.10",
|
||||
Link: "/v1/version/4XTjMpqFngbu9r/download",
|
||||
Hash: "093f92c6d52c853bade386d5bc79cf103b27fb6e9d6f806850929b866ff98222",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "ModularUI",
|
||||
ModID: "ModularUI",
|
||||
Condition: "^2.1.9",
|
||||
Optional: false,
|
||||
},
|
||||
{
|
||||
Mod_id: "RefinedRDLib",
|
||||
ModID: "RefinedRDLib",
|
||||
Condition: "^1.1.5",
|
||||
Optional: false,
|
||||
},
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -261,21 +251,17 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "AreaActions":
|
||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
||||
Id: "6vQ6ckVYFiidDh",
|
||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
||||
return &ficsit.AllVersionsResponse{
|
||||
Success: true,
|
||||
Data: []ficsit.ModVersion{
|
||||
{
|
||||
Id: "5KMXBkdAz5YJe",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.6.7",
|
||||
Link: "/v1/version/5KMXBkdAz5YJe/download",
|
||||
Hash: "0baa673eea245b8ec5fe203a70b98deb666d85e27fb6ce9201e3c0fa3aaedcbe",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.4.1",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -283,13 +269,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "EtEbwJj3smMn3o",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.6.6",
|
||||
Link: "/v1/version/EtEbwJj3smMn3o/download",
|
||||
Hash: "b64aa7b3a4766295323eac47d432e0d857d042c9cfb1afdd16330483b0476c89",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.2.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -297,13 +281,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "9uw1eDwgrQs279",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.6.5",
|
||||
Link: "/v1/version/9uw1eDwgrQs279/download",
|
||||
Hash: "427a93383fe8a8557096666b7e81bf5fb25f54a5428248904f52adc4dc34d60c",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.0.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -311,21 +293,17 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "RefinedRDLib":
|
||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
||||
Id: "B24emzbs6xVZQr",
|
||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
||||
return &ficsit.AllVersionsResponse{
|
||||
Success: true,
|
||||
Data: []ficsit.ModVersion{
|
||||
{
|
||||
Id: "2XcE6RUzGhZW7p",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.1.7",
|
||||
Link: "/v1/version/2XcE6RUzGhZW7p/download",
|
||||
Hash: "034f3a7862d0153768e1a95d29d47a9d08ebcb7ff0fc8f9f2cb59147b09f16dd",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.1",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -333,13 +311,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "52RMLEigqT5Ksn",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.1.6",
|
||||
Link: "/v1/version/52RMLEigqT5Ksn/download",
|
||||
Hash: "9577e401e1a12a29657c8e3ed0cff34815009504dc62fc1a335b1e7a3b6fed12",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -347,13 +323,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "F4HY9eP4D5XjWQ",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "1.1.5",
|
||||
Link: "/v1/version/F4HY9eP4D5XjWQ/download",
|
||||
Hash: "9cbeae078e28a661ebe15642e6d8f652c6c40c50dabd79a0781e25b84ed9bddf",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -361,21 +335,17 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "ModularUI":
|
||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
||||
Id: "As2uJmQLLxjXLG",
|
||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
||||
return &ficsit.AllVersionsResponse{
|
||||
Success: true,
|
||||
Data: []ficsit.ModVersion{
|
||||
{
|
||||
Id: "7ay11W9MAv6MHs",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "2.1.12",
|
||||
Link: "/v1/version/7ay11W9MAv6MHs/download",
|
||||
Hash: "a0de64c02448f9e37903e7569cc6ceee67f8e018f2774aac9cf295704b9e4696",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.1",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -383,13 +353,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "4YuL9UbCDdzm68",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "2.1.11",
|
||||
Link: "/v1/version/4YuL9UbCDdzm68/download",
|
||||
Hash: "b70658bfa74c132530046bee886c3c0f0277b95339b4fc67da6207cbd2cd422d",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -397,13 +365,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "5yY2zmx5nTyhWv",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "2.1.10",
|
||||
Link: "/v1/version/5yY2zmx5nTyhWv/download",
|
||||
Hash: "7c523c9e6263a0b182ed42fe4d4de40aada10c17b1b344219618cd39055870bd",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -411,23 +377,25 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "ThisModDoesNotExist$$$":
|
||||
return &ficsit.ModVersionsWithDependenciesResponse{}, nil
|
||||
return &ficsit.AllVersionsResponse{
|
||||
Success: false,
|
||||
Error: &ficsit.Error{
|
||||
Message: "mod not found",
|
||||
Code: 200,
|
||||
},
|
||||
}, nil
|
||||
case "FicsitRemoteMonitoring":
|
||||
return &ficsit.ModVersionsWithDependenciesResponse{
|
||||
Mod: ficsit.ModVersionsWithDependenciesMod{
|
||||
Id: "9LguyCdDUrpT9N",
|
||||
Versions: []ficsit.ModVersionsWithDependenciesModVersionsVersion{
|
||||
return &ficsit.AllVersionsResponse{
|
||||
Success: true,
|
||||
Data: []ficsit.ModVersion{
|
||||
{
|
||||
Id: "7ay11W9MAv6MHs",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "0.10.1",
|
||||
Link: "/v1/version/9LguyCdDUrpT9N/download",
|
||||
Hash: "9278b37653ad33dd859875929b15cd1f8aba88d0ea65879df2db1ae8808029d4",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.6.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -435,13 +403,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "DYvfwan5tYqZKE",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "0.10.0",
|
||||
Link: "/v1/version/DYvfwan5tYqZKE/download",
|
||||
Hash: "8666b37b24188c3f56b1dad6f1d437c1127280381172a1046e85142e7cb81c64",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.5.0",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -449,13 +415,11 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
{
|
||||
Id: "918KMrX94xFpVw",
|
||||
ID: "7QcfNdo5QAAyoC",
|
||||
Version: "0.9.8",
|
||||
Link: "/v1/version/918KMrX94xFpVw/download",
|
||||
Hash: "d4fed641b6ecb25b9191f4dd7210576e9bd7bc644abcb3ca592200ccfd08fc44",
|
||||
Dependencies: []ficsit.ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency{
|
||||
Dependencies: []ficsit.Dependency{
|
||||
{
|
||||
Mod_id: "SML",
|
||||
ModID: "SML",
|
||||
Condition: "^3.4.1",
|
||||
Optional: false,
|
||||
},
|
||||
|
@ -463,7 +427,6 @@ func (m MockProvider) ModVersionsWithDependencies(_ context.Context, modID strin
|
|||
Targets: commonTargets,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, 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
|
||||
|
||||
toolchain go1.21.4
|
||||
|
||||
require (
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.4.2
|
||||
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 (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/charmbracelet/bubbles/progress"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
|
@ -35,24 +36,29 @@ type apply struct {
|
|||
root components.RootModel
|
||||
parent tea.Model
|
||||
error *components.ErrorComponent
|
||||
installChannel chan string
|
||||
updateChannel chan cli.InstallUpdate
|
||||
updateChannel chan applyUpdate
|
||||
doneChannel chan bool
|
||||
errorChannel chan error
|
||||
cancelChannel chan bool
|
||||
title string
|
||||
status status
|
||||
status map[string]status
|
||||
overall progress.Model
|
||||
sub progress.Model
|
||||
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 {
|
||||
overall := progress.New(progress.WithSolidFill("118"))
|
||||
sub := progress.New(progress.WithSolidFill("202"))
|
||||
|
||||
installChannel := make(chan string)
|
||||
updateChannel := make(chan cli.InstallUpdate)
|
||||
updateChannel := make(chan applyUpdate)
|
||||
doneChannel := make(chan bool, 1)
|
||||
errorChannel := make(chan error)
|
||||
cancelChannel := make(chan bool, 1)
|
||||
|
@ -63,26 +69,34 @@ func NewApply(root components.RootModel, parent tea.Model) tea.Model {
|
|||
title: teaUtils.NonListTitleStyle.MarginTop(1).MarginBottom(1).Render("Applying Changes"),
|
||||
overall: overall,
|
||||
sub: sub,
|
||||
status: status{
|
||||
installName: "",
|
||||
done: false,
|
||||
},
|
||||
installChannel: installChannel,
|
||||
status: make(map[string]status),
|
||||
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
|
||||
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)
|
||||
go func() {
|
||||
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
|
||||
}
|
||||
|
||||
stop := false
|
||||
select {
|
||||
case <-cancelChannel:
|
||||
stop = true
|
||||
default:
|
||||
}
|
||||
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
updateChannel <- applyUpdate{
|
||||
Installation: installation,
|
||||
Done: true,
|
||||
}
|
||||
}(installation)
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
doneChannel <- true
|
||||
}()
|
||||
|
||||
|
@ -122,6 +133,13 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case keys.KeyQ:
|
||||
fallthrough
|
||||
case keys.KeyEscape:
|
||||
if m.done {
|
||||
if m.parent != nil {
|
||||
return m.parent, m.parent.Init()
|
||||
}
|
||||
return m, tea.Quit
|
||||
}
|
||||
|
||||
m.cancelled = true
|
||||
|
||||
if m.error != nil {
|
||||
|
@ -134,7 +152,7 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
m.cancelChannel <- true
|
||||
return m, nil
|
||||
case keys.KeyEnter:
|
||||
if m.status.done || m.error != nil {
|
||||
if m.done || m.error != nil {
|
||||
if m.parent != nil {
|
||||
return m.parent, m.parent.Init()
|
||||
}
|
||||
|
@ -149,35 +167,37 @@ func (m apply) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case teaUtils.TickMsg:
|
||||
select {
|
||||
case <-m.doneChannel:
|
||||
m.status.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{}
|
||||
m.done = true
|
||||
break
|
||||
case update := <-m.updateChannel:
|
||||
switch update.Type {
|
||||
s := m.status[update.Installation.Path]
|
||||
|
||||
if update.Done {
|
||||
s.done = true
|
||||
} else {
|
||||
switch update.Update.Type {
|
||||
case cli.InstallUpdateTypeOverall:
|
||||
m.status.overallProgress = update.Progress
|
||||
s.overallProgress = update.Update.Progress
|
||||
case cli.InstallUpdateTypeModDownload:
|
||||
m.status.modProgresses[update.Item.Mod] = modProgress{
|
||||
downloadProgress: update.Progress,
|
||||
s.modProgresses[update.Update.Item.Mod] = modProgress{
|
||||
downloadProgress: update.Update.Progress,
|
||||
downloading: true,
|
||||
complete: false,
|
||||
}
|
||||
case cli.InstallUpdateTypeModExtract:
|
||||
m.status.modProgresses[update.Item.Mod] = modProgress{
|
||||
extractProgress: update.Progress,
|
||||
s.modProgresses[update.Update.Item.Mod] = modProgress{
|
||||
extractProgress: update.Update.Progress,
|
||||
downloading: false,
|
||||
complete: false,
|
||||
}
|
||||
case cli.InstallUpdateTypeModComplete:
|
||||
m.status.modProgresses[update.Item.Mod] = modProgress{
|
||||
s.modProgresses[update.Update.Item.Mod] = modProgress{
|
||||
complete: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m.status[update.Installation.Path] = s
|
||||
break
|
||||
case err := <-m.errorChannel:
|
||||
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 {
|
||||
strs := make([]string, 0)
|
||||
|
||||
if m.status.installName != "" {
|
||||
strs = append(strs, lipgloss.NewStyle().Render(m.status.installName))
|
||||
strs = append(strs, lipgloss.NewStyle().MarginBottom(1).Render(m.overall.ViewAs(m.status.overallProgress.Percentage())))
|
||||
installationList := make([]string, len(m.status))
|
||||
i := 0
|
||||
for key := range m.status {
|
||||
installationList[i] = key
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Strings(installationList)
|
||||
|
||||
totalHeight := 3 + 3 // Header + Footer
|
||||
totalHeight += len(installationList) * 2 // Bottom Margin + Overall progress per-install
|
||||
|
||||
bottomMargins := 1
|
||||
if m.root.Size().Height < totalHeight {
|
||||
bottomMargins = 0
|
||||
}
|
||||
|
||||
totalHeight += len(installationList) // Top margin
|
||||
|
||||
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 m.status.modProgresses {
|
||||
for k := range s.modProgresses {
|
||||
modReferences = append(modReferences, k)
|
||||
}
|
||||
sort.Strings(modReferences)
|
||||
|
||||
if m.root.Size().Height > totalHeight {
|
||||
for _, modReference := range modReferences {
|
||||
p := m.status.modProgresses[modReference]
|
||||
if p.complete {
|
||||
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.NewStyle().Render(modReference+" (Downloading)"))
|
||||
strs = append(strs, m.sub.ViewAs(p.downloadProgress.Percentage()))
|
||||
strs = append(strs, lipgloss.JoinHorizontal(
|
||||
lipgloss.Left,
|
||||
m.sub.ViewAs(p.downloadProgress.Percentage()),
|
||||
" - ",
|
||||
lipgloss.NewStyle().Render(modReference+" (Downloading)"),
|
||||
))
|
||||
} else {
|
||||
strs = append(strs, lipgloss.NewStyle().Render(modReference+" (Extracting)"))
|
||||
strs = append(strs, m.sub.ViewAs(p.extractProgress.Percentage()))
|
||||
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 {
|
||||
strs = append(strs, teaUtils.LabelStyle.Copy().Foreground(lipgloss.Color("196")).Padding(0).Margin(1).Render("Cancelled! Press Enter to return"))
|
||||
} else {
|
||||
|
|
|
@ -228,6 +228,6 @@ func (m mainMenu) View() string {
|
|||
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())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue