Compare commits
10 commits
5e9fe2aebb
...
9045893b1d
Author | SHA1 | Date | |
---|---|---|---|
9045893b1d | |||
|
5dc8bdbaf6 | ||
|
a4d8bea800 | ||
|
9fc258edf6 | ||
|
3640e5e708 | ||
|
bf6d6b0850 | ||
|
7cd93926c6 | ||
|
8acb690014 | ||
|
d744884f25 | ||
|
d051b5800a |
60 changed files with 1499 additions and 1062 deletions
28
.editorconfig
Normal file
28
.editorconfig
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
root = true
|
||||||
|
["*"]
|
||||||
|
charset = "utf-8"
|
||||||
|
curly_bracket_next_line = true
|
||||||
|
end_of_line = "lf"
|
||||||
|
indent_brace_style = "K&R"
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = "space"
|
||||||
|
insert_final_newline = true
|
||||||
|
max_line_length = 80
|
||||||
|
tab_width = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
["*.md"]
|
||||||
|
max_line_length = "off"
|
||||||
|
|
||||||
|
["package.json"]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = "space"
|
||||||
|
tab_width = 2
|
||||||
|
|
||||||
|
["{LICENSES/**,LICENSE}"]
|
||||||
|
charset = "unset"
|
||||||
|
end_of_line = "unset"
|
||||||
|
indent_size = "unset"
|
||||||
|
indent_style = "unset"
|
||||||
|
insert_final_newline = "unset"
|
||||||
|
trim_trailing_whitespace = "unset"
|
2
.github/workflows/push.yaml
vendored
2
.github/workflows/push.yaml
vendored
|
@ -96,7 +96,7 @@ jobs:
|
||||||
|
|
||||||
- name: Boot ftp and sftp
|
- name: Boot ftp and sftp
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
run: docker-compose -f docker-compose-test.yml up -d
|
run: docker compose -f docker-compose-test.yml up -d
|
||||||
|
|
||||||
- name: Download GQL schema
|
- name: Download GQL schema
|
||||||
run: "npx graphqurl https://api.ficsit.dev/v2/query --introspect -H 'content-type: application/json' > schema.graphql"
|
run: "npx graphqurl https://api.ficsit.dev/v2/query --introspect -H 'content-type: application/json' > schema.graphql"
|
||||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -42,7 +42,7 @@ jobs:
|
||||||
uses: goreleaser/goreleaser-action@v2
|
uses: goreleaser/goreleaser-action@v2
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: release --rm-dist --debug
|
args: release --clean
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
AUR_KEY: ${{ secrets.AUR_KEY }}
|
AUR_KEY: ${{ secrets.AUR_KEY }}
|
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -129,4 +129,11 @@ dist/
|
||||||
schema.graphql
|
schema.graphql
|
||||||
*.log
|
*.log
|
||||||
.direnv
|
.direnv
|
||||||
/SatisfactoryDedicatedServer
|
/SatisfactoryDedicatedServer
|
||||||
|
# nixago: ignore-linked-files
|
||||||
|
/treefmt.toml
|
||||||
|
/.prettierrc.json
|
||||||
|
/lefthook.yml
|
||||||
|
/.conform.yaml
|
||||||
|
# mfgames-project-setup: ignore-files
|
||||||
|
/.direnv/
|
|
@ -29,11 +29,8 @@ builds:
|
||||||
- windows
|
- windows
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
- arm
|
|
||||||
- arm64
|
- arm64
|
||||||
- 386
|
- 386
|
||||||
goarm:
|
|
||||||
- 7
|
|
||||||
|
|
||||||
universal_binaries:
|
universal_binaries:
|
||||||
- replace: true
|
- replace: true
|
||||||
|
|
85
README.md
85
README.md
|
@ -1,8 +1,10 @@
|
||||||
<img align="right" width="310" src="./.github/screenshot.png" />
|
<!-- markdownlint-disable MD033 -->
|
||||||
|
<!-- markdownlint-disable MD041 -->
|
||||||
|
<img align="right" width="310" src="./.github/screenshot.png" alt="ficsit-cli screenshot" />
|
||||||
|
|
||||||
# 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/satisfactorymodding/ficsit-cli/actions/workflows/push.yaml/badge.svg)](https://github.com/satisfactorymodding/ficsit-cli/actions/workflows/push.yaml) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/satisfactorymodding/ficsit-cli) ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/satisfactorymodding/ficsit-cli) [![GitHub license](https://img.shields.io/github/license/satisfactorymodding/ficsit-cli)](https://github.com/satisfactorymodding/ficsit-cli/blob/master/LICENSE) ![GitHub all releases](https://img.shields.io/github/downloads/satisfactorymodding/ficsit-cli/total)
|
||||||
|
|
||||||
A CLI tool for managing mods for the game Satisfactory
|
A CLI tool for managing mods for the game [Satisfactory](https://www.satisfactorygame.com/).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -19,10 +21,10 @@ A CLI tool for managing mods for the game Satisfactory
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Windows</th>
|
<th>Windows</th>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_windows_amd64.exe">amd64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_windows_amd64.exe">amd64</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_windows_386.exe">386</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_windows_386.exe">386</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_windows_arm64.exe">arm64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_windows_arm64.exe">arm64</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_windows_armv7.exe">armv7</a></td>
|
<td>N/A</td>
|
||||||
<td>N/A</td>
|
<td>N/A</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -31,39 +33,39 @@ A CLI tool for managing mods for the game Satisfactory
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Debian</th>
|
<th>Debian</th>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_amd64.deb">amd64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_amd64.deb">amd64</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_386.deb">386</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_386.deb">386</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_arm64.deb">arm64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_arm64.deb">arm64</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_armv7.deb">armv7</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_armv7.deb">armv7</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le.deb">ppc64le</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le.deb">ppc64le</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Fedora</th>
|
<th>Fedora</th>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_amd64.rpm">amd64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_amd64.rpm">amd64</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_386.rpm">386</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_386.rpm">386</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_arm64.rpm">arm64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_arm64.rpm">arm64</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_armv7.rpm">armv7</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_armv7.rpm">armv7</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le.rpm">ppc64le</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le.rpm">ppc64le</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Alpine</th>
|
<th>Alpine</th>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_amd64.apk">amd64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_amd64.apk">amd64</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_386.apk">386</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_386.apk">386</a></td>
|
||||||
<td><a href="https://github.com/Vilsol/ficsit-cli/releases/latest/download/ficsit_linux_arm64.apk">arm64</a></td>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_arm64.apk">arm64</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/satisfactorymodding/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/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le.apk">ppc64le</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Linux</th>
|
<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/satisfactorymodding/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/satisfactorymodding/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/satisfactorymodding/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/satisfactorymodding/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>
|
<td><a href="https://github.com/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_linux_ppc64le">ppc64le</a></td>
|
||||||
</tr>
|
</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/satisfactorymodding/ficsit-cli/releases/latest/download/ficsit_darwin_all">darwin_all</a></td>
|
||||||
<td>N/A</td>
|
<td>N/A</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -74,21 +76,38 @@ A CLI tool for managing mods for the game Satisfactory
|
||||||
|
|
||||||
To launch the interactive CLI, run the executable without any arguments.
|
To launch the interactive CLI, run the executable without any arguments.
|
||||||
|
|
||||||
|
All screens display control hints at the bottom.
|
||||||
|
|
||||||
### Command Line
|
### Command Line
|
||||||
|
|
||||||
Run `ficsit help` to see a list of available commands.
|
Run `ficsit help` to see a list of available commands and flags.
|
||||||
|
|
||||||
|
## Managing Installations
|
||||||
|
|
||||||
|
Unlike [Satisfactory Mod Manager](https://github.com/satisfactorymodding/SatisfactoryModManager/),
|
||||||
|
ficsit-cli does not automatically detect installations.
|
||||||
|
|
||||||
|
First, locate your game install path.
|
||||||
|
Check the [Modding FAQ](https://docs.ficsit.app/satisfactory-modding/latest/faq.html#Files_GameInstall)
|
||||||
|
to learn how to find it given your specific install situation.
|
||||||
|
|
||||||
|
To add installations in the interactive CLI, use `Installations` > `new installation`.
|
||||||
|
|
||||||
|
To add installations from the command line, use `ficsit-cli installation add yourPathHere`.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
* Profile and installation records are located in `%APPDATA%\ficsit\`
|
- Profile and installation records are located in `%APPDATA%\ficsit\`
|
||||||
* Downloads are cached in `%LOCALAPPDATA%\ficsit\downloadCache\`
|
- Downloads are cached in `%LOCALAPPDATA%\ficsit\downloadCache\`
|
||||||
|
|
||||||
|
Get help on the [modding Discord](https://discord.ficsit.app/).
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
* [Go 1.21](https://go.dev/doc/install)
|
- [Go 1.21](https://go.dev/doc/install)
|
||||||
* IDE of Choice. Goland or VSCode suggested.
|
- IDE of Choice. Goland or VSCode suggested.
|
||||||
|
|
||||||
### Code Generation
|
### Code Generation
|
||||||
|
|
||||||
|
|
118
cli/cache/integrity.go
vendored
118
cli/cache/integrity.go
vendored
|
@ -1,118 +0,0 @@
|
||||||
package cache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/puzpuzpuz/xsync/v3"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/satisfactorymodding/ficsit-cli/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
type hashInfo struct {
|
|
||||||
Modified time.Time
|
|
||||||
Hash string
|
|
||||||
Size int64
|
|
||||||
}
|
|
||||||
|
|
||||||
var hashCache *xsync.MapOf[string, hashInfo]
|
|
||||||
|
|
||||||
var integrityFilename = ".integrity"
|
|
||||||
|
|
||||||
func getFileHash(file string) (string, error) {
|
|
||||||
if hashCache == nil {
|
|
||||||
loadHashCache()
|
|
||||||
}
|
|
||||||
cachedHash, ok := hashCache.Load(file)
|
|
||||||
if !ok {
|
|
||||||
return cacheFileHash(file)
|
|
||||||
}
|
|
||||||
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
|
||||||
stat, err := os.Stat(filepath.Join(downloadCache, file))
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to stat file: %w", err)
|
|
||||||
}
|
|
||||||
if stat.Size() != cachedHash.Size || stat.ModTime() != cachedHash.Modified {
|
|
||||||
return cacheFileHash(file)
|
|
||||||
}
|
|
||||||
return cachedHash.Hash, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cacheFileHash(file string) (string, error) {
|
|
||||||
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
|
||||||
stat, err := os.Stat(filepath.Join(downloadCache, file))
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to stat file: %w", err)
|
|
||||||
}
|
|
||||||
f, err := os.Open(filepath.Join(downloadCache, file))
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to open file: %w", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
hash, err := utils.SHA256Data(f)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to hash file: %w", err)
|
|
||||||
}
|
|
||||||
hashCache.Store(file, hashInfo{
|
|
||||||
Hash: hash,
|
|
||||||
Size: stat.Size(),
|
|
||||||
Modified: stat.ModTime(),
|
|
||||||
})
|
|
||||||
saveHashCache()
|
|
||||||
return hash, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadHashCache() {
|
|
||||||
hashCache = xsync.NewMapOf[string, hashInfo]()
|
|
||||||
cacheFile := filepath.Join(viper.GetString("cache-dir"), "downloadCache", integrityFilename)
|
|
||||||
if _, err := os.Stat(cacheFile); os.IsNotExist(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f, err := os.Open(cacheFile)
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn("failed to open hash cache, recreating", slog.Any("err", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
hashCacheJSON, err := io.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn("failed to read hash cache, recreating", slog.Any("err", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var plainCache map[string]hashInfo
|
|
||||||
if err := json.Unmarshal(hashCacheJSON, &plainCache); err != nil {
|
|
||||||
slog.Warn("failed to unmarshal hash cache, recreating", slog.Any("err", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range plainCache {
|
|
||||||
hashCache.Store(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func saveHashCache() {
|
|
||||||
cacheFile := filepath.Join(viper.GetString("cache-dir"), "downloadCache", integrityFilename)
|
|
||||||
plainCache := make(map[string]hashInfo, hashCache.Size())
|
|
||||||
hashCache.Range(func(k string, v hashInfo) bool {
|
|
||||||
plainCache[k] = v
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
hashCacheJSON, err := json.Marshal(plainCache)
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn("failed to marshal hash cache", slog.Any("err", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.WriteFile(cacheFile, hashCacheJSON, 0o755); err != nil {
|
|
||||||
slog.Warn("failed to write hash cache", slog.Any("err", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
81
cli/cache/cache.go → cli/cache/mod_details.go
vendored
81
cli/cache/cache.go → cli/cache/mod_details.go
vendored
|
@ -12,43 +12,44 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mircearoata/pubgrub-go/pubgrub/semver"
|
||||||
"github.com/puzpuzpuz/xsync/v3"
|
"github.com/puzpuzpuz/xsync/v3"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const IconFilename = "Resources/Icon128.png" // This is the path UE expects for the icon
|
const IconFilename = "Resources/Icon128.png" // This is the path UE expects for the icon
|
||||||
|
|
||||||
type File struct {
|
type Mod struct {
|
||||||
Icon *string
|
ModReference string
|
||||||
ModReference string
|
Name string
|
||||||
Hash string
|
Author string
|
||||||
Plugin UPlugin
|
Icon *string
|
||||||
Size int64
|
LatestVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
var loadedCache *xsync.MapOf[string, []File]
|
var loadedMods *xsync.MapOf[string, Mod]
|
||||||
|
|
||||||
func GetCache() (*xsync.MapOf[string, []File], error) {
|
func GetCacheMods() (*xsync.MapOf[string, Mod], error) {
|
||||||
if loadedCache != nil {
|
if loadedMods != nil {
|
||||||
return loadedCache, nil
|
return loadedMods, nil
|
||||||
}
|
}
|
||||||
return LoadCache()
|
return LoadCacheMods()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCacheMod(mod string) ([]File, error) {
|
func GetCacheMod(mod string) (Mod, error) {
|
||||||
cache, err := GetCache()
|
cache, err := GetCacheMods()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Mod{}, err
|
||||||
}
|
}
|
||||||
value, _ := cache.Load(mod)
|
value, _ := cache.Load(mod)
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadCache() (*xsync.MapOf[string, []File], error) {
|
func LoadCacheMods() (*xsync.MapOf[string, Mod], error) {
|
||||||
loadedCache = xsync.NewMapOf[string, []File]()
|
loadedMods = xsync.NewMapOf[string, Mod]()
|
||||||
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
||||||
if _, err := os.Stat(downloadCache); os.IsNotExist(err) {
|
if _, err := os.Stat(downloadCache); os.IsNotExist(err) {
|
||||||
return loadedCache, nil
|
return loadedMods, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
items, err := os.ReadDir(downloadCache)
|
items, err := os.ReadDir(downloadCache)
|
||||||
|
@ -60,32 +61,45 @@ func LoadCache() (*xsync.MapOf[string, []File], error) {
|
||||||
if item.IsDir() {
|
if item.IsDir() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if item.Name() == integrityFilename {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = addFileToCache(item.Name())
|
_, err = addFileToCache(item.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("failed to add file to cache", slog.String("file", item.Name()), slog.Any("err", err))
|
slog.Error("failed to add file to cache", slog.String("file", item.Name()), slog.Any("err", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return loadedCache, nil
|
return loadedMods, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addFileToCache(filename string) (*File, error) {
|
func addFileToCache(filename string) (*Mod, error) {
|
||||||
cacheFile, err := readCacheFile(filename)
|
cacheFile, err := readCacheFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read cache file: %w", err)
|
return nil, fmt.Errorf("failed to read cache file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedCache.Compute(cacheFile.ModReference, func(oldValue []File, _ bool) ([]File, bool) {
|
loadedMods.Compute(cacheFile.ModReference, func(oldValue Mod, loaded bool) (Mod, bool) {
|
||||||
return append(oldValue, *cacheFile), false
|
if !loaded {
|
||||||
|
return *cacheFile, false
|
||||||
|
}
|
||||||
|
oldVersion, err := semver.NewVersion(oldValue.LatestVersion)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to parse version", slog.String("version", oldValue.LatestVersion), slog.Any("err", err))
|
||||||
|
return *cacheFile, false
|
||||||
|
}
|
||||||
|
newVersion, err := semver.NewVersion(cacheFile.LatestVersion)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to parse version", slog.String("version", cacheFile.LatestVersion), slog.Any("err", err))
|
||||||
|
return oldValue, false
|
||||||
|
}
|
||||||
|
if newVersion.Compare(oldVersion) > 0 {
|
||||||
|
return *cacheFile, false
|
||||||
|
}
|
||||||
|
return oldValue, false
|
||||||
})
|
})
|
||||||
|
|
||||||
return cacheFile, nil
|
return cacheFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readCacheFile(filename string) (*File, error) {
|
func readCacheFile(filename string) (*Mod, error) {
|
||||||
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
downloadCache := filepath.Join(viper.GetString("cache-dir"), "downloadCache")
|
||||||
path := filepath.Join(downloadCache, filename)
|
path := filepath.Join(downloadCache, filename)
|
||||||
stat, err := os.Stat(path)
|
stat, err := os.Stat(path)
|
||||||
|
@ -132,11 +146,6 @@ func readCacheFile(filename string) (*File, error) {
|
||||||
|
|
||||||
modReference := strings.TrimSuffix(upluginFile.Name, ".uplugin")
|
modReference := strings.TrimSuffix(upluginFile.Name, ".uplugin")
|
||||||
|
|
||||||
hash, err := getFileHash(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get file hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var iconFile *zip.File
|
var iconFile *zip.File
|
||||||
for _, file := range reader.File {
|
for _, file := range reader.File {
|
||||||
if file.Name == IconFilename {
|
if file.Name == IconFilename {
|
||||||
|
@ -160,11 +169,11 @@ func readCacheFile(filename string) (*File, error) {
|
||||||
icon = &iconData
|
icon = &iconData
|
||||||
}
|
}
|
||||||
|
|
||||||
return &File{
|
return &Mod{
|
||||||
ModReference: modReference,
|
ModReference: modReference,
|
||||||
Hash: hash,
|
Name: uplugin.FriendlyName,
|
||||||
Size: size,
|
Author: uplugin.CreatedBy,
|
||||||
Icon: icon,
|
Icon: icon,
|
||||||
Plugin: uplugin,
|
LatestVersion: uplugin.SemVersion,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
1
cli/cache/uplugin.go
vendored
1
cli/cache/uplugin.go
vendored
|
@ -5,6 +5,7 @@ type UPlugin struct {
|
||||||
FriendlyName string `json:"FriendlyName"`
|
FriendlyName string `json:"FriendlyName"`
|
||||||
Description string `json:"Description"`
|
Description string `json:"Description"`
|
||||||
CreatedBy string `json:"CreatedBy"`
|
CreatedBy string `json:"CreatedBy"`
|
||||||
|
GameVersion string `json:"GameVersion"`
|
||||||
Plugins []Plugins `json:"Plugins"`
|
Plugins []Plugins `json:"Plugins"`
|
||||||
}
|
}
|
||||||
type Plugins struct {
|
type Plugins struct {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cli/cache"
|
"github.com/satisfactorymodding/ficsit-cli/cli/cache"
|
||||||
|
"github.com/satisfactorymodding/ficsit-cli/cli/localregistry"
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cli/provider"
|
"github.com/satisfactorymodding/ficsit-cli/cli/provider"
|
||||||
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||||
)
|
)
|
||||||
|
@ -45,11 +46,16 @@ func InitCLI(apiOnly bool) (*GlobalContext, error) {
|
||||||
return nil, fmt.Errorf("failed to initialize installations: %w", err)
|
return nil, fmt.Errorf("failed to initialize installations: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = cache.LoadCache()
|
_, err = cache.LoadCacheMods()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to load cache: %w", err)
|
return nil, fmt.Errorf("failed to load cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = localregistry.Init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to initialize local registry: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
globalContext = &GlobalContext{
|
globalContext = &GlobalContext{
|
||||||
Installations: installations,
|
Installations: installations,
|
||||||
Profiles: profiles,
|
Profiles: profiles,
|
||||||
|
|
188
cli/disk/ftp.go
188
cli/disk/ftp.go
|
@ -3,12 +3,15 @@ package disk
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
"path"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -91,7 +94,86 @@ func testFTP(u *url.URL, options ...ftp.DialOption) (*ftp.ServerConn, bool, erro
|
||||||
return c, false, nil
|
return c, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ftpDisk) Exists(path string) (bool, error) {
|
func (l *ftpDisk) existsWithLock(res *puddle.Resource[*ftp.ServerConn], p string) (bool, error) {
|
||||||
|
slog.Debug("checking if file exists", slog.String("path", clean(p)), slog.String("schema", "ftp"))
|
||||||
|
|
||||||
|
var protocolError *textproto.Error
|
||||||
|
|
||||||
|
_, err := res.Value().GetEntry(clean(p))
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.As(err, &protocolError) {
|
||||||
|
switch protocolError.Code {
|
||||||
|
case ftp.StatusFileUnavailable:
|
||||||
|
return false, nil
|
||||||
|
case ftp.StatusNotImplemented:
|
||||||
|
// GetEntry uses MLST, which might not be supported by the server.
|
||||||
|
// Even though in this case the error is not coming from the server,
|
||||||
|
// the ftp library still returns it as a protocol error.
|
||||||
|
default:
|
||||||
|
// We won't handle any other kind of error, such as
|
||||||
|
// * temporary errors (4xx) - should be retried after a while, so we won't deal with the delay
|
||||||
|
// * connection errors (x2x) - can't really do anything about them
|
||||||
|
// * authentication errors (x3x) - can't do anything about them
|
||||||
|
return false, fmt.Errorf("failed to get path info: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is a non-protocol error, so we can't be sure what it means.
|
||||||
|
return false, fmt.Errorf("failed to get path info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case MLST is not supported, we can try to LIST the target path.
|
||||||
|
// We can be sure that List() will actually execute LIST and not MLSD,
|
||||||
|
// since MLST was not supported in the previous step.
|
||||||
|
entries, err := res.Value().List(clean(p))
|
||||||
|
if err == nil {
|
||||||
|
if len(entries) > 0 {
|
||||||
|
// Some server implementations return an empty list for a nonexistent path,
|
||||||
|
// so we cannot be sure that no error means a directory exists unless it also contains some items.
|
||||||
|
// For files, when they exist, they will be listed as a single entry.
|
||||||
|
// TODO: so far the servers (just one) this was happening on also listed . and .. for valid dirs, because it was using `LIST -a`. Is that behaviour consistent that we can rely on it?
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if errors.As(err, &protocolError) {
|
||||||
|
if protocolError.Code == ftp.StatusFileUnavailable {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We won't handle any other kind of error, see above.
|
||||||
|
return false, fmt.Errorf("failed to list path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got here, either the path is an empty directory,
|
||||||
|
// or it does not exist and the server is a weird implementation.
|
||||||
|
|
||||||
|
// List the parent directory to determine if the path exists
|
||||||
|
dir, err := l.readDirLock(res, path.Dir(clean(p)))
|
||||||
|
if err == nil {
|
||||||
|
found := false
|
||||||
|
for _, entry := range dir {
|
||||||
|
if entry.Name() == path.Base(clean(p)) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.As(err, &protocolError) {
|
||||||
|
if protocolError.Code == ftp.StatusFileUnavailable {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We won't handle any other kind of error, see above.
|
||||||
|
return false, fmt.Errorf("failed to list parent path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ftpDisk) Exists(p string) (bool, error) {
|
||||||
res, err := l.acquire()
|
res, err := l.acquire()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -99,49 +181,7 @@ func (l *ftpDisk) Exists(path string) (bool, error) {
|
||||||
|
|
||||||
defer res.Release()
|
defer res.Release()
|
||||||
|
|
||||||
slog.Debug("checking if file exists", slog.String("path", clean(path)), slog.String("schema", "ftp"))
|
return l.existsWithLock(res, p)
|
||||||
|
|
||||||
split := strings.Split(clean(path)[1:], "/")
|
|
||||||
for _, s := range split[:len(split)-1] {
|
|
||||||
dir, err := l.readDirLock(res, "")
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDir, _ := res.Value().CurrentDir()
|
|
||||||
|
|
||||||
foundDir := false
|
|
||||||
for _, entry := range dir {
|
|
||||||
if entry.IsDir() && entry.Name() == s {
|
|
||||||
foundDir = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !foundDir {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("entering directory", slog.String("dir", s), slog.String("cwd", currentDir), slog.String("schema", "ftp"))
|
|
||||||
if err := res.Value().ChangeDir(s); err != nil {
|
|
||||||
return false, fmt.Errorf("failed to enter directory: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dir, err := l.readDirLock(res, "")
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("failed listing directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, entry := range dir {
|
|
||||||
if entry.Name() == clean(filepath.Base(path)) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ftpDisk) Read(path string) ([]byte, error) {
|
func (l *ftpDisk) Read(path string) ([]byte, error) {
|
||||||
|
@ -203,7 +243,7 @@ func (l *ftpDisk) Remove(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ftpDisk) MkDir(path string) error {
|
func (l *ftpDisk) MkDir(p string) error {
|
||||||
res, err := l.acquire()
|
res, err := l.acquire()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -211,34 +251,47 @@ func (l *ftpDisk) MkDir(path string) error {
|
||||||
|
|
||||||
defer res.Release()
|
defer res.Release()
|
||||||
|
|
||||||
split := strings.Split(clean(path)[1:], "/")
|
lastExistingDir := clean(p)
|
||||||
for _, s := range split {
|
for lastExistingDir != "/" && lastExistingDir != "." {
|
||||||
dir, err := l.readDirLock(res, "")
|
foundDir, err := l.existsWithLock(res, lastExistingDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDir, _ := res.Value().CurrentDir()
|
if foundDir {
|
||||||
|
break
|
||||||
foundDir := false
|
|
||||||
for _, entry := range dir {
|
|
||||||
if entry.IsDir() && entry.Name() == s {
|
|
||||||
foundDir = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !foundDir {
|
lastExistingDir = path.Dir(lastExistingDir)
|
||||||
slog.Debug("making directory", slog.String("dir", s), slog.String("cwd", currentDir), slog.String("schema", "ftp"))
|
}
|
||||||
if err := res.Value().MakeDir(s); err != nil {
|
|
||||||
return fmt.Errorf("failed to make directory: %w", err)
|
remainingDirs := clean(p)
|
||||||
}
|
|
||||||
|
if lastExistingDir != "/" && lastExistingDir != "." {
|
||||||
|
remainingDirs = strings.TrimPrefix(remainingDirs, lastExistingDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remainingDirs) == 0 {
|
||||||
|
// Already exists
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := res.Value().ChangeDir(lastExistingDir); err != nil {
|
||||||
|
return fmt.Errorf("failed to enter directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
split := strings.Split(clean(remainingDirs)[1:], "/")
|
||||||
|
for _, s := range split {
|
||||||
|
slog.Debug("making directory", slog.String("dir", s), slog.String("cwd", lastExistingDir), slog.String("schema", "ftp"))
|
||||||
|
if err := res.Value().MakeDir(s); err != nil {
|
||||||
|
return fmt.Errorf("failed to make directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Debug("entering directory", slog.String("dir", s), slog.String("cwd", currentDir), slog.String("schema", "ftp"))
|
slog.Debug("entering directory", slog.String("dir", s), slog.String("cwd", lastExistingDir), slog.String("schema", "ftp"))
|
||||||
if err := res.Value().ChangeDir(s); err != nil {
|
if err := res.Value().ChangeDir(s); err != nil {
|
||||||
return fmt.Errorf("failed to enter directory: %w", err)
|
return fmt.Errorf("failed to enter directory: %w", err)
|
||||||
}
|
}
|
||||||
|
lastExistingDir = path.Join(lastExistingDir, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -252,7 +305,14 @@ func (l *ftpDisk) ReadDir(path string) ([]Entry, error) {
|
||||||
|
|
||||||
defer res.Release()
|
defer res.Release()
|
||||||
|
|
||||||
return l.readDirLock(res, path)
|
entries, err := l.readDirLock(res, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries = slices.DeleteFunc(entries, func(i Entry) bool {
|
||||||
|
return i.Name() == "." || i.Name() == ".."
|
||||||
|
})
|
||||||
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ftpDisk) readDirLock(res *puddle.Resource[*ftp.ServerConn], path string) ([]Entry, error) {
|
func (l *ftpDisk) readDirLock(res *puddle.Resource[*ftp.ServerConn], path string) ([]Entry, error) {
|
||||||
|
|
|
@ -183,6 +183,8 @@ func (i *Installations) DeleteInstallation(installPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rootExecutables = []string{"FactoryGame.exe", "FactoryServer.sh", "FactoryServer.exe", "FactoryGameSteam.exe", "FactoryGameEGS.exe"}
|
||||||
|
|
||||||
func (i *Installation) Validate(ctx *GlobalContext) error {
|
func (i *Installation) Validate(ctx *GlobalContext) error {
|
||||||
found := false
|
found := false
|
||||||
for _, p := range ctx.Profiles.Profiles {
|
for _, p := range ctx.Profiles.Profiles {
|
||||||
|
@ -203,31 +205,25 @@ func (i *Installation) Validate(ctx *GlobalContext) error {
|
||||||
|
|
||||||
foundExecutable := false
|
foundExecutable := false
|
||||||
|
|
||||||
exists, err := d.Exists(filepath.Join(i.BasePath(), "FactoryGame.exe"))
|
var checkWait errgroup.Group
|
||||||
if !exists {
|
|
||||||
if err != nil {
|
for _, executable := range rootExecutables {
|
||||||
return fmt.Errorf("failed reading FactoryGame.exe: %w", err)
|
e := executable
|
||||||
}
|
checkWait.Go(func() error {
|
||||||
} else {
|
exists, err := d.Exists(filepath.Join(i.BasePath(), e))
|
||||||
foundExecutable = true
|
if !exists {
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed reading %s: %w", e, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foundExecutable = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exists, err = d.Exists(filepath.Join(i.BasePath(), "FactoryServer.sh"))
|
if err = checkWait.Wait(); err != nil {
|
||||||
if !exists {
|
return err //nolint:wrapcheck
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed reading FactoryServer.sh: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundExecutable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
exists, err = d.Exists(filepath.Join(i.BasePath(), "FactoryServer.exe"))
|
|
||||||
if !exists {
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed reading FactoryServer.exe: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundExecutable = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !foundExecutable {
|
if !foundExecutable {
|
||||||
|
@ -243,26 +239,18 @@ var (
|
||||||
matchAllCap = regexp.MustCompile(`([a-z\d])([A-Z])`)
|
matchAllCap = regexp.MustCompile(`([a-z\d])([A-Z])`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i *Installation) LockFilePath(ctx *GlobalContext) (string, error) {
|
func (i *Installation) lockFilePath(ctx *GlobalContext, platform *Platform) string {
|
||||||
platform, err := i.GetPlatform(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
lockFileName := ctx.Profiles.Profiles[i.Profile].Name
|
lockFileName := ctx.Profiles.Profiles[i.Profile].Name
|
||||||
lockFileName = matchFirstCap.ReplaceAllString(lockFileName, "${1}_${2}")
|
lockFileName = matchFirstCap.ReplaceAllString(lockFileName, "${1}_${2}")
|
||||||
lockFileName = matchAllCap.ReplaceAllString(lockFileName, "${1}_${2}")
|
lockFileName = matchAllCap.ReplaceAllString(lockFileName, "${1}_${2}")
|
||||||
lockFileName = lockFileCleaner.ReplaceAllLiteralString(lockFileName, "-")
|
lockFileName = lockFileCleaner.ReplaceAllLiteralString(lockFileName, "-")
|
||||||
lockFileName = strings.ToLower(lockFileName) + "-lock.json"
|
lockFileName = strings.ToLower(lockFileName) + "-lock.json"
|
||||||
|
|
||||||
return filepath.Join(i.BasePath(), platform.LockfilePath, lockFileName), nil
|
return filepath.Join(i.BasePath(), platform.LockfilePath, lockFileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Installation) LockFile(ctx *GlobalContext) (*resolver.LockFile, error) {
|
func (i *Installation) lockfile(ctx *GlobalContext, platform *Platform) (*resolver.LockFile, error) {
|
||||||
lockfilePath, err := i.LockFilePath(ctx)
|
lockfilePath := i.lockFilePath(ctx, platform)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err := i.GetDisk()
|
d, err := i.GetDisk()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -291,11 +279,8 @@ func (i *Installation) LockFile(ctx *GlobalContext) (*resolver.LockFile, error)
|
||||||
return lockFile, nil
|
return lockFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Installation) WriteLockFile(ctx *GlobalContext, lockfile *resolver.LockFile) error {
|
func (i *Installation) writeLockFile(ctx *GlobalContext, platform *Platform, lockfile *resolver.LockFile) error {
|
||||||
lockfilePath, err := i.LockFilePath(ctx)
|
lockfilePath := i.lockFilePath(ctx, platform)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err := i.GetDisk()
|
d, err := i.GetDisk()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -341,15 +326,15 @@ func (i *Installation) Wipe() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Installation) ResolveProfile(ctx *GlobalContext) (*resolver.LockFile, error) {
|
func (i *Installation) resolveProfile(ctx *GlobalContext, platform *Platform) (*resolver.LockFile, error) {
|
||||||
lockFile, err := i.LockFile(ctx)
|
lockFile, err := i.lockfile(ctx, platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
depResolver := resolver.NewDependencyResolver(ctx.Provider, viper.GetString("api-base"))
|
depResolver := resolver.NewDependencyResolver(ctx.Provider)
|
||||||
|
|
||||||
gameVersion, err := i.GetGameVersion(ctx)
|
gameVersion, err := i.getGameVersion(platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to detect game version: %w", err)
|
return nil, fmt.Errorf("failed to detect game version: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -359,13 +344,37 @@ func (i *Installation) ResolveProfile(ctx *GlobalContext) (*resolver.LockFile, e
|
||||||
return nil, fmt.Errorf("could not resolve mods: %w", err)
|
return nil, fmt.Errorf("could not resolve mods: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := i.WriteLockFile(ctx, lockfile); err != nil {
|
if err := i.writeLockFile(ctx, platform, lockfile); err != nil {
|
||||||
return nil, fmt.Errorf("failed to write lockfile: %w", err)
|
return nil, fmt.Errorf("failed to write lockfile: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return lockfile, nil
|
return lockfile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Installation) GetGameVersion(ctx *GlobalContext) (int, error) {
|
||||||
|
platform, err := i.GetPlatform(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return i.getGameVersion(platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Installation) LockFile(ctx *GlobalContext) (*resolver.LockFile, error) {
|
||||||
|
platform, err := i.GetPlatform(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return i.lockfile(ctx, platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Installation) WriteLockFile(ctx *GlobalContext, lockfile *resolver.LockFile) error {
|
||||||
|
platform, err := i.GetPlatform(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return i.writeLockFile(ctx, platform, lockfile)
|
||||||
|
}
|
||||||
|
|
||||||
type InstallUpdateType string
|
type InstallUpdateType string
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -387,10 +396,6 @@ type InstallUpdateItem struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate) error {
|
func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate) error {
|
||||||
if err := i.Validate(ctx); err != nil {
|
|
||||||
return fmt.Errorf("failed to validate installation: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
platform, err := i.GetPlatform(ctx)
|
platform, err := i.GetPlatform(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to detect platform: %w", err)
|
return fmt.Errorf("failed to detect platform: %w", err)
|
||||||
|
@ -400,7 +405,7 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate)
|
||||||
|
|
||||||
if !i.Vanilla {
|
if !i.Vanilla {
|
||||||
var err error
|
var err error
|
||||||
lockfile, err = i.ResolveProfile(ctx)
|
lockfile, err = i.resolveProfile(ctx, platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to resolve lockfile: %w", err)
|
return fmt.Errorf("failed to resolve lockfile: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -421,25 +426,41 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate)
|
||||||
return fmt.Errorf("failed to read mods directory: %w", err)
|
return fmt.Errorf("failed to read mods directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var deleteWait errgroup.Group
|
||||||
for _, entry := range dir {
|
for _, entry := range dir {
|
||||||
if entry.IsDir() {
|
if entry.IsDir() {
|
||||||
if _, ok := lockfile.Mods[entry.Name()]; !ok {
|
modName := entry.Name()
|
||||||
modDir := filepath.Join(modsDirectory, entry.Name())
|
mod, hasMod := lockfile.Mods[modName]
|
||||||
exists, err := d.Exists(filepath.Join(modDir, ".smm"))
|
if hasMod {
|
||||||
if err != nil {
|
_, hasTarget := mod.Targets[platform.TargetName]
|
||||||
return err
|
hasMod = hasTarget
|
||||||
}
|
}
|
||||||
|
if !hasMod {
|
||||||
if exists {
|
modName := entry.Name()
|
||||||
slog.Info("deleting mod", slog.String("mod_reference", entry.Name()))
|
modDir := filepath.Join(modsDirectory, modName)
|
||||||
if err := d.Remove(modDir); err != nil {
|
deleteWait.Go(func() error {
|
||||||
return fmt.Errorf("failed to delete mod directory: %w", err)
|
exists, err := d.Exists(filepath.Join(modDir, ".smm"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if exists {
|
||||||
|
slog.Info("deleting mod", slog.String("mod_reference", modName))
|
||||||
|
if err := d.Remove(modDir); err != nil {
|
||||||
|
return fmt.Errorf("failed to delete mod directory: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := deleteWait.Wait(); err != nil {
|
||||||
|
return fmt.Errorf("failed to remove old mods: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
slog.Info("starting installation", slog.Int("concurrency", viper.GetInt("concurrent-downloads")), slog.String("path", i.Path))
|
slog.Info("starting installation", slog.Int("concurrency", viper.GetInt("concurrent-downloads")), slog.String("path", i.Path))
|
||||||
|
|
||||||
errg := errgroup.Group{}
|
errg := errgroup.Group{}
|
||||||
|
@ -478,7 +499,10 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate)
|
||||||
|
|
||||||
target, ok := version.Targets[platform.TargetName]
|
target, ok := version.Targets[platform.TargetName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("%s@%s not available for %s", modReference, version.Version, platform.TargetName)
|
// The resolver validates that the resulting lockfile mods can be installed on the sides where they are required
|
||||||
|
// so if the mod is missing this target, it means it is not required on this target
|
||||||
|
slog.Info("skipping mod not available for target", slog.String("mod_reference", modReference), slog.String("version", version.Version), slog.String("target", platform.TargetName))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only install if a link is provided, otherwise assume mod is already installed
|
// Only install if a link is provided, otherwise assume mod is already installed
|
||||||
|
@ -523,18 +547,19 @@ func (i *Installation) Install(ctx *GlobalContext, updates chan<- InstallUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Installation) UpdateMods(ctx *GlobalContext, mods []string) error {
|
func (i *Installation) UpdateMods(ctx *GlobalContext, mods []string) error {
|
||||||
if err := i.Validate(ctx); err != nil {
|
platform, err := i.GetPlatform(ctx)
|
||||||
return fmt.Errorf("failed to validate installation: %w", err)
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lockFile, err := i.LockFile(ctx)
|
lockFile, err := i.lockfile(ctx, platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read lock file: %w", err)
|
return fmt.Errorf("failed to read lock file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver := resolver.NewDependencyResolver(ctx.Provider, viper.GetString("api-base"))
|
resolver := resolver.NewDependencyResolver(ctx.Provider)
|
||||||
|
|
||||||
gameVersion, err := i.GetGameVersion(ctx)
|
gameVersion, err := i.getGameVersion(platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to detect game version: %w", err)
|
return fmt.Errorf("failed to detect game version: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -553,7 +578,7 @@ func (i *Installation) UpdateMods(ctx *GlobalContext, mods []string) error {
|
||||||
return fmt.Errorf("failed to resolve dependencies: %w", err)
|
return fmt.Errorf("failed to resolve dependencies: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := i.WriteLockFile(ctx, newLockFile); err != nil {
|
if err := i.writeLockFile(ctx, platform, newLockFile); err != nil {
|
||||||
return fmt.Errorf("failed to write lock file: %w", err)
|
return fmt.Errorf("failed to write lock file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,30 +692,13 @@ type gameVersionFile struct {
|
||||||
IsPromotedBuild int `json:"IsPromotedBuild"`
|
IsPromotedBuild int `json:"IsPromotedBuild"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Installation) GetGameVersion(ctx *GlobalContext) (int, error) {
|
func (i *Installation) getGameVersion(platform *Platform) (int, error) {
|
||||||
if err := i.Validate(ctx); err != nil {
|
|
||||||
return 0, fmt.Errorf("failed to validate installation: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
platform, err := i.GetPlatform(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err := i.GetDisk()
|
d, err := i.GetDisk()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fullPath := filepath.Join(i.BasePath(), platform.VersionPath)
|
fullPath := filepath.Join(i.BasePath(), platform.VersionPath)
|
||||||
exists, err := d.Exists(fullPath)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return 0, errors.New("game version file does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := d.Read(fullPath)
|
file, err := d.Read(fullPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
106
cli/localregistry/migrations.go
Normal file
106
cli/localregistry/migrations.go
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
package localregistry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var migrations = []func(*sql.Tx) error{
|
||||||
|
initialSetup,
|
||||||
|
addRequiredOnRemote,
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyMigrations(db *sql.DB) error {
|
||||||
|
// user_version will store the 1-indexed migration that was last applied
|
||||||
|
var nextMigration int
|
||||||
|
err := db.QueryRow("PRAGMA user_version;").Scan(&nextMigration)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get user_version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := nextMigration; i < len(migrations); i++ {
|
||||||
|
err := applyMigration(db, i)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to apply migration %d: %w", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyMigration(db *sql.DB, migrationIndex int) error {
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to start transaction: %w", err)
|
||||||
|
}
|
||||||
|
// Will noop if the transaction was committed
|
||||||
|
defer tx.Rollback() //nolint:errcheck
|
||||||
|
|
||||||
|
err = migrations[migrationIndex](tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.Exec(fmt.Sprintf("PRAGMA user_version = %d;", migrationIndex+1))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to set user_version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to commit transaction: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initialSetup(tx *sql.Tx) error {
|
||||||
|
// Create the initial user
|
||||||
|
_, err := tx.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS "versions" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"mod_reference" TEXT NOT NULL,
|
||||||
|
"version" TEXT NOT NULL,
|
||||||
|
"game_version" TEXT NOT NULL
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "mod_reference" ON "versions" ("mod_reference");
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "mod_version" ON "versions" ("mod_reference", "version");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "dependencies" (
|
||||||
|
"version_id" TEXT NOT NULL,
|
||||||
|
"dependency" TEXT NOT NULL,
|
||||||
|
"condition" TEXT NOT NULL,
|
||||||
|
"optional" INT NOT NULL,
|
||||||
|
FOREIGN KEY ("version_id") REFERENCES "versions" ("id") ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY ("version_id", "dependency")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "targets" (
|
||||||
|
"version_id" TEXT NOT NULL,
|
||||||
|
"target_name" TEXT NOT NULL,
|
||||||
|
"link" TEXT NOT NULL,
|
||||||
|
"hash" TEXT NOT NULL,
|
||||||
|
"size" INT NOT NULL,
|
||||||
|
FOREIGN KEY ("version_id") REFERENCES "versions" ("id") ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY ("version_id", "target_name")
|
||||||
|
);
|
||||||
|
`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create initial tables: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRequiredOnRemote(tx *sql.Tx) error {
|
||||||
|
_, err := tx.Exec(`
|
||||||
|
ALTER TABLE "versions" ADD COLUMN "required_on_remote" INT NOT NULL DEFAULT 1;
|
||||||
|
`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to add required_on_remote column: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
175
cli/localregistry/registry.go
Normal file
175
cli/localregistry/registry.go
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
package localregistry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||||
|
|
||||||
|
// sqlite driver
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
var db *sql.DB
|
||||||
|
var dbWriteMutex = sync.Mutex{}
|
||||||
|
|
||||||
|
func Init() error {
|
||||||
|
dbPath := filepath.Join(viper.GetString("cache-dir"), "registry.db")
|
||||||
|
|
||||||
|
err := os.MkdirAll(filepath.Dir(dbPath), 0o777)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create local registry directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err = sql.Open("sqlite", dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set pragmas here because modernc.org/sqlite does not support them in the connection string
|
||||||
|
_, err = db.Exec(`
|
||||||
|
PRAGMA journal_mode = WAL;
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
|
PRAGMA busy_timeout = 5000;
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to setup connection pragmas: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = applyMigrations(db)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to apply migrations: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Add(modReference string, modVersions []ficsit.ModVersion) {
|
||||||
|
dbWriteMutex.Lock()
|
||||||
|
defer dbWriteMutex.Unlock()
|
||||||
|
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to start local registry transaction", slog.Any("err", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// In case the transaction is not committed, revert and release
|
||||||
|
defer tx.Rollback() //nolint:errcheck
|
||||||
|
|
||||||
|
_, err = tx.Exec("DELETE FROM versions WHERE mod_reference = ?", modReference)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to delete existing mod versions from local registry", slog.Any("err", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, modVersion := range modVersions {
|
||||||
|
l := slog.With(slog.String("mod", modReference), slog.String("version", modVersion.Version))
|
||||||
|
|
||||||
|
_, err = tx.Exec("INSERT INTO versions (id, mod_reference, version, game_version, required_on_remote) VALUES (?, ?, ?, ?, ?)", modVersion.ID, modReference, modVersion.Version, modVersion.GameVersion, modVersion.RequiredOnRemote)
|
||||||
|
if err != nil {
|
||||||
|
l.Error("failed to insert mod version into local registry", slog.Any("err", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, dependency := range modVersion.Dependencies {
|
||||||
|
_, err = tx.Exec("INSERT INTO dependencies (version_id, dependency, condition, optional) VALUES (?, ?, ?, ?)", modVersion.ID, dependency.ModID, dependency.Condition, dependency.Optional)
|
||||||
|
if err != nil {
|
||||||
|
l.Error("failed to insert dependency into local registry", slog.String("dependency", dependency.ModID), slog.Any("err", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, target := range modVersion.Targets {
|
||||||
|
_, err = tx.Exec("INSERT INTO targets (version_id, target_name, link, hash, size) VALUES (?, ?, ?, ?, ?)", modVersion.ID, target.TargetName, target.Link, target.Hash, target.Size)
|
||||||
|
if err != nil {
|
||||||
|
l.Error("failed to insert target into local registry", slog.Any("target", target.TargetName), slog.Any("err", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to commit local registry transaction", slog.Any("err", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetModVersions(modReference string) ([]ficsit.ModVersion, error) {
|
||||||
|
versionRows, err := db.Query("SELECT id, version, game_version, required_on_remote FROM versions WHERE mod_reference = ?", modReference)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch mod versions from local registry: %w", err)
|
||||||
|
}
|
||||||
|
defer versionRows.Close()
|
||||||
|
|
||||||
|
var versions []ficsit.ModVersion
|
||||||
|
for versionRows.Next() {
|
||||||
|
var version ficsit.ModVersion
|
||||||
|
err = versionRows.Scan(&version.ID, &version.Version, &version.GameVersion, &version.RequiredOnRemote)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to scan version row: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies, err := getVersionDependencies(version.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
version.Dependencies = dependencies
|
||||||
|
|
||||||
|
targets, err := getVersionTargets(version.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
version.Targets = targets
|
||||||
|
|
||||||
|
versions = append(versions, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersionDependencies(versionID string) ([]ficsit.Dependency, error) {
|
||||||
|
var dependencies []ficsit.Dependency
|
||||||
|
dependencyRows, err := db.Query("SELECT dependency, condition, optional FROM dependencies WHERE version_id = ?", versionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch dependencies from local registry: %w", err)
|
||||||
|
}
|
||||||
|
defer dependencyRows.Close()
|
||||||
|
|
||||||
|
for dependencyRows.Next() {
|
||||||
|
var dependency ficsit.Dependency
|
||||||
|
err = dependencyRows.Scan(&dependency.ModID, &dependency.Condition, &dependency.Optional)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to scan dependency row: %w", err)
|
||||||
|
}
|
||||||
|
dependencies = append(dependencies, dependency)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersionTargets(versionID string) ([]ficsit.Target, error) {
|
||||||
|
var targets []ficsit.Target
|
||||||
|
targetRows, err := db.Query("SELECT target_name, link, hash, size FROM targets WHERE version_id = ?", versionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch targets from local registry: %w", err)
|
||||||
|
}
|
||||||
|
defer targetRows.Close()
|
||||||
|
|
||||||
|
for targetRows.Next() {
|
||||||
|
var target ficsit.Target
|
||||||
|
err = targetRows.Scan(&target.TargetName, &target.Link, &target.Hash, &target.Size)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to scan target row: %w", err)
|
||||||
|
}
|
||||||
|
targets = append(targets, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
return targets, nil
|
||||||
|
}
|
|
@ -35,4 +35,15 @@ var platforms = []Platform{
|
||||||
LockfilePath: filepath.Join("FactoryGame", "Mods"),
|
LockfilePath: filepath.Join("FactoryGame", "Mods"),
|
||||||
TargetName: "WindowsServer",
|
TargetName: "WindowsServer",
|
||||||
},
|
},
|
||||||
|
// 1.0 stuff
|
||||||
|
{
|
||||||
|
VersionPath: filepath.Join("Engine", "Binaries", "Win64", "FactoryGameSteam-Win64-Shipping.version"),
|
||||||
|
LockfilePath: filepath.Join("FactoryGame", "Mods"),
|
||||||
|
TargetName: "Windows",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VersionPath: filepath.Join("Engine", "Binaries", "Win64", "FactoryGameEGS-Win64-Shipping.version"),
|
||||||
|
LockfilePath: filepath.Join("FactoryGame", "Mods"),
|
||||||
|
TargetName: "Windows",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -299,7 +298,7 @@ func (p *Profile) Resolve(resolver resolver.DependencyResolver, lockFile *resolv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resultLockfile, err := resolver.ResolveModDependencies(context.TODO(), toResolve, lockFile, gameVersion, p.RequiredTargets)
|
resultLockfile, err := resolver.ResolveModDependencies(toResolve, lockFile, gameVersion, p.RequiredTargets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed resolving profile dependencies: %w", err)
|
return nil, fmt.Errorf("failed resolving profile dependencies: %w", err)
|
||||||
}
|
}
|
||||||
|
|
41
cli/provider/converter.go
Normal file
41
cli/provider/converter.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertFicsitVersionsToResolver(versions []ficsit.ModVersion) []resolver.ModVersion {
|
||||||
|
modVersions := make([]resolver.ModVersion, len(versions))
|
||||||
|
for i, modVersion := range versions {
|
||||||
|
dependencies := make([]resolver.Dependency, len(modVersion.Dependencies))
|
||||||
|
for j, dependency := range modVersion.Dependencies {
|
||||||
|
dependencies[j] = resolver.Dependency{
|
||||||
|
ModID: dependency.ModID,
|
||||||
|
Condition: dependency.Condition,
|
||||||
|
Optional: dependency.Optional,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
targets := make([]resolver.Target, len(modVersion.Targets))
|
||||||
|
for j, target := range modVersion.Targets {
|
||||||
|
targets[j] = resolver.Target{
|
||||||
|
TargetName: resolver.TargetName(target.TargetName),
|
||||||
|
Link: viper.GetString("api-base") + target.Link,
|
||||||
|
Hash: target.Hash,
|
||||||
|
Size: target.Size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modVersions[i] = resolver.ModVersion{
|
||||||
|
Version: modVersion.Version,
|
||||||
|
GameVersion: modVersion.GameVersion,
|
||||||
|
Dependencies: dependencies,
|
||||||
|
Targets: targets,
|
||||||
|
RequiredOnRemote: modVersion.RequiredOnRemote,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modVersions
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/Khan/genqlient/graphql"
|
"github.com/Khan/genqlient/graphql"
|
||||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||||
|
|
||||||
|
"github.com/satisfactorymodding/ficsit-cli/cli/localregistry"
|
||||||
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,38 +29,6 @@ func (p FicsitProvider) GetMod(context context.Context, modReference string) (*f
|
||||||
return ficsit.GetMod(context, p.client, modReference)
|
return ficsit.GetMod(context, p.client, modReference)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p FicsitProvider) ModVersions(context context.Context, modReference string, filter ficsit.VersionFilter) (*ficsit.ModVersionsResponse, error) {
|
|
||||||
return ficsit.ModVersions(context, p.client, modReference, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p FicsitProvider) SMLVersions(context context.Context) ([]resolver.SMLVersion, error) {
|
|
||||||
response, err := ficsit.SMLVersions(context, p.client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
smlVersions := make([]resolver.SMLVersion, len(response.SmlVersions.Sml_versions))
|
|
||||||
for i, version := range response.GetSmlVersions().Sml_versions {
|
|
||||||
targets := make([]resolver.SMLVersionTarget, len(version.Targets))
|
|
||||||
|
|
||||||
for j, target := range version.Targets {
|
|
||||||
targets[j] = resolver.SMLVersionTarget{
|
|
||||||
TargetName: resolver.TargetName(target.TargetName),
|
|
||||||
Link: target.Link,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
smlVersions[i] = resolver.SMLVersion{
|
|
||||||
ID: version.Id,
|
|
||||||
Version: version.Version,
|
|
||||||
SatisfactoryVersion: version.Satisfactory_version,
|
|
||||||
Targets: targets,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return smlVersions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p FicsitProvider) ModVersionsWithDependencies(_ context.Context, modID string) ([]resolver.ModVersion, error) {
|
func (p FicsitProvider) ModVersionsWithDependencies(_ context.Context, modID string) ([]resolver.ModVersion, error) {
|
||||||
response, err := ficsit.GetAllModVersions(modID)
|
response, err := ficsit.GetAllModVersions(modID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -70,36 +39,9 @@ func (p FicsitProvider) ModVersionsWithDependencies(_ context.Context, modID str
|
||||||
return nil, errors.New(response.Error.Message)
|
return nil, errors.New(response.Error.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
modVersions := make([]resolver.ModVersion, len(response.Data))
|
localregistry.Add(modID, response.Data)
|
||||||
for i, modVersion := range response.Data {
|
|
||||||
dependencies := make([]resolver.Dependency, len(modVersion.Dependencies))
|
|
||||||
for j, dependency := range modVersion.Dependencies {
|
|
||||||
dependencies[j] = resolver.Dependency{
|
|
||||||
ModID: dependency.ModID,
|
|
||||||
Condition: dependency.Condition,
|
|
||||||
Optional: dependency.Optional,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
targets := make([]resolver.Target, len(modVersion.Targets))
|
return convertFicsitVersionsToResolver(response.Data), nil
|
||||||
for j, target := range modVersion.Targets {
|
|
||||||
targets[j] = resolver.Target{
|
|
||||||
VersionID: target.VersionID,
|
|
||||||
TargetName: resolver.TargetName(target.TargetName),
|
|
||||||
Hash: target.Hash,
|
|
||||||
Size: target.Size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modVersions[i] = resolver.ModVersion{
|
|
||||||
ID: modVersion.ID,
|
|
||||||
Version: modVersion.Version,
|
|
||||||
Dependencies: dependencies,
|
|
||||||
Targets: targets,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return modVersions, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p FicsitProvider) GetModName(context context.Context, modReference string) (*resolver.ModName, error) {
|
func (p FicsitProvider) GetModName(context context.Context, modReference string) (*resolver.ModName, error) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -10,6 +9,7 @@ import (
|
||||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||||
|
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cli/cache"
|
"github.com/satisfactorymodding/ficsit-cli/cli/cache"
|
||||||
|
"github.com/satisfactorymodding/ficsit-cli/cli/localregistry"
|
||||||
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,18 +20,14 @@ func NewLocalProvider() LocalProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p LocalProvider) Mods(_ context.Context, filter ficsit.ModFilter) (*ficsit.ModsResponse, error) {
|
func (p LocalProvider) Mods(_ context.Context, filter ficsit.ModFilter) (*ficsit.ModsResponse, error) {
|
||||||
cachedMods, err := cache.GetCache()
|
cachedMods, err := cache.GetCacheMods()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get cache: %w", err)
|
return nil, fmt.Errorf("failed to get cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mods := make([]ficsit.ModsModsGetModsModsMod, 0)
|
mods := make([]ficsit.ModsModsGetModsModsMod, 0)
|
||||||
|
|
||||||
cachedMods.Range(func(modReference string, files []cache.File) bool {
|
cachedMods.Range(func(modReference string, cachedMod cache.Mod) bool {
|
||||||
if modReference == "SML" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(filter.References) > 0 {
|
if len(filter.References) > 0 {
|
||||||
skip := true
|
skip := true
|
||||||
|
|
||||||
|
@ -49,7 +45,7 @@ func (p LocalProvider) Mods(_ context.Context, filter ficsit.ModFilter) (*ficsit
|
||||||
|
|
||||||
mods = append(mods, ficsit.ModsModsGetModsModsMod{
|
mods = append(mods, ficsit.ModsModsGetModsModsMod{
|
||||||
Id: modReference,
|
Id: modReference,
|
||||||
Name: files[0].Plugin.FriendlyName,
|
Name: cachedMod.Name,
|
||||||
Mod_reference: modReference,
|
Mod_reference: modReference,
|
||||||
Last_version_date: time.Now(),
|
Last_version_date: time.Now(),
|
||||||
Created_at: time.Now(),
|
Created_at: time.Now(),
|
||||||
|
@ -92,18 +88,14 @@ func (p LocalProvider) Mods(_ context.Context, filter ficsit.ModFilter) (*ficsit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p LocalProvider) GetMod(_ context.Context, modReference string) (*ficsit.GetModResponse, error) {
|
func (p LocalProvider) GetMod(_ context.Context, modReference string) (*ficsit.GetModResponse, error) {
|
||||||
cachedModFiles, err := cache.GetCacheMod(modReference)
|
cachedMod, err := cache.GetCacheMod(modReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get cache: %w", err)
|
return nil, fmt.Errorf("failed to get cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cachedModFiles) == 0 {
|
|
||||||
return nil, errors.New("mod not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
authors := make([]ficsit.GetModModAuthorsUserMod, 0)
|
authors := make([]ficsit.GetModModAuthorsUserMod, 0)
|
||||||
|
|
||||||
for _, author := range strings.Split(cachedModFiles[0].Plugin.CreatedBy, ",") {
|
for _, author := range strings.Split(cachedMod.Author, ",") {
|
||||||
authors = append(authors, ficsit.GetModModAuthorsUserMod{
|
authors = append(authors, ficsit.GetModModAuthorsUserMod{
|
||||||
Role: "Unknown",
|
Role: "Unknown",
|
||||||
User: ficsit.GetModModAuthorsUserModUser{
|
User: ficsit.GetModModAuthorsUserModUser{
|
||||||
|
@ -115,7 +107,7 @@ func (p LocalProvider) GetMod(_ context.Context, modReference string) (*ficsit.G
|
||||||
return &ficsit.GetModResponse{
|
return &ficsit.GetModResponse{
|
||||||
Mod: ficsit.GetModMod{
|
Mod: ficsit.GetModMod{
|
||||||
Id: modReference,
|
Id: modReference,
|
||||||
Name: cachedModFiles[0].Plugin.FriendlyName,
|
Name: cachedMod.Name,
|
||||||
Mod_reference: modReference,
|
Mod_reference: modReference,
|
||||||
Created_at: time.Now(),
|
Created_at: time.Now(),
|
||||||
Views: 0,
|
Views: 0,
|
||||||
|
@ -127,56 +119,26 @@ func (p LocalProvider) GetMod(_ context.Context, modReference string) (*ficsit.G
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p LocalProvider) SMLVersions(_ context.Context) ([]resolver.SMLVersion, error) {
|
|
||||||
cachedSMLFiles, err := cache.GetCacheMod("SML")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get cache: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
smlVersions := make([]resolver.SMLVersion, 0)
|
|
||||||
|
|
||||||
for _, smlFile := range cachedSMLFiles {
|
|
||||||
smlVersions = append(smlVersions, resolver.SMLVersion{
|
|
||||||
ID: "SML:" + smlFile.Plugin.SemVersion,
|
|
||||||
Version: smlFile.Plugin.SemVersion,
|
|
||||||
SatisfactoryVersion: 0, // TODO: where can this be obtained from?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return smlVersions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p LocalProvider) ModVersionsWithDependencies(_ context.Context, modID string) ([]resolver.ModVersion, error) {
|
func (p LocalProvider) ModVersionsWithDependencies(_ context.Context, modID string) ([]resolver.ModVersion, error) {
|
||||||
cachedModFiles, err := cache.GetCacheMod(modID)
|
modVersions, err := localregistry.GetModVersions(modID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get cache: %w", err)
|
return nil, fmt.Errorf("failed to get local mod versions: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
versions := make([]resolver.ModVersion, 0)
|
// TODO: only list as available the versions that have at least one target cached
|
||||||
|
|
||||||
for _, modFile := range cachedModFiles {
|
return convertFicsitVersionsToResolver(modVersions), nil
|
||||||
versions = append(versions, resolver.ModVersion{
|
|
||||||
ID: modID + ":" + modFile.Plugin.SemVersion,
|
|
||||||
Version: modFile.Plugin.SemVersion,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return versions, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p LocalProvider) GetModName(_ context.Context, modReference string) (*resolver.ModName, error) {
|
func (p LocalProvider) GetModName(_ context.Context, modReference string) (*resolver.ModName, error) {
|
||||||
cachedModFiles, err := cache.GetCacheMod(modReference)
|
cachedMod, err := cache.GetCacheMod(modReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get cache: %w", err)
|
return nil, fmt.Errorf("failed to get cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cachedModFiles) == 0 {
|
|
||||||
return nil, errors.New("mod not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &resolver.ModName{
|
return &resolver.ModName{
|
||||||
ID: modReference,
|
ID: modReference,
|
||||||
Name: cachedModFiles[0].Plugin.FriendlyName,
|
Name: cachedMod.Name,
|
||||||
ModReference: modReference,
|
ModReference: modReference,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,13 +36,6 @@ func (p MixedProvider) GetMod(context context.Context, modReference string) (*fi
|
||||||
return p.onlineProvider.GetMod(context, modReference)
|
return p.onlineProvider.GetMod(context, modReference)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p MixedProvider) SMLVersions(context context.Context) ([]resolver.SMLVersion, error) {
|
|
||||||
if p.Offline {
|
|
||||||
return p.offlineProvider.SMLVersions(context) // nolint
|
|
||||||
}
|
|
||||||
return p.onlineProvider.SMLVersions(context) // nolint
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p MixedProvider) ModVersionsWithDependencies(context context.Context, modID string) ([]resolver.ModVersion, error) {
|
func (p MixedProvider) ModVersionsWithDependencies(context context.Context, modID string) ([]resolver.ModVersion, error) {
|
||||||
if p.Offline {
|
if p.Offline {
|
||||||
return p.offlineProvider.ModVersionsWithDependencies(context, modID) // nolint
|
return p.offlineProvider.ModVersionsWithDependencies(context, modID) // nolint
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/MarvinJWendt/testza"
|
"github.com/MarvinJWendt/testza"
|
||||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cfg"
|
"github.com/satisfactorymodding/ficsit-cli/cfg"
|
||||||
)
|
)
|
||||||
|
@ -34,6 +34,108 @@ func installWatcher() chan<- InstallUpdate {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClientOnlyMod(t *testing.T) {
|
||||||
|
ctx, err := InitCLI(false)
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
err = ctx.Wipe()
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
ctx.Provider = MockProvider{}
|
||||||
|
|
||||||
|
profileName := "ClientOnlyModTest"
|
||||||
|
profile, err := ctx.Profiles.AddProfile(profileName)
|
||||||
|
profile.RequiredTargets = []resolver.TargetName{resolver.TargetNameWindows, resolver.TargetNameWindowsServer, resolver.TargetNameLinuxServer}
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
testza.AssertNoError(t, profile.AddMod("ClientOnlyMod", "<=0.0.1"))
|
||||||
|
|
||||||
|
serverLocation := os.Getenv("SF_DEDICATED_SERVER")
|
||||||
|
if serverLocation != "" {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
testza.AssertNoError(t, os.RemoveAll(filepath.Join(serverLocation, "FactoryGame", "Mods")))
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
installation, err := ctx.Installations.AddInstallation(ctx, serverLocation, profileName)
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
testza.AssertNotNil(t, installation)
|
||||||
|
|
||||||
|
err = installation.Install(ctx, installWatcher())
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerOnlyMod(t *testing.T) {
|
||||||
|
ctx, err := InitCLI(false)
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
err = ctx.Wipe()
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
ctx.Provider = MockProvider{}
|
||||||
|
|
||||||
|
profileName := "ServerOnlyModTest"
|
||||||
|
profile, err := ctx.Profiles.AddProfile(profileName)
|
||||||
|
profile.RequiredTargets = []resolver.TargetName{resolver.TargetNameWindows, resolver.TargetNameWindowsServer, resolver.TargetNameLinuxServer}
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
testza.AssertNoError(t, profile.AddMod("ServerOnlyMod", "<=0.0.1"))
|
||||||
|
|
||||||
|
serverLocation := os.Getenv("SF_DEDICATED_SERVER")
|
||||||
|
if serverLocation != "" {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
testza.AssertNoError(t, os.RemoveAll(filepath.Join(serverLocation, "FactoryGame", "Mods")))
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
installation, err := ctx.Installations.AddInstallation(ctx, serverLocation, profileName)
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
testza.AssertNotNil(t, installation)
|
||||||
|
|
||||||
|
err = installation.Install(ctx, installWatcher())
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveWhenNotSupported(t *testing.T) {
|
||||||
|
ctx, err := InitCLI(false)
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
err = ctx.Wipe()
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
ctx.Provider = MockProvider{}
|
||||||
|
|
||||||
|
profileName := "ClientOnlyModTest"
|
||||||
|
profile, err := ctx.Profiles.AddProfile(profileName)
|
||||||
|
profile.RequiredTargets = []resolver.TargetName{resolver.TargetNameWindows, resolver.TargetNameWindowsServer, resolver.TargetNameLinuxServer}
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
testza.AssertNoError(t, profile.AddMod("LaterClientOnlyMod", "0.0.1"))
|
||||||
|
|
||||||
|
serverLocation := os.Getenv("SF_DEDICATED_SERVER")
|
||||||
|
if serverLocation != "" {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
testza.AssertNoError(t, os.RemoveAll(filepath.Join(serverLocation, "FactoryGame", "Mods")))
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
installation, err := ctx.Installations.AddInstallation(ctx, serverLocation, profileName)
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
testza.AssertNotNil(t, installation)
|
||||||
|
|
||||||
|
err = installation.Install(ctx, installWatcher())
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
_, err = os.Stat(filepath.Join(serverLocation, "FactoryGame", "Mods", "LaterClientOnlyMod"))
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
testza.AssertNoError(t, profile.AddMod("LaterClientOnlyMod", "0.0.2"))
|
||||||
|
|
||||||
|
err = installation.Install(ctx, installWatcher())
|
||||||
|
testza.AssertNoError(t, err)
|
||||||
|
|
||||||
|
_, err = os.Stat(filepath.Join(serverLocation, "FactoryGame", "Mods", "LaterClientOnlyMod"))
|
||||||
|
testza.AssertNotNil(t, err)
|
||||||
|
testza.AssertErrorIs(t, err, os.ErrNotExist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUpdateMods(t *testing.T) {
|
func TestUpdateMods(t *testing.T) {
|
||||||
ctx, err := InitCLI(false)
|
ctx, err := InitCLI(false)
|
||||||
testza.AssertNoError(t, err)
|
testza.AssertNoError(t, err)
|
||||||
|
@ -43,9 +145,9 @@ func TestUpdateMods(t *testing.T) {
|
||||||
|
|
||||||
ctx.Provider = MockProvider{}
|
ctx.Provider = MockProvider{}
|
||||||
|
|
||||||
depResolver := resolver.NewDependencyResolver(ctx.Provider, viper.GetString("api-base"))
|
depResolver := resolver.NewDependencyResolver(ctx.Provider)
|
||||||
|
|
||||||
oldLockfile, err := depResolver.ResolveModDependencies(context.Background(), map[string]string{
|
oldLockfile, err := depResolver.ResolveModDependencies(map[string]string{
|
||||||
"FicsitRemoteMonitoring": "0.9.8",
|
"FicsitRemoteMonitoring": "0.9.8",
|
||||||
}, nil, math.MaxInt, nil)
|
}, nil, math.MaxInt, nil)
|
||||||
|
|
||||||
|
|
|
@ -70,19 +70,28 @@ func (m MockProvider) Mods(_ context.Context, f ficsit.ModFilter) (*ficsit.ModsR
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var windowsTarget = resolver.Target{
|
||||||
|
TargetName: "Windows",
|
||||||
|
Link: "https://api.ficsit.dev/v1/version/7QcfNdo5QAAyoC/Windows/download",
|
||||||
|
Hash: "698df20278b3de3ec30405569a22050c6721cc682389312258c14948bd8f38ae",
|
||||||
|
}
|
||||||
|
|
||||||
|
var windowsServerTarget = resolver.Target{
|
||||||
|
TargetName: "WindowsServer",
|
||||||
|
Link: "https://api.ficsit.dev/v1/version/7QcfNdo5QAAyoC/WindowsServer/download",
|
||||||
|
Hash: "7be01ed372e0cf3287a04f5cb32bb9dcf6f6e7a5b7603b7e43669ec4c6c1457f",
|
||||||
|
}
|
||||||
|
|
||||||
|
var linuxServerTarget = resolver.Target{
|
||||||
|
TargetName: "LinuxServer",
|
||||||
|
Link: "https://api.ficsit.dev/v1/version/7QcfNdo5QAAyoC/LinuxServer/download",
|
||||||
|
Hash: "bdbd4cb1b472a5316621939ae2fe270fd0e3c0f0a75666a9cbe74ff1313c3663",
|
||||||
|
}
|
||||||
|
|
||||||
var commonTargets = []resolver.Target{
|
var commonTargets = []resolver.Target{
|
||||||
{
|
windowsTarget,
|
||||||
TargetName: "Windows",
|
windowsServerTarget,
|
||||||
Hash: "698df20278b3de3ec30405569a22050c6721cc682389312258c14948bd8f38ae",
|
linuxServerTarget,
|
||||||
},
|
|
||||||
{
|
|
||||||
TargetName: "WindowsServer",
|
|
||||||
Hash: "7be01ed372e0cf3287a04f5cb32bb9dcf6f6e7a5b7603b7e43669ec4c6c1457f",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
TargetName: "LinuxServer",
|
|
||||||
Hash: "bdbd4cb1b472a5316621939ae2fe270fd0e3c0f0a75666a9cbe74ff1313c3663",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID string) ([]resolver.ModVersion, error) {
|
func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID string) ([]resolver.ModVersion, error) {
|
||||||
|
@ -90,7 +99,6 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
||||||
case "AreaActions":
|
case "AreaActions":
|
||||||
return []resolver.ModVersion{
|
return []resolver.ModVersion{
|
||||||
{
|
{
|
||||||
ID: "7QcfNdo5QAAyoC",
|
|
||||||
Version: "1.6.7",
|
Version: "1.6.7",
|
||||||
Dependencies: []resolver.Dependency{
|
Dependencies: []resolver.Dependency{
|
||||||
{
|
{
|
||||||
|
@ -99,10 +107,10 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
Targets: commonTargets,
|
||||||
|
RequiredOnRemote: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "7QcfNdo5QAAyoC",
|
|
||||||
Version: "1.6.6",
|
Version: "1.6.6",
|
||||||
Dependencies: []resolver.Dependency{
|
Dependencies: []resolver.Dependency{
|
||||||
{
|
{
|
||||||
|
@ -111,10 +119,10 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
Targets: commonTargets,
|
||||||
|
RequiredOnRemote: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "7QcfNdo5QAAyoC",
|
|
||||||
Version: "1.6.5",
|
Version: "1.6.5",
|
||||||
Dependencies: []resolver.Dependency{
|
Dependencies: []resolver.Dependency{
|
||||||
{
|
{
|
||||||
|
@ -123,13 +131,13 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
Targets: commonTargets,
|
||||||
|
RequiredOnRemote: true,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case "FicsitRemoteMonitoring":
|
case "FicsitRemoteMonitoring":
|
||||||
return []resolver.ModVersion{
|
return []resolver.ModVersion{
|
||||||
{
|
{
|
||||||
ID: "7QcfNdo5QAAyoC",
|
|
||||||
Version: "0.10.1",
|
Version: "0.10.1",
|
||||||
Dependencies: []resolver.Dependency{
|
Dependencies: []resolver.Dependency{
|
||||||
{
|
{
|
||||||
|
@ -138,10 +146,10 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
Targets: commonTargets,
|
||||||
|
RequiredOnRemote: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "7QcfNdo5QAAyoC",
|
|
||||||
Version: "0.10.0",
|
Version: "0.10.0",
|
||||||
Dependencies: []resolver.Dependency{
|
Dependencies: []resolver.Dependency{
|
||||||
{
|
{
|
||||||
|
@ -150,10 +158,10 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
Targets: commonTargets,
|
||||||
|
RequiredOnRemote: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "7QcfNdo5QAAyoC",
|
|
||||||
Version: "0.9.8",
|
Version: "0.9.8",
|
||||||
Dependencies: []resolver.Dependency{
|
Dependencies: []resolver.Dependency{
|
||||||
{
|
{
|
||||||
|
@ -162,7 +170,72 @@ func (m MockProvider) ModVersionsWithDependencies(ctx context.Context, modID str
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: commonTargets,
|
Targets: commonTargets,
|
||||||
|
RequiredOnRemote: true,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
case "ClientOnlyMod":
|
||||||
|
return []resolver.ModVersion{
|
||||||
|
{
|
||||||
|
Version: "0.0.1",
|
||||||
|
Dependencies: []resolver.Dependency{
|
||||||
|
{
|
||||||
|
ModID: "SML",
|
||||||
|
Condition: "^3.6.0",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Targets: []resolver.Target{
|
||||||
|
windowsTarget,
|
||||||
|
},
|
||||||
|
RequiredOnRemote: false,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
case "ServerOnlyMod":
|
||||||
|
return []resolver.ModVersion{
|
||||||
|
{
|
||||||
|
Version: "0.0.1",
|
||||||
|
Dependencies: []resolver.Dependency{
|
||||||
|
{
|
||||||
|
ModID: "SML",
|
||||||
|
Condition: "^3.6.0",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Targets: []resolver.Target{
|
||||||
|
windowsServerTarget,
|
||||||
|
linuxServerTarget,
|
||||||
|
},
|
||||||
|
RequiredOnRemote: false,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
case "LaterClientOnlyMod":
|
||||||
|
return []resolver.ModVersion{
|
||||||
|
{
|
||||||
|
Version: "0.0.1",
|
||||||
|
Dependencies: []resolver.Dependency{
|
||||||
|
{
|
||||||
|
ModID: "SML",
|
||||||
|
Condition: "^3.6.0",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Targets: commonTargets,
|
||||||
|
RequiredOnRemote: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "0.0.2",
|
||||||
|
Dependencies: []resolver.Dependency{
|
||||||
|
{
|
||||||
|
ModID: "SML",
|
||||||
|
Condition: "^3.6.0",
|
||||||
|
Optional: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Targets: []resolver.Target{
|
||||||
|
windowsTarget,
|
||||||
|
},
|
||||||
|
RequiredOnRemote: false,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,8 @@ func init() {
|
||||||
baseLocalDir = os.Getenv("APPDATA")
|
baseLocalDir = os.Getenv("APPDATA")
|
||||||
case "linux":
|
case "linux":
|
||||||
baseLocalDir = filepath.Join(os.Getenv("HOME"), ".local", "share")
|
baseLocalDir = filepath.Join(os.Getenv("HOME"), ".local", "share")
|
||||||
|
case "darwin":
|
||||||
|
baseLocalDir = filepath.Join(os.Getenv("HOME"), "Library", "Application Support")
|
||||||
default:
|
default:
|
||||||
panic("unsupported platform: " + runtime.GOOS)
|
panic("unsupported platform: " + runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
45
cspell.json
45
cspell.json
|
@ -1,26 +1,25 @@
|
||||||
// https://cspell.org/configuration/
|
// https://cspell.org/configuration/
|
||||||
{
|
{
|
||||||
// Version of the setting file. Always 0.2
|
// Version of the setting file. Always 0.2
|
||||||
"version": "0.2",
|
"version": "0.2",
|
||||||
// language - current active spelling language
|
// language - current active spelling language
|
||||||
"language": "en",
|
"language": "en",
|
||||||
// words - list of words to be always considered correct
|
// words - list of words to be always considered correct
|
||||||
"words": [
|
"words": [
|
||||||
"ficsit",
|
"armv",
|
||||||
"gofumpt",
|
"ficsit",
|
||||||
"Goland",
|
"gofumpt",
|
||||||
"golangci",
|
"Goland",
|
||||||
"goquery",
|
"golangci",
|
||||||
"graphqurl",
|
"goquery",
|
||||||
"mvdan",
|
"graphqurl",
|
||||||
"pgdn",
|
"mvdan",
|
||||||
"pgup",
|
"pgdn",
|
||||||
"wordwrap"
|
"pgup",
|
||||||
],
|
"wordwrap"
|
||||||
// flagWords - list of words to be always considered incorrect
|
],
|
||||||
// This is useful for offensive words and common spelling errors.
|
// flagWords - list of words to be always considered incorrect
|
||||||
// cSpell:disable (don't complain about the words we listed here)
|
// This is useful for offensive words and common spelling errors.
|
||||||
"flagWords": [
|
// cSpell:disable (don't complain about the words we listed here)
|
||||||
"hte"
|
"flagWords": ["hte"]
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ cli mod manager for satisfactory
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit apply](ficsit_apply.md) - Apply profiles to all installations
|
- [ficsit apply](ficsit_apply.md) - Apply profiles to all installations
|
||||||
* [ficsit cli](ficsit_cli.md) - Start interactive CLI (default)
|
- [ficsit cli](ficsit_cli.md) - Start interactive CLI (default)
|
||||||
* [ficsit installation](ficsit_installation.md) - Manage installations
|
- [ficsit installation](ficsit_installation.md) - Manage installations
|
||||||
* [ficsit profile](ficsit_profile.md) - Manage profiles
|
- [ficsit profile](ficsit_profile.md) - Manage profiles
|
||||||
* [ficsit search](ficsit_search.md) - Search mods
|
- [ficsit search](ficsit_search.md) - Search mods
|
||||||
* [ficsit smr](ficsit_smr.md) - Manage mods on SMR
|
- [ficsit smr](ficsit_smr.md) - Manage mods on SMR
|
||||||
* [ficsit version](ficsit_version.md) - Print current version information
|
- [ficsit version](ficsit_version.md) - Print current version information
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit apply [installation] ... [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit](ficsit.md) - cli mod manager for satisfactory
|
- [ficsit](ficsit.md) - cli mod manager for satisfactory
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit cli [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit](ficsit.md) - cli mod manager for satisfactory
|
- [ficsit](ficsit.md) - cli mod manager for satisfactory
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -29,11 +29,11 @@ Manage installations
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit](ficsit.md) - cli mod manager for satisfactory
|
- [ficsit](ficsit.md) - cli mod manager for satisfactory
|
||||||
* [ficsit installation add](ficsit_installation_add.md) - Add an installation
|
- [ficsit installation add](ficsit_installation_add.md) - Add an installation
|
||||||
* [ficsit installation ls](ficsit_installation_ls.md) - List all installations
|
- [ficsit installation ls](ficsit_installation_ls.md) - List all installations
|
||||||
* [ficsit installation remove](ficsit_installation_remove.md) - Remove an installation
|
- [ficsit installation remove](ficsit_installation_remove.md) - Remove an installation
|
||||||
* [ficsit installation set-profile](ficsit_installation_set-profile.md) - Change the profile of an installation
|
- [ficsit installation set-profile](ficsit_installation_set-profile.md) - Change the profile of an installation
|
||||||
* [ficsit installation set-vanilla](ficsit_installation_set-vanilla.md) - Set the installation to vanilla mode or not
|
- [ficsit installation set-vanilla](ficsit_installation_set-vanilla.md) - Set the installation to vanilla mode or not
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit installation add <path> [profile] [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit installation](ficsit_installation.md) - Manage installations
|
- [ficsit installation](ficsit_installation.md) - Manage installations
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit installation ls [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit installation](ficsit_installation.md) - Manage installations
|
- [ficsit installation](ficsit_installation.md) - Manage installations
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit installation remove <path> [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit installation](ficsit_installation.md) - Manage installations
|
- [ficsit installation](ficsit_installation.md) - Manage installations
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit installation set-profile <path> <profile> [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit installation](ficsit_installation.md) - Manage installations
|
- [ficsit installation](ficsit_installation.md) - Manage installations
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -34,6 +34,6 @@ ficsit installation set-vanilla <path> [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit installation](ficsit_installation.md) - Manage installations
|
- [ficsit installation](ficsit_installation.md) - Manage installations
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -29,11 +29,11 @@ Manage profiles
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit](ficsit.md) - cli mod manager for satisfactory
|
- [ficsit](ficsit.md) - cli mod manager for satisfactory
|
||||||
* [ficsit profile delete](ficsit_profile_delete.md) - Delete a profile
|
- [ficsit profile delete](ficsit_profile_delete.md) - Delete a profile
|
||||||
* [ficsit profile ls](ficsit_profile_ls.md) - List all profiles
|
- [ficsit profile ls](ficsit_profile_ls.md) - List all profiles
|
||||||
* [ficsit profile mods](ficsit_profile_mods.md) - List all mods in a profile
|
- [ficsit profile mods](ficsit_profile_mods.md) - List all mods in a profile
|
||||||
* [ficsit profile new](ficsit_profile_new.md) - Create a new profile
|
- [ficsit profile new](ficsit_profile_new.md) - Create a new profile
|
||||||
* [ficsit profile rename](ficsit_profile_rename.md) - Rename a profile
|
- [ficsit profile rename](ficsit_profile_rename.md) - Rename a profile
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit profile delete <name> [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit profile](ficsit_profile.md) - Manage profiles
|
- [ficsit profile](ficsit_profile.md) - Manage profiles
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit profile ls [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit profile](ficsit_profile.md) - Manage profiles
|
- [ficsit profile](ficsit_profile.md) - Manage profiles
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit profile mods <profile> [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit profile](ficsit_profile.md) - Manage profiles
|
- [ficsit profile](ficsit_profile.md) - Manage profiles
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit profile new <name> [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit profile](ficsit_profile.md) - Manage profiles
|
- [ficsit profile](ficsit_profile.md) - Manage profiles
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit profile rename <old> <name> [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit profile](ficsit_profile.md) - Manage profiles
|
- [ficsit profile](ficsit_profile.md) - Manage profiles
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -38,6 +38,6 @@ ficsit search [query] [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit](ficsit.md) - cli mod manager for satisfactory
|
- [ficsit](ficsit.md) - cli mod manager for satisfactory
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -29,7 +29,7 @@ Manage mods on SMR
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit](ficsit.md) - cli mod manager for satisfactory
|
- [ficsit](ficsit.md) - cli mod manager for satisfactory
|
||||||
* [ficsit smr upload](ficsit_smr_upload.md) - Upload a new mod version
|
- [ficsit smr upload](ficsit_smr_upload.md) - Upload a new mod version
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -35,6 +35,6 @@ ficsit smr upload [flags] <mod-id> <file> <changelog...>
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit smr](ficsit_smr.md) - Manage mods on SMR
|
- [ficsit smr](ficsit_smr.md) - Manage mods on SMR
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
|
@ -33,6 +33,6 @@ ficsit version [flags]
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [ficsit](ficsit.md) - cli mod manager for satisfactory
|
- [ficsit](ficsit.md) - cli mod manager for satisfactory
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 7-Dec-2023
|
###### Auto generated by spf13/cobra on 7-Dec-2023
|
||||||
|
|
BIN
ficsit-cli
Executable file
BIN
ficsit-cli
Executable file
Binary file not shown.
|
@ -17,15 +17,6 @@ func init() {
|
||||||
client = InitAPI()
|
client = InitAPI()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModVersions(t *testing.T) {
|
|
||||||
response, err := ModVersions(context.Background(), client, "SmartFoundations", VersionFilter{})
|
|
||||||
testza.AssertNoError(t, err)
|
|
||||||
testza.AssertNotNil(t, response)
|
|
||||||
testza.AssertNotNil(t, response.Mod)
|
|
||||||
testza.AssertNotNil(t, response.Mod.Versions)
|
|
||||||
testza.AssertNotZero(t, len(response.Mod.Versions))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMods(t *testing.T) {
|
func TestMods(t *testing.T) {
|
||||||
response, err := Mods(context.Background(), client, ModFilter{})
|
response, err := Mods(context.Background(), client, ModFilter{})
|
||||||
testza.AssertNoError(t, err)
|
testza.AssertNoError(t, err)
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# @genqlient(omitempty: true)
|
|
||||||
query ModVersions (
|
|
||||||
$modId: String!,
|
|
||||||
$filter: VersionFilter
|
|
||||||
) {
|
|
||||||
mod: getModByIdOrReference(modIdOrReference: $modId) {
|
|
||||||
id
|
|
||||||
versions (filter: $filter) {
|
|
||||||
id
|
|
||||||
version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
# @genqlient(omitempty: true)
|
|
||||||
query ModVersionsWithDependencies (
|
|
||||||
$modId: String!,
|
|
||||||
) {
|
|
||||||
mod: getModByIdOrReference(modIdOrReference: $modId) {
|
|
||||||
id
|
|
||||||
versions (filter: { limit: 100 }) {
|
|
||||||
id
|
|
||||||
version
|
|
||||||
link
|
|
||||||
hash
|
|
||||||
dependencies {
|
|
||||||
mod_id
|
|
||||||
condition
|
|
||||||
optional
|
|
||||||
}
|
|
||||||
targets {
|
|
||||||
targetName
|
|
||||||
link
|
|
||||||
hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
# @genqlient(omitempty: true)
|
|
||||||
query SMLVersions {
|
|
||||||
smlVersions: getSMLVersions(filter: {limit: 100}) {
|
|
||||||
count
|
|
||||||
sml_versions {
|
|
||||||
id
|
|
||||||
version
|
|
||||||
satisfactory_version
|
|
||||||
targets {
|
|
||||||
targetName
|
|
||||||
link
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
391
ficsit/types.go
391
ficsit/types.go
|
@ -355,136 +355,6 @@ func (v *ModFilter) GetHidden() bool { return v.Hidden }
|
||||||
// GetTagIDs returns ModFilter.TagIDs, and is useful for accessing the field via an interface.
|
// GetTagIDs returns ModFilter.TagIDs, and is useful for accessing the field via an interface.
|
||||||
func (v *ModFilter) GetTagIDs() []string { return v.TagIDs }
|
func (v *ModFilter) GetTagIDs() []string { return v.TagIDs }
|
||||||
|
|
||||||
// ModVersionsMod includes the requested fields of the GraphQL type Mod.
|
|
||||||
type ModVersionsMod struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Versions []ModVersionsModVersionsVersion `json:"versions"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetId returns ModVersionsMod.Id, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsMod) GetId() string { return v.Id }
|
|
||||||
|
|
||||||
// GetVersions returns ModVersionsMod.Versions, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsMod) GetVersions() []ModVersionsModVersionsVersion { return v.Versions }
|
|
||||||
|
|
||||||
// ModVersionsModVersionsVersion includes the requested fields of the GraphQL type Version.
|
|
||||||
type ModVersionsModVersionsVersion struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetId returns ModVersionsModVersionsVersion.Id, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsModVersionsVersion) GetId() string { return v.Id }
|
|
||||||
|
|
||||||
// GetVersion returns ModVersionsModVersionsVersion.Version, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsModVersionsVersion) GetVersion() string { return v.Version }
|
|
||||||
|
|
||||||
// ModVersionsResponse is returned by ModVersions on success.
|
|
||||||
type ModVersionsResponse struct {
|
|
||||||
Mod ModVersionsMod `json:"mod"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMod returns ModVersionsResponse.Mod, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsResponse) GetMod() ModVersionsMod { return v.Mod }
|
|
||||||
|
|
||||||
// ModVersionsWithDependenciesMod includes the requested fields of the GraphQL type Mod.
|
|
||||||
type ModVersionsWithDependenciesMod struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Versions []ModVersionsWithDependenciesModVersionsVersion `json:"versions"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetId returns ModVersionsWithDependenciesMod.Id, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesMod) GetId() string { return v.Id }
|
|
||||||
|
|
||||||
// GetVersions returns ModVersionsWithDependenciesMod.Versions, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesMod) GetVersions() []ModVersionsWithDependenciesModVersionsVersion {
|
|
||||||
return v.Versions
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModVersionsWithDependenciesModVersionsVersion includes the requested fields of the GraphQL type Version.
|
|
||||||
type ModVersionsWithDependenciesModVersionsVersion struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
Link string `json:"link"`
|
|
||||||
Hash string `json:"hash"`
|
|
||||||
Dependencies []ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency `json:"dependencies"`
|
|
||||||
Targets []ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget `json:"targets"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetId returns ModVersionsWithDependenciesModVersionsVersion.Id, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersion) GetId() string { return v.Id }
|
|
||||||
|
|
||||||
// GetVersion returns ModVersionsWithDependenciesModVersionsVersion.Version, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersion) GetVersion() string { return v.Version }
|
|
||||||
|
|
||||||
// GetLink returns ModVersionsWithDependenciesModVersionsVersion.Link, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersion) GetLink() string { return v.Link }
|
|
||||||
|
|
||||||
// GetHash returns ModVersionsWithDependenciesModVersionsVersion.Hash, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersion) GetHash() string { return v.Hash }
|
|
||||||
|
|
||||||
// GetDependencies returns ModVersionsWithDependenciesModVersionsVersion.Dependencies, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersion) GetDependencies() []ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency {
|
|
||||||
return v.Dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTargets returns ModVersionsWithDependenciesModVersionsVersion.Targets, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersion) GetTargets() []ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget {
|
|
||||||
return v.Targets
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency includes the requested fields of the GraphQL type VersionDependency.
|
|
||||||
type ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency struct {
|
|
||||||
Mod_id string `json:"mod_id"`
|
|
||||||
Condition string `json:"condition"`
|
|
||||||
Optional bool `json:"optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMod_id returns ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency.Mod_id, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency) GetMod_id() string {
|
|
||||||
return v.Mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCondition returns ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency.Condition, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency) GetCondition() string {
|
|
||||||
return v.Condition
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOptional returns ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency.Optional, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersionDependenciesVersionDependency) GetOptional() bool {
|
|
||||||
return v.Optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget includes the requested fields of the GraphQL type VersionTarget.
|
|
||||||
type ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget struct {
|
|
||||||
TargetName TargetName `json:"targetName"`
|
|
||||||
Link string `json:"link"`
|
|
||||||
Hash string `json:"hash"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTargetName returns ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget.TargetName, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget) GetTargetName() TargetName {
|
|
||||||
return v.TargetName
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLink returns ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget.Link, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget) GetLink() string {
|
|
||||||
return v.Link
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHash returns ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget.Hash, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesModVersionsVersionTargetsVersionTarget) GetHash() string {
|
|
||||||
return v.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModVersionsWithDependenciesResponse is returned by ModVersionsWithDependencies on success.
|
|
||||||
type ModVersionsWithDependenciesResponse struct {
|
|
||||||
Mod ModVersionsWithDependenciesMod `json:"mod"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMod returns ModVersionsWithDependenciesResponse.Mod, and is useful for accessing the field via an interface.
|
|
||||||
func (v *ModVersionsWithDependenciesResponse) GetMod() ModVersionsWithDependenciesMod { return v.Mod }
|
|
||||||
|
|
||||||
// ModsModsGetMods includes the requested fields of the GraphQL type GetMods.
|
// ModsModsGetMods includes the requested fields of the GraphQL type GetMods.
|
||||||
type ModsModsGetMods struct {
|
type ModsModsGetMods struct {
|
||||||
Count int `json:"count"`
|
Count int `json:"count"`
|
||||||
|
@ -675,115 +545,6 @@ const (
|
||||||
OrderDesc Order = "desc"
|
OrderDesc Order = "desc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SMLVersionsResponse is returned by SMLVersions on success.
|
|
||||||
type SMLVersionsResponse struct {
|
|
||||||
SmlVersions SMLVersionsSmlVersionsGetSMLVersions `json:"smlVersions"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSmlVersions returns SMLVersionsResponse.SmlVersions, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsResponse) GetSmlVersions() SMLVersionsSmlVersionsGetSMLVersions {
|
|
||||||
return v.SmlVersions
|
|
||||||
}
|
|
||||||
|
|
||||||
// SMLVersionsSmlVersionsGetSMLVersions includes the requested fields of the GraphQL type GetSMLVersions.
|
|
||||||
type SMLVersionsSmlVersionsGetSMLVersions struct {
|
|
||||||
Count int `json:"count"`
|
|
||||||
Sml_versions []SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion `json:"sml_versions"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCount returns SMLVersionsSmlVersionsGetSMLVersions.Count, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersions) GetCount() int { return v.Count }
|
|
||||||
|
|
||||||
// GetSml_versions returns SMLVersionsSmlVersionsGetSMLVersions.Sml_versions, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersions) GetSml_versions() []SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion {
|
|
||||||
return v.Sml_versions
|
|
||||||
}
|
|
||||||
|
|
||||||
// SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion includes the requested fields of the GraphQL type SMLVersion.
|
|
||||||
type SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
Satisfactory_version int `json:"satisfactory_version"`
|
|
||||||
Targets []SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget `json:"targets"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetId returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion.Id, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion) GetId() string { return v.Id }
|
|
||||||
|
|
||||||
// GetVersion returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion.Version, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion) GetVersion() string {
|
|
||||||
return v.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSatisfactory_version returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion.Satisfactory_version, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion) GetSatisfactory_version() int {
|
|
||||||
return v.Satisfactory_version
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTargets returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion.Targets, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersion) GetTargets() []SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget {
|
|
||||||
return v.Targets
|
|
||||||
}
|
|
||||||
|
|
||||||
// SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget includes the requested fields of the GraphQL type SMLVersionTarget.
|
|
||||||
type SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget struct {
|
|
||||||
TargetName TargetName `json:"targetName"`
|
|
||||||
Link string `json:"link"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTargetName returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget.TargetName, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget) GetTargetName() TargetName {
|
|
||||||
return v.TargetName
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLink returns SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget.Link, and is useful for accessing the field via an interface.
|
|
||||||
func (v *SMLVersionsSmlVersionsGetSMLVersionsSml_versionsSMLVersionTargetsSMLVersionTarget) GetLink() string {
|
|
||||||
return v.Link
|
|
||||||
}
|
|
||||||
|
|
||||||
type TargetName string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TargetNameWindows TargetName = "Windows"
|
|
||||||
TargetNameWindowsserver TargetName = "WindowsServer"
|
|
||||||
TargetNameLinuxserver TargetName = "LinuxServer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type VersionFields string
|
|
||||||
|
|
||||||
const (
|
|
||||||
VersionFieldsCreatedAt VersionFields = "created_at"
|
|
||||||
VersionFieldsUpdatedAt VersionFields = "updated_at"
|
|
||||||
VersionFieldsDownloads VersionFields = "downloads"
|
|
||||||
)
|
|
||||||
|
|
||||||
type VersionFilter struct {
|
|
||||||
Limit int `json:"limit,omitempty"`
|
|
||||||
Offset int `json:"offset,omitempty"`
|
|
||||||
Order_by VersionFields `json:"order_by,omitempty"`
|
|
||||||
Order Order `json:"order,omitempty"`
|
|
||||||
Search string `json:"search,omitempty"`
|
|
||||||
Ids []string `json:"ids,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLimit returns VersionFilter.Limit, and is useful for accessing the field via an interface.
|
|
||||||
func (v *VersionFilter) GetLimit() int { return v.Limit }
|
|
||||||
|
|
||||||
// GetOffset returns VersionFilter.Offset, and is useful for accessing the field via an interface.
|
|
||||||
func (v *VersionFilter) GetOffset() int { return v.Offset }
|
|
||||||
|
|
||||||
// GetOrder_by returns VersionFilter.Order_by, and is useful for accessing the field via an interface.
|
|
||||||
func (v *VersionFilter) GetOrder_by() VersionFields { return v.Order_by }
|
|
||||||
|
|
||||||
// GetOrder returns VersionFilter.Order, and is useful for accessing the field via an interface.
|
|
||||||
func (v *VersionFilter) GetOrder() Order { return v.Order }
|
|
||||||
|
|
||||||
// GetSearch returns VersionFilter.Search, and is useful for accessing the field via an interface.
|
|
||||||
func (v *VersionFilter) GetSearch() string { return v.Search }
|
|
||||||
|
|
||||||
// GetIds returns VersionFilter.Ids, and is useful for accessing the field via an interface.
|
|
||||||
func (v *VersionFilter) GetIds() []string { return v.Ids }
|
|
||||||
|
|
||||||
// VersionMod includes the requested fields of the GraphQL type Mod.
|
// VersionMod includes the requested fields of the GraphQL type Mod.
|
||||||
type VersionMod struct {
|
type VersionMod struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
@ -884,26 +645,6 @@ type __GetModNameInput struct {
|
||||||
// GetModId returns __GetModNameInput.ModId, and is useful for accessing the field via an interface.
|
// GetModId returns __GetModNameInput.ModId, and is useful for accessing the field via an interface.
|
||||||
func (v *__GetModNameInput) GetModId() string { return v.ModId }
|
func (v *__GetModNameInput) GetModId() string { return v.ModId }
|
||||||
|
|
||||||
// __ModVersionsInput is used internally by genqlient
|
|
||||||
type __ModVersionsInput struct {
|
|
||||||
ModId string `json:"modId,omitempty"`
|
|
||||||
Filter VersionFilter `json:"filter,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetModId returns __ModVersionsInput.ModId, and is useful for accessing the field via an interface.
|
|
||||||
func (v *__ModVersionsInput) GetModId() string { return v.ModId }
|
|
||||||
|
|
||||||
// GetFilter returns __ModVersionsInput.Filter, and is useful for accessing the field via an interface.
|
|
||||||
func (v *__ModVersionsInput) GetFilter() VersionFilter { return v.Filter }
|
|
||||||
|
|
||||||
// __ModVersionsWithDependenciesInput is used internally by genqlient
|
|
||||||
type __ModVersionsWithDependenciesInput struct {
|
|
||||||
ModId string `json:"modId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetModId returns __ModVersionsWithDependenciesInput.ModId, and is useful for accessing the field via an interface.
|
|
||||||
func (v *__ModVersionsWithDependenciesInput) GetModId() string { return v.ModId }
|
|
||||||
|
|
||||||
// __ModsInput is used internally by genqlient
|
// __ModsInput is used internally by genqlient
|
||||||
type __ModsInput struct {
|
type __ModsInput struct {
|
||||||
Filter ModFilter `json:"filter,omitempty"`
|
Filter ModFilter `json:"filter,omitempty"`
|
||||||
|
@ -1129,98 +870,6 @@ func GetModName(
|
||||||
return &data, err
|
return &data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The query or mutation executed by ModVersions.
|
|
||||||
const ModVersions_Operation = `
|
|
||||||
query ModVersions ($modId: String!, $filter: VersionFilter) {
|
|
||||||
mod: getModByIdOrReference(modIdOrReference: $modId) {
|
|
||||||
id
|
|
||||||
versions(filter: $filter) {
|
|
||||||
id
|
|
||||||
version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
func ModVersions(
|
|
||||||
ctx context.Context,
|
|
||||||
client graphql.Client,
|
|
||||||
modId string,
|
|
||||||
filter VersionFilter,
|
|
||||||
) (*ModVersionsResponse, error) {
|
|
||||||
req := &graphql.Request{
|
|
||||||
OpName: "ModVersions",
|
|
||||||
Query: ModVersions_Operation,
|
|
||||||
Variables: &__ModVersionsInput{
|
|
||||||
ModId: modId,
|
|
||||||
Filter: filter,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
|
|
||||||
var data ModVersionsResponse
|
|
||||||
resp := &graphql.Response{Data: &data}
|
|
||||||
|
|
||||||
err = client.MakeRequest(
|
|
||||||
ctx,
|
|
||||||
req,
|
|
||||||
resp,
|
|
||||||
)
|
|
||||||
|
|
||||||
return &data, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The query or mutation executed by ModVersionsWithDependencies.
|
|
||||||
const ModVersionsWithDependencies_Operation = `
|
|
||||||
query ModVersionsWithDependencies ($modId: String!) {
|
|
||||||
mod: getModByIdOrReference(modIdOrReference: $modId) {
|
|
||||||
id
|
|
||||||
versions(filter: {limit:100}) {
|
|
||||||
id
|
|
||||||
version
|
|
||||||
link
|
|
||||||
hash
|
|
||||||
dependencies {
|
|
||||||
mod_id
|
|
||||||
condition
|
|
||||||
optional
|
|
||||||
}
|
|
||||||
targets {
|
|
||||||
targetName
|
|
||||||
link
|
|
||||||
hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
func ModVersionsWithDependencies(
|
|
||||||
ctx context.Context,
|
|
||||||
client graphql.Client,
|
|
||||||
modId string,
|
|
||||||
) (*ModVersionsWithDependenciesResponse, error) {
|
|
||||||
req := &graphql.Request{
|
|
||||||
OpName: "ModVersionsWithDependencies",
|
|
||||||
Query: ModVersionsWithDependencies_Operation,
|
|
||||||
Variables: &__ModVersionsWithDependenciesInput{
|
|
||||||
ModId: modId,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
|
|
||||||
var data ModVersionsWithDependenciesResponse
|
|
||||||
resp := &graphql.Response{Data: &data}
|
|
||||||
|
|
||||||
err = client.MakeRequest(
|
|
||||||
ctx,
|
|
||||||
req,
|
|
||||||
resp,
|
|
||||||
)
|
|
||||||
|
|
||||||
return &data, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The query or mutation executed by Mods.
|
// The query or mutation executed by Mods.
|
||||||
const Mods_Operation = `
|
const Mods_Operation = `
|
||||||
query Mods ($filter: ModFilter) {
|
query Mods ($filter: ModFilter) {
|
||||||
|
@ -1267,46 +916,6 @@ func Mods(
|
||||||
return &data, err
|
return &data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The query or mutation executed by SMLVersions.
|
|
||||||
const SMLVersions_Operation = `
|
|
||||||
query SMLVersions {
|
|
||||||
smlVersions: getSMLVersions(filter: {limit:100}) {
|
|
||||||
count
|
|
||||||
sml_versions {
|
|
||||||
id
|
|
||||||
version
|
|
||||||
satisfactory_version
|
|
||||||
targets {
|
|
||||||
targetName
|
|
||||||
link
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
func SMLVersions(
|
|
||||||
ctx context.Context,
|
|
||||||
client graphql.Client,
|
|
||||||
) (*SMLVersionsResponse, error) {
|
|
||||||
req := &graphql.Request{
|
|
||||||
OpName: "SMLVersions",
|
|
||||||
Query: SMLVersions_Operation,
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
|
|
||||||
var data SMLVersionsResponse
|
|
||||||
resp := &graphql.Response{Data: &data}
|
|
||||||
|
|
||||||
err = client.MakeRequest(
|
|
||||||
ctx,
|
|
||||||
req,
|
|
||||||
resp,
|
|
||||||
)
|
|
||||||
|
|
||||||
return &data, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The query or mutation executed by Version.
|
// The query or mutation executed by Version.
|
||||||
const Version_Operation = `
|
const Version_Operation = `
|
||||||
query Version ($modId: String!, $version: String!) {
|
query Version ($modId: String!, $version: String!) {
|
||||||
|
|
|
@ -7,10 +7,12 @@ type AllVersionsResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModVersion struct {
|
type ModVersion struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Dependencies []Dependency `json:"dependencies"`
|
GameVersion string `json:"game_version"`
|
||||||
Targets []Target `json:"targets"`
|
Dependencies []Dependency `json:"dependencies"`
|
||||||
|
Targets []Target `json:"targets"`
|
||||||
|
RequiredOnRemote bool `json:"required_on_remote"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Dependency struct {
|
type Dependency struct {
|
||||||
|
@ -22,6 +24,7 @@ type Dependency struct {
|
||||||
type Target struct {
|
type Target struct {
|
||||||
VersionID string `json:"version_id"`
|
VersionID string `json:"version_id"`
|
||||||
TargetName string `json:"target_name"`
|
TargetName string `json:"target_name"`
|
||||||
|
Link string `json:"link"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
}
|
}
|
||||||
|
|
411
flake.lock
411
flake.lock
|
@ -18,18 +18,396 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"flake-utils_10": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1700014976,
|
"lastModified": 1653893745,
|
||||||
"narHash": "sha256-dSGpS2YeJrXW5aH9y7Abd235gGufY3RuZFth6vuyVtU=",
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
"owner": "NixOS",
|
"owner": "numtide",
|
||||||
"repo": "nixpkgs",
|
"repo": "flake-utils",
|
||||||
"rev": "592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3",
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"owner": "numtide",
|
||||||
"type": "indirect"
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_4": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_5": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_6": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_7": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_8": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_9": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1653893745,
|
||||||
|
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mfgames-project-setup": {
|
||||||
|
"inputs": {
|
||||||
|
"nixago": "nixago",
|
||||||
|
"nixago-exts": "nixago-exts_3",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1723051996,
|
||||||
|
"narHash": "sha256-pcWXdsdAbD0U9b93V/I+eJREbgZ5TWYkFc26gmSz46E=",
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"rev": "f378dedc71e3b2b82f95041069bec56fce9e9524",
|
||||||
|
"revCount": 29,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://src.mfgames.com/nixos-contrib/mfgames-project-setup-flake.git"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://src.mfgames.com/nixos-contrib/mfgames-project-setup-flake.git"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
|
"nixago-exts": "nixago-exts",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687381756,
|
||||||
|
"narHash": "sha256-IUMIlYfrvj7Yli4H2vvyig8HEPpfCeMaE6+kBGPzFyk=",
|
||||||
|
"owner": "jmgilman",
|
||||||
|
"repo": "nixago",
|
||||||
|
"rev": "dacceb10cace103b3e66552ec9719fa0d33c0dc9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "jmgilman",
|
||||||
|
"repo": "nixago",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago-exts": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_3",
|
||||||
|
"nixago": "nixago_2",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixago",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1676070308,
|
||||||
|
"narHash": "sha256-QaJ65oc2l8iwQIGWUJ0EKjCeSuuCM/LqR8RauxZUUkc=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"rev": "e5380cb0456f4ea3c86cf94e3039eb856bf07d0b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago-exts_2": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_5",
|
||||||
|
"nixago": "nixago_3",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixago",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixago",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1655508669,
|
||||||
|
"narHash": "sha256-BDDdo5dZQMmwNH/GNacy33nPBnCpSIydWFPZs0kkj/g=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"rev": "3022a932ce109258482ecc6568c163e8d0b426aa",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago-exts_3": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_7",
|
||||||
|
"nixago": "nixago_4",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1676070308,
|
||||||
|
"narHash": "sha256-QaJ65oc2l8iwQIGWUJ0EKjCeSuuCM/LqR8RauxZUUkc=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"rev": "e5380cb0456f4ea3c86cf94e3039eb856bf07d0b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago-exts_4": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_9",
|
||||||
|
"nixago": "nixago_5",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixago",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1655508669,
|
||||||
|
"narHash": "sha256-BDDdo5dZQMmwNH/GNacy33nPBnCpSIydWFPZs0kkj/g=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"rev": "3022a932ce109258482ecc6568c163e8d0b426aa",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago-extensions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago_2": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_4",
|
||||||
|
"nixago-exts": "nixago-exts_2",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixago",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1676070010,
|
||||||
|
"narHash": "sha256-iYzJIWptE1EUD8VINAg66AAMUajizg8JUYN3oBmb8no=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago",
|
||||||
|
"rev": "d480ba6c0c16e2c5c0bd2122852d6a0c9ad1ed0e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"ref": "rename-config-data",
|
||||||
|
"repo": "nixago",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago_3": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_6",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixago",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixago",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1655405483,
|
||||||
|
"narHash": "sha256-Crd49aZWNrpczlRTOwWGfwBMsTUoG9vlHDKQC7cx264=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago",
|
||||||
|
"rev": "e6a9566c18063db5b120e69e048d3627414e327d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago_4": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_8",
|
||||||
|
"nixago-exts": "nixago-exts_4",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1676070010,
|
||||||
|
"narHash": "sha256-iYzJIWptE1EUD8VINAg66AAMUajizg8JUYN3oBmb8no=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago",
|
||||||
|
"rev": "d480ba6c0c16e2c5c0bd2122852d6a0c9ad1ed0e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"ref": "rename-config-data",
|
||||||
|
"repo": "nixago",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixago_5": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_10",
|
||||||
|
"nixpkgs": [
|
||||||
|
"mfgames-project-setup",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixago",
|
||||||
|
"nixago-exts",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1655405483,
|
||||||
|
"narHash": "sha256-Crd49aZWNrpczlRTOwWGfwBMsTUoG9vlHDKQC7cx264=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago",
|
||||||
|
"rev": "e6a9566c18063db5b120e69e048d3627414e327d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixago",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1706098335,
|
||||||
|
"narHash": "sha256-r3dWjT8P9/Ah5m5ul4WqIWD8muj5F+/gbCdjiNVBKmU=",
|
||||||
|
"rev": "a77ab169a83a4175169d78684ddd2e54486ac651",
|
||||||
|
"revCount": 554858,
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2311.554858%2Brev-a77ab169a83a4175169d78684ddd2e54486ac651/018d46f0-798f-71dc-a8c5-4689c46f7d12/source.tar.gz"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://flakehub.com/f/NixOS/nixpkgs/%2A.tar.gz"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
|
@ -47,10 +425,25 @@
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1700014976,
|
||||||
|
"narHash": "sha256-dSGpS2YeJrXW5aH9y7Abd235gGufY3RuZFth6vuyVtU=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"nixpkgs": "nixpkgs",
|
"mfgames-project-setup": "mfgames-project-setup",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
"nixpkgs-unstable": "nixpkgs-unstable"
|
"nixpkgs-unstable": "nixpkgs-unstable"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
28
flake.nix
28
flake.nix
|
@ -1,19 +1,35 @@
|
||||||
{
|
{
|
||||||
description = "smr-cli";
|
description = "ficsit-cli";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
nixpkgs-unstable.url = "flake:nixpkgs/nixpkgs-unstable";
|
nixpkgs-unstable.url = "flake:nixpkgs/nixpkgs-unstable";
|
||||||
|
mfgames-project-setup.url = "git+https://src.mfgames.com/nixos-contrib/mfgames-project-setup-flake.git";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils, nixpkgs-unstable }:
|
outputs = { self, nixpkgs, flake-utils, nixpkgs-unstable, mfgames-project-setup }:
|
||||||
flake-utils.lib.eachDefaultSystem
|
flake-utils.lib.eachDefaultSystem
|
||||||
(system:
|
(system:
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
unstable = nixpkgs-unstable.legacyPackages.${system}; in
|
unstable = nixpkgs-unstable.legacyPackages.${system};
|
||||||
|
in
|
||||||
{
|
{
|
||||||
devShells.default = import ./shell.nix { inherit pkgs unstable; };
|
devShells.default = import ./shell.nix { inherit system pkgs unstable mfgames-project-setup; };
|
||||||
|
|
||||||
|
defaultPackage = pkgs.buildGoModule {
|
||||||
|
pname = "ficsit-cli";
|
||||||
|
version = "0.6.0";
|
||||||
|
doCheck = false; # Tests are failing in this flake.
|
||||||
|
vendorHash = "sha256-vmA3jvxOLRYj5BmvWMhSEnCTEoe8BLm8lpm2kruIEv4="; #pkgs.lib.fakeHash;
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "satisfactorymodding";
|
||||||
|
repo = "ficsit-cli";
|
||||||
|
rev = "v0.6.0";
|
||||||
|
hash = "sha256-Zwidx0war3hos9NEmk9dEzPBgDGdUtWvZb7FIF5OZMA="; #pkgs.lib.fakeHash;
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml
|
# https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml
|
||||||
schema: schema.graphql
|
schema: schema.graphql
|
||||||
operations:
|
operations:
|
||||||
- ficsit/queries/*.graphql
|
- ficsit/queries/*.graphql
|
||||||
generated: ficsit/types.go
|
generated: ficsit/types.go
|
||||||
package: ficsit
|
package: ficsit
|
||||||
bindings:
|
bindings:
|
||||||
|
@ -17,10 +17,8 @@ bindings:
|
||||||
type: string
|
type: string
|
||||||
GuideID:
|
GuideID:
|
||||||
type: string
|
type: string
|
||||||
SMLVersionID:
|
|
||||||
type: string
|
|
||||||
Date:
|
Date:
|
||||||
type: time.Time
|
type: time.Time
|
||||||
unmarshaler: github.com/satisfactorymodding/ficsit-cli/ficsit/utils.UnmarshalDateTime
|
unmarshaler: github.com/satisfactorymodding/ficsit-cli/ficsit/utils.UnmarshalDateTime
|
||||||
TagID:
|
TagID:
|
||||||
type: string
|
type: string
|
||||||
|
|
29
go.mod
29
go.mod
|
@ -19,18 +19,20 @@ require (
|
||||||
github.com/jackc/puddle/v2 v2.2.1
|
github.com/jackc/puddle/v2 v2.2.1
|
||||||
github.com/jlaffaye/ftp v0.2.0
|
github.com/jlaffaye/ftp v0.2.0
|
||||||
github.com/lmittmann/tint v1.0.3
|
github.com/lmittmann/tint v1.0.3
|
||||||
|
github.com/mircearoata/pubgrub-go v0.3.3
|
||||||
github.com/muesli/reflow v0.3.0
|
github.com/muesli/reflow v0.3.0
|
||||||
github.com/pkg/sftp v1.13.6
|
github.com/pkg/sftp v1.13.6
|
||||||
github.com/pterm/pterm v0.12.71
|
github.com/pterm/pterm v0.12.71
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.0.2
|
github.com/puzpuzpuz/xsync/v3 v3.0.2
|
||||||
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f
|
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f
|
||||||
github.com/samber/slog-multi v1.0.2
|
github.com/samber/slog-multi v1.0.2
|
||||||
github.com/satisfactorymodding/ficsit-resolver v0.0.2
|
github.com/satisfactorymodding/ficsit-resolver v0.0.6
|
||||||
github.com/spf13/cobra v1.8.0
|
github.com/spf13/cobra v1.8.0
|
||||||
github.com/spf13/viper v1.18.1
|
github.com/spf13/viper v1.18.1
|
||||||
goftp.io/server/v2 v2.0.1
|
goftp.io/server/v2 v2.0.1
|
||||||
golang.org/x/crypto v0.16.0
|
golang.org/x/crypto v0.21.0
|
||||||
golang.org/x/sync v0.5.0
|
golang.org/x/sync v0.6.0
|
||||||
|
modernc.org/sqlite v1.32.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -54,10 +56,12 @@ require (
|
||||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gookit/color v1.5.4 // indirect
|
github.com/gookit/color v1.5.4 // indirect
|
||||||
github.com/gorilla/css v1.0.1 // indirect
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||||
|
@ -69,14 +73,15 @@ require (
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
|
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
|
||||||
github.com/mircearoata/pubgrub-go v0.3.3 // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/termenv v0.15.2 // indirect
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
|
@ -94,13 +99,19 @@ require (
|
||||||
github.com/yuin/goldmark-emoji v1.0.2 // indirect
|
github.com/yuin/goldmark-emoji v1.0.2 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect
|
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect
|
||||||
golang.org/x/mod v0.14.0 // indirect
|
golang.org/x/mod v0.16.0 // indirect
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/net v0.22.0 // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
golang.org/x/term v0.15.0 // indirect
|
golang.org/x/term v0.18.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.16.0 // indirect
|
golang.org/x/tools v0.19.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||||
|
modernc.org/libc v1.55.3 // indirect
|
||||||
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
modernc.org/memory v1.8.0 // indirect
|
||||||
|
modernc.org/strutil v1.2.0 // indirect
|
||||||
|
modernc.org/token v1.1.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
68
go.sum
68
go.sum
|
@ -86,6 +86,10 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
|
||||||
|
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||||
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
||||||
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
||||||
|
@ -99,6 +103,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
@ -164,6 +170,8 @@ github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKt
|
||||||
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
||||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||||
|
@ -187,6 +195,8 @@ github.com/pterm/pterm v0.12.71 h1:KcEJ98EiVCbzDkFbktJ2gMlr4pn8IzyGb9bwK6ffkuA=
|
||||||
github.com/pterm/pterm v0.12.71/go.mod h1:SUAcoZjRt+yjPWlWba+/Fd8zJJ2lSXBQWf0Z0HbFiIQ=
|
github.com/pterm/pterm v0.12.71/go.mod h1:SUAcoZjRt+yjPWlWba+/Fd8zJJ2lSXBQWf0Z0HbFiIQ=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew=
|
github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
|
@ -205,8 +215,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||||
github.com/samber/slog-multi v1.0.2 h1:6BVH9uHGAsiGkbbtQgAOQJMpKgV8unMrHhhJaw+X1EQ=
|
github.com/samber/slog-multi v1.0.2 h1:6BVH9uHGAsiGkbbtQgAOQJMpKgV8unMrHhhJaw+X1EQ=
|
||||||
github.com/samber/slog-multi v1.0.2/go.mod h1:uLAvHpGqbYgX4FSL0p1ZwoLuveIAJvBECtE07XmYvFo=
|
github.com/samber/slog-multi v1.0.2/go.mod h1:uLAvHpGqbYgX4FSL0p1ZwoLuveIAJvBECtE07XmYvFo=
|
||||||
github.com/satisfactorymodding/ficsit-resolver v0.0.2 h1:dj/OsDLpaMUqCHpfBVHvDMUv2nf5gT4HS2ydBMkmtcQ=
|
github.com/satisfactorymodding/ficsit-resolver v0.0.6 h1:4iCIHOg3z+AvwSVeWtu+k9aysLOL9+FIszCbiKOG2oo=
|
||||||
github.com/satisfactorymodding/ficsit-resolver v0.0.2/go.mod h1:ckKMmMvDoYbbkEbWXEsMes608uvv6EKphXPhHX8LKSc=
|
github.com/satisfactorymodding/ficsit-resolver v0.0.6/go.mod h1:ckKMmMvDoYbbkEbWXEsMes608uvv6EKphXPhHX8LKSc=
|
||||||
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
|
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
|
||||||
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
@ -267,14 +277,14 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
|
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
|
||||||
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
@ -290,13 +300,13 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -318,8 +328,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
@ -329,8 +339,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
||||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
@ -346,8 +356,8 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
@ -363,3 +373,29 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
|
||||||
|
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
|
||||||
|
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||||
|
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||||
|
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||||
|
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||||
|
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||||
|
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||||
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
|
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||||
|
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||||
|
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||||
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||||
|
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||||
|
modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s=
|
||||||
|
modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
|
||||||
|
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||||
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
|
11
shell.nix
11
shell.nix
|
@ -1,6 +1,13 @@
|
||||||
{ pkgs, unstable }:
|
{ system, pkgs, unstable, mfgames-project-setup }:
|
||||||
|
let
|
||||||
|
project-config = mfgames-project-setup.lib.mkConfig {
|
||||||
|
inherit system pkgs;
|
||||||
|
};
|
||||||
|
in
|
||||||
pkgs.mkShell {
|
pkgs.mkShell {
|
||||||
|
buildInputs = project-config.packages;
|
||||||
|
shellHook = project-config.shellHook;
|
||||||
|
|
||||||
nativeBuildInputs = with pkgs.buildPackages; [
|
nativeBuildInputs = with pkgs.buildPackages; [
|
||||||
unstable.go_1_21
|
unstable.go_1_21
|
||||||
unstable.golangci-lint
|
unstable.golangci-lint
|
||||||
|
|
|
@ -3,6 +3,7 @@ package components
|
||||||
import (
|
import (
|
||||||
"github.com/Khan/genqlient/graphql"
|
"github.com/Khan/genqlient/graphql"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||||
|
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cli"
|
"github.com/satisfactorymodding/ficsit-cli/cli"
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cli/provider"
|
"github.com/satisfactorymodding/ficsit-cli/cli/provider"
|
||||||
|
@ -19,6 +20,7 @@ type RootModel interface {
|
||||||
|
|
||||||
GetAPIClient() graphql.Client
|
GetAPIClient() graphql.Client
|
||||||
GetProvider() provider.Provider
|
GetProvider() provider.Provider
|
||||||
|
GetResolver() resolver.DependencyResolver
|
||||||
|
|
||||||
Size() tea.WindowSizeMsg
|
Size() tea.WindowSizeMsg
|
||||||
SetSize(size tea.WindowSizeMsg)
|
SetSize(size tea.WindowSizeMsg)
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cli"
|
"github.com/satisfactorymodding/ficsit-cli/cli"
|
||||||
"github.com/satisfactorymodding/ficsit-cli/cli/provider"
|
"github.com/satisfactorymodding/ficsit-cli/cli/provider"
|
||||||
|
@ -29,7 +28,7 @@ func newModel(global *cli.GlobalContext) *rootModel {
|
||||||
Width: 20,
|
Width: 20,
|
||||||
Height: 14,
|
Height: 14,
|
||||||
},
|
},
|
||||||
dependencyResolver: resolver.NewDependencyResolver(global.Provider, viper.GetString("api-base")),
|
dependencyResolver: resolver.NewDependencyResolver(global.Provider),
|
||||||
}
|
}
|
||||||
|
|
||||||
m.headerComponent = components.NewHeaderComponent(m)
|
m.headerComponent = components.NewHeaderComponent(m)
|
||||||
|
@ -71,6 +70,10 @@ func (m *rootModel) GetProvider() provider.Provider {
|
||||||
return m.global.Provider
|
return m.global.Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *rootModel) GetResolver() resolver.DependencyResolver {
|
||||||
|
return m.dependencyResolver
|
||||||
|
}
|
||||||
|
|
||||||
func (m *rootModel) Size() tea.WindowSizeMsg {
|
func (m *rootModel) Size() tea.WindowSizeMsg {
|
||||||
return m.currentSize
|
return m.currentSize
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@ import (
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/muesli/reflow/truncate"
|
"github.com/muesli/reflow/truncate"
|
||||||
resolver "github.com/satisfactorymodding/ficsit-resolver"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
"github.com/satisfactorymodding/ficsit-cli/ficsit"
|
||||||
"github.com/satisfactorymodding/ficsit-cli/tea/components"
|
"github.com/satisfactorymodding/ficsit-cli/tea/components"
|
||||||
|
@ -112,9 +110,7 @@ func (m updateModsList) LoadModData() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver := resolver.NewDependencyResolver(m.root.GetProvider(), viper.GetString("api-base"))
|
updatedLockfile, err := currentProfile.Resolve(m.root.GetResolver(), nil, gameVersion)
|
||||||
|
|
||||||
updatedLockfile, err := currentProfile.Resolve(resolver, nil, gameVersion)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
2
tools.go
2
tools.go
|
@ -46,6 +46,8 @@ func main() {
|
||||||
baseLocalDir = os.Getenv("APPDATA")
|
baseLocalDir = os.Getenv("APPDATA")
|
||||||
case "linux":
|
case "linux":
|
||||||
baseLocalDir = filepath.Join(os.Getenv("HOME"), ".local", "share")
|
baseLocalDir = filepath.Join(os.Getenv("HOME"), ".local", "share")
|
||||||
|
case "darwin":
|
||||||
|
baseLocalDir = filepath.Join(os.Getenv("HOME"), "Library", "Application Support")
|
||||||
default:
|
default:
|
||||||
panic("unsupported platform: " + runtime.GOOS)
|
panic("unsupported platform: " + runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue