feat: add download command

main
sudo pacman -Syu 2022-10-24 21:57:44 +07:00
parent 4436671155
commit 7c07820fe1
No known key found for this signature in database
GPG Key ID: D6CB5C6C567C47B0
7 changed files with 140 additions and 45 deletions

View File

@ -21,6 +21,10 @@
{
"internal": "data/kitty",
"external": "~/.config/kitty"
},
{
"internal": "data/kitty/mocha.conf",
"url": "https://raw.githubusercontent.com/catppuccin/kitty/main/mocha.conf"
}
]
},

View File

@ -1,6 +1,6 @@
# vim:ft=kitty
## name: Catppuccin Kitty Diff Mocha
## name: Catppuccin Kitty Mocha
## author: Catppuccin Org
## license: MIT
## upstream: https://github.com/catppuccin/kitty/blob/main/mocha.conf

View File

@ -21,73 +21,77 @@ func (a *action) runHelp(c *cli.Context) error {
}
func (a *action) runInstall(c *cli.Context) error {
a.getFlags(c)
a.log("start %s\n", installCommand)
cfg, err := a.loadConfig()
cfg, err := a.loadConfig(c, installCommand)
if err != nil {
return err
}
if err := cfg.Install(); err != nil {
return fmt.Errorf("failed to install config: %w", err)
return fmt.Errorf("config: failed to install: %w", err)
}
return nil
}
func (a *action) runUpdate(c *cli.Context) error {
a.getFlags(c)
a.log("start %s\n", updateCommand)
cfg, err := a.loadConfig()
cfg, err := a.loadConfig(c, updateCommand)
if err != nil {
return err
}
if err := cfg.Update(); err != nil {
return fmt.Errorf("failed to update config: %w", err)
return fmt.Errorf("config: failed to update: %w", err)
}
return nil
}
func (a *action) runDownload(c *cli.Context) error {
cfg, err := a.loadConfig(c, downloadCommand)
if err != nil {
return err
}
if err := cfg.Download(); err != nil {
return fmt.Errorf("config: failed to download: %w", err)
}
return nil
}
func (a *action) runClean(c *cli.Context) error {
a.getFlags(c)
a.log("start %s\n", cleanCommand)
cfg, err := a.loadConfig()
cfg, err := a.loadConfig(c, cleanCommand)
if err != nil {
return err
}
if err := cfg.Clean(); err != nil {
return fmt.Errorf("failed to clean config: %w", err)
return fmt.Errorf("config: failed to clean: %w", err)
}
return nil
}
func (a *action) runDiff(c *cli.Context) error {
a.getFlags(c)
a.log("start %s\n", diffCommand)
cfg, err := a.loadConfig()
cfg, err := a.loadConfig(c, diffCommand)
if err != nil {
return err
}
if err := cfg.Diff(); err != nil {
return fmt.Errorf("failed to compare config: %w", err)
return fmt.Errorf("config: failed to compare: %w", err)
}
return nil
}
func (a *action) loadConfig() (config.Config, error) {
func (a *action) loadConfig(c *cli.Context, command string) (config.Config, error) {
a.getFlags(c)
a.log("start %s with flags %+v\n", command, a.flags)
cfgReal, cfgDemo, err := config.LoadConfig(currentDir)
if err != nil {
return nil, fmt.Errorf("failed to load config: %w", err)
return nil, fmt.Errorf("config: failed to load: %w", err)
}
if a.flags.dryRun {

View File

@ -13,34 +13,36 @@ const (
appName = "dotfiles"
appUsage = "managing dotfiles"
// flags
verboseFlag = "verbose"
dryRunFlag = "dry-run"
// commands
installCommand = "install"
updateCommand = "update"
cleanCommand = "clean"
diffCommand = "diff"
installUsage = "install user configs from dotfiles"
// flag usages
verboseUsage = "show what is going on"
dryRunUsage = "demo mode without actually changing anything"
updateCommand = "update"
updateUsage = "update dotfiles from user configs"
// command usages
installUsage = "install user configs from dotfiles"
updateUsage = "update dotfiles from user configs"
downloadCommand = "download"
downloadUsage = "download configs from internet (theme for example)"
cleanCommand = "clean"
cleanUsage = "clean unused dotfiles"
diffUsage = "diff dotfiles with user configs"
diffCommand = "diff"
diffUsage = "diff dotfiles with user configs"
verboseFlag = "verbose"
verboseUsage = "show what is going on"
dryRunFlag = "dry-run"
dryRunUsage = "demo mode without actually changing anything"
currentDir = "."
)
var (
// command aliases
installAliases = []string{"i"}
updateAliases = []string{"u"}
cleanAliases = []string{"c"}
installAliases = []string{"i"}
updateAliases = []string{"u"}
downloadAliases = []string{"d"}
cleanAliases = []string{"c"}
diffAliases = []string{"df"}
)
// denyOSes contains OS which is not supported
@ -92,6 +94,22 @@ func NewApp() *App {
},
Action: a.runUpdate,
},
{
Name: downloadCommand,
Aliases: downloadAliases,
Usage: downloadUsage,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: verboseFlag,
Usage: verboseUsage,
},
&cli.BoolFlag{
Name: dryRunFlag,
Usage: dryRunUsage,
},
},
Action: a.runDownload,
},
{
Name: cleanCommand,
Aliases: cleanAliases,
@ -109,8 +127,9 @@ func NewApp() *App {
Action: a.runClean,
},
{
Name: diffCommand,
Usage: diffUsage,
Name: diffCommand,
Aliases: diffAliases,
Usage: diffUsage,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: verboseFlag,

View File

@ -3,8 +3,10 @@ package config
import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"time"
)
const (
@ -17,6 +19,7 @@ type Config interface {
Update() error
Clean() error
Diff() error
Download() error
}
type configApps struct {
@ -30,7 +33,8 @@ type App struct {
type Path struct {
Internal string `json:"internal"`
External string `json:"external"`
External string `json:"external,omitempty"`
URL string `json:"url,omitempty"`
}
// LoadConfig return config, configDemo
@ -47,6 +51,9 @@ func LoadConfig(path string) (*configReal, *configDemo, error) {
}
cfgReal := configReal{
httpClient: &http.Client{
Timeout: time.Second * 5,
},
configApps: cfgApps,
}

View File

@ -11,6 +11,10 @@ var _ Config = (*configDemo)(nil)
func (c *configDemo) Install() error {
for _, app := range c.Apps {
for _, p := range app.Paths {
if p.External == "" {
continue
}
fmt.Printf("Replace %s -> %s\n", p.Internal, p.External)
}
}
@ -21,6 +25,10 @@ func (c *configDemo) Install() error {
func (c *configDemo) Update() error {
for _, app := range c.Apps {
for _, p := range app.Paths {
if p.External == "" {
continue
}
fmt.Printf("Replace %s -> %s\n", p.External, p.Internal)
}
}
@ -28,6 +36,20 @@ func (c *configDemo) Update() error {
return nil
}
func (c *configDemo) Download() error {
for _, app := range c.Apps {
for _, p := range app.Paths {
if p.URL == "" {
continue
}
fmt.Printf("Download %s -> %s\n", p.URL, p.Internal)
}
}
return nil
}
func (c *configDemo) Clean() error {
unusedDirs, err := getUnusedDirs(c.Apps)
if err != nil {

View File

@ -2,6 +2,8 @@ package config
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
@ -10,6 +12,7 @@ import (
)
type configReal struct {
httpClient *http.Client
configApps
}
@ -19,6 +22,10 @@ var _ Config = (*configReal)(nil)
func (c *configReal) Install() error {
for _, app := range c.Apps {
for _, p := range app.Paths {
if p.External == "" {
continue
}
if err := copy.Replace(p.Internal, p.External); err != nil {
return fmt.Errorf("failed to replace %s -> %s: %w", p.Internal, p.External, err)
}
@ -32,6 +39,10 @@ func (c *configReal) Install() error {
func (c *configReal) Update() error {
for _, app := range c.Apps {
for _, p := range app.Paths {
if p.External == "" {
continue
}
if err := copy.Replace(p.External, p.Internal); err != nil {
return fmt.Errorf("failed to replace %s -> %s: %w", p.External, p.Internal, err)
}
@ -41,6 +52,34 @@ func (c *configReal) Update() error {
return nil
}
func (c *configReal) Download() error {
for _, app := range c.Apps {
for _, p := range app.Paths {
if p.URL == "" {
continue
}
httpRsp, err := c.httpClient.Get(p.URL)
if err != nil {
return fmt.Errorf("http client: failed to get: %w", err)
}
data, err := io.ReadAll(httpRsp.Body)
if err != nil {
return fmt.Errorf("io: failed to read all: %w", err)
}
if err := os.WriteFile(p.Internal, data, 0o600); err != nil {
return fmt.Errorf("os: failed to write file: %w", err)
}
httpRsp.Body.Close()
}
}
return nil
}
// Clean remove unused config inside config dir
func (c *configReal) Clean() error {
unusedDirs, err := getUnusedDirs(c.Apps)