first alpha version cli

This commit is contained in:
2025-05-10 21:52:52 +02:00
parent f791b7085c
commit 2380a36271
8 changed files with 275 additions and 12 deletions

View File

@@ -17,19 +17,19 @@ type (
} }
) )
func (AddCmd) Name() string { return "add" } func (*AddCmd) Name() string { return "add" }
func (AddCmd) Synopsis() string { return "Add a folder to the sync list" } func (*AddCmd) Synopsis() string { return "Add a folder to the sync list" }
func (AddCmd) Usage() string { func (*AddCmd) Usage() string {
return `add: return `add:
Add a folder to the sync list Add a folder to the sync list
` `
} }
func (p AddCmd) SetFlags(f *flag.FlagSet) { func (p *AddCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&p.name, "name", "", "Override the name of the game") f.StringVar(&p.name, "name", "", "Override the name of the game")
} }
func (p AddCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { func (p *AddCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if f.NArg() != 1 { if f.NArg() != 1 {
fmt.Fprintln(os.Stderr, "error: the command is expecting for 1 argument") fmt.Fprintln(os.Stderr, "error: the command is expecting for 1 argument")
return subcommands.ExitUsageError return subcommands.ExitUsageError

View File

@@ -0,0 +1,45 @@
package list
import (
"cloudsave/pkg/game"
"context"
"flag"
"fmt"
"os"
"github.com/google/subcommands"
)
type (
ListCmd struct {
name string
}
)
func (*ListCmd) Name() string { return "list" }
func (*ListCmd) Synopsis() string { return "list all game registered" }
func (*ListCmd) Usage() string {
return `add:
List all game registered
`
}
func (p *ListCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&p.name, "name", "", "Override the name of the game")
}
func (p *ListCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
datastore, err := game.All()
if err != nil {
fmt.Fprintln(os.Stderr, "error: failed to load datastore:", err)
return subcommands.ExitFailure
}
fmt.Println("ID | NAME | PATH")
fmt.Println("-- | ---- | ----")
for _, metadata := range datastore {
fmt.Println(metadata.ID, "|", metadata.Name, "|", metadata.Path)
}
return subcommands.ExitSuccess
}

View File

@@ -0,0 +1,67 @@
package remote
import (
"cloudsave/pkg/remote"
"context"
"flag"
"fmt"
"os"
"github.com/google/subcommands"
)
type (
RemoteCmd struct {
set bool
list bool
}
)
func (*RemoteCmd) Name() string { return "remote" }
func (*RemoteCmd) Synopsis() string { return "manage remote" }
func (*RemoteCmd) Usage() string {
return `remote:
manage remove
`
}
func (p *RemoteCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&p.list, "list", false, "list remotes")
f.BoolVar(&p.set, "set", false, "set remote for a game")
}
func (p *RemoteCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if p.list {
remotes, err := remote.All()
if err != nil {
fmt.Fprintln(os.Stderr, "error: failed to load datastore:", err)
return subcommands.ExitFailure
}
fmt.Println("ID | REMOTE URL")
fmt.Println("-- | ----------")
for _, remote := range remotes {
fmt.Println(remote.GameID, "|", remote.URL)
}
return subcommands.ExitSuccess
}
if p.set {
if f.NArg() != 2 {
fmt.Fprintln(os.Stderr, "error: the command is expecting for 2 arguments")
f.Usage()
return subcommands.ExitUsageError
}
err := remote.Set(f.Arg(0), f.Arg(1))
if err != nil {
fmt.Fprintln(os.Stderr, "error: failed to set remote:", err)
return subcommands.ExitFailure
}
fmt.Println(f.Arg(0))
return subcommands.ExitSuccess
}
f.Usage()
return subcommands.ExitUsageError
}

View File

@@ -0,0 +1,40 @@
package remove
import (
"cloudsave/pkg/game"
"context"
"flag"
"fmt"
"os"
"github.com/google/subcommands"
)
type (
RemoveCmd struct{}
)
func (*RemoveCmd) Name() string { return "remove" }
func (*RemoveCmd) Synopsis() string { return "unregister a game" }
func (*RemoveCmd) Usage() string {
return `remove:
Unregister a game
`
}
func (p *RemoveCmd) SetFlags(f *flag.FlagSet) {
}
func (p *RemoveCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if f.NArg() != 1 {
fmt.Fprintln(os.Stderr, "error: the command is expecting for 1 argument")
return subcommands.ExitUsageError
}
err := game.Remove(f.Arg(0))
if err != nil {
fmt.Fprintln(os.Stderr, "error: failed to unregister the game:", err)
return subcommands.ExitFailure
}
return subcommands.ExitSuccess
}

View File

@@ -20,17 +20,17 @@ type (
} }
) )
func (RunCmd) Name() string { return "run" } func (*RunCmd) Name() string { return "run" }
func (RunCmd) Synopsis() string { return "Check and process all the folder" } func (*RunCmd) Synopsis() string { return "Check and process all the folder" }
func (RunCmd) Usage() string { func (*RunCmd) Usage() string {
return `run: return `run:
Check and process all the folder Check and process all the folder
` `
} }
func (p RunCmd) SetFlags(f *flag.FlagSet) {} func (p *RunCmd) SetFlags(f *flag.FlagSet) {}
func (p RunCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { func (p *RunCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
datastore, err := game.All() datastore, err := game.All()
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "error: failed to load datastore:", err) fmt.Fprintln(os.Stderr, "error: failed to load datastore:", err)

View File

@@ -2,6 +2,9 @@ package main
import ( import (
"cloudsave/cmd/cli/commands/add" "cloudsave/cmd/cli/commands/add"
"cloudsave/cmd/cli/commands/list"
"cloudsave/cmd/cli/commands/remote"
"cloudsave/cmd/cli/commands/remove"
"cloudsave/cmd/cli/commands/run" "cloudsave/cmd/cli/commands/run"
"context" "context"
"flag" "flag"
@@ -15,8 +18,12 @@ func main() {
subcommands.Register(subcommands.FlagsCommand(), "help") subcommands.Register(subcommands.FlagsCommand(), "help")
subcommands.Register(subcommands.CommandsCommand(), "help") subcommands.Register(subcommands.CommandsCommand(), "help")
subcommands.Register(add.AddCmd{}, "management") subcommands.Register(&add.AddCmd{}, "management")
subcommands.Register(run.RunCmd{}, "management") subcommands.Register(&run.RunCmd{}, "management")
subcommands.Register(&list.ListCmd{}, "management")
subcommands.Register(&remove.RemoveCmd{}, "management")
subcommands.Register(&remote.RemoteCmd{}, "remote")
flag.Parse() flag.Parse()
ctx := context.Background() ctx := context.Background()

View File

@@ -42,6 +42,11 @@ func Add(name, path string) (Metadata, error) {
Path: path, Path: path,
} }
err := os.MkdirAll(filepath.Join(datastorepath, m.ID), 0740)
if err != nil {
panic("cannot make directory for the game:" + err.Error())
}
f, err := os.OpenFile(filepath.Join(datastorepath, m.ID, "metadata.json"), os.O_CREATE|os.O_WRONLY, 0740) f, err := os.OpenFile(filepath.Join(datastorepath, m.ID, "metadata.json"), os.O_CREATE|os.O_WRONLY, 0740)
if err != nil { if err != nil {
return Metadata{}, fmt.Errorf("cannot open the metadata file in the datastore: %w", err) return Metadata{}, fmt.Errorf("cannot open the metadata file in the datastore: %w", err)
@@ -84,3 +89,11 @@ func All() ([]Metadata, error) {
func DatastorePath() string { func DatastorePath() string {
return datastorepath return datastorepath
} }
func Remove(gameID string) error {
err := os.RemoveAll(filepath.Join(datastorepath, gameID))
if err != nil {
return err
}
return nil
}

91
pkg/remote/remote.go Normal file
View File

@@ -0,0 +1,91 @@
package remote
import (
"cloudsave/pkg/game"
"encoding/json"
"fmt"
"os"
"path/filepath"
)
type (
Remote struct {
URL string `json:"url"`
GameID string `json:"-"`
}
)
var (
roaming string
datastorepath string
)
func init() {
var err error
roaming, err = os.UserConfigDir()
if err != nil {
panic("failed to get user config path: " + err.Error())
}
datastorepath = filepath.Join(roaming, "cloudsave", "data")
err = os.MkdirAll(datastorepath, 0740)
if err != nil {
panic("cannot make the datastore:" + err.Error())
}
}
func All() ([]Remote, error) {
ds, err := os.ReadDir(datastorepath)
if err != nil {
return nil, fmt.Errorf("cannot open the datastore: %w", err)
}
var remotes []Remote
for _, d := range ds {
content, err := os.ReadFile(filepath.Join(datastorepath, d.Name(), "remote.json"))
if err != nil {
continue
}
var r Remote
err = json.Unmarshal(content, &r)
if err != nil {
return nil, fmt.Errorf("corrupted datastore: failed to parse %s/remote.json: %w", d.Name(), err)
}
content, err = os.ReadFile(filepath.Join(datastorepath, d.Name(), "metadata.json"))
if err != nil {
return nil, fmt.Errorf("corrupted datastore: failed to read %s/metadata.json: %w", d.Name(), err)
}
var m game.Metadata
err = json.Unmarshal(content, &m)
if err != nil {
return nil, fmt.Errorf("corrupted datastore: failed to parse %s/metadata.json: %w", d.Name(), err)
}
r.GameID = m.ID
remotes = append(remotes, r)
}
return remotes, nil
}
func Set(gameID, url string) error {
r := Remote{
URL: url,
}
f, err := os.OpenFile(filepath.Join(datastorepath, gameID, "remote.json"), os.O_WRONLY|os.O_CREATE, 0740)
if err != nil {
return err
}
defer f.Close()
e := json.NewEncoder(f)
err = e.Encode(r)
if err != nil {
return err
}
return nil
}