Skip to content

Commit

Permalink
Improve debug mode and config handling.
Browse files Browse the repository at this point in the history
- config from CLI and file are now correctly merged
- debug output can be enabled with -debug
- config is now in its own file
  • Loading branch information
Björn Mosler committed Jan 10, 2023
1 parent cce4c95 commit 57d3960
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 82 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ darwin-bin:
windows-bin:
GOOS=windows go build -ldflags "-s -w" -o bin/booxsync-windows-amd64.exe cmd/booxsync/main.go
run:
go run cmd/booxsync/main.go
go run cmd/booxsync/main.go -debug
clean:
rm -rf bin
test:
Expand Down
23 changes: 14 additions & 9 deletions cmd/booxsync/main.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
package main

import (
"fmt"
"log"

"github.com/bjorm/booxsync/pkg/booxsync"
log "github.com/sirupsen/logrus"
"strings"
)

func main() {
config, err := booxsync.GetConfig()

if err != nil {
panic(fmt.Sprintf("invalid config: %s", err))
log.Infof("invalid config: %s", err)
return
}

log.Printf("syncing %s to %s", config.SyncRoot, config.Host)
log.Infof("syncing %s to %s", config.SyncRoot, config.Host)

uploadedFiles, err := booxsync.Sync(*config)
uploadedFiles, err := booxsync.Sync(config)

if err != nil {
panic(fmt.Sprintf("sync failed: %s", err))
log.Infof("sync failed: %s", err)
return
}

log.Printf("uploaded files: %s", uploadedFiles)
if len(uploadedFiles) > 0 {
log.Infof("uploaded files:\n%s", strings.Join(uploadedFiles, "\n"))
} else {
log.Infoln("nothing uploaded")
}

log.Println("sync complete")
log.Infoln("sync complete")
}
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ module github.com/bjorm/booxsync

go 1.18

require github.com/stretchr/testify v1.8.1
require (
github.com/imdario/mergo v0.3.13
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
65 changes: 35 additions & 30 deletions pkg/booxsync/boox.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"bytes"
"encoding/json"
"fmt"
log "github.com/sirupsen/logrus"
"io"
"io/fs"
"log"
"mime/multipart"
"net/http"
"net/url"
Expand All @@ -17,7 +17,7 @@ import (
)

const (
API_PATH = "/api/library"
ApiPath = "/api/library"
)

type BooxFile struct {
Expand All @@ -40,6 +40,10 @@ type libraryJson struct {
VisibleBookList []visibleBookJson `json:"visibleBookList"`
}

type libraryApiArgs struct {
LibraryUniqueId string `json:"libraryUniqueId"`
}

type visibleLibraryJson struct {
IdString string `json:"idString"`
Name string `json:"name"`
Expand Down Expand Up @@ -107,7 +111,7 @@ func (library *BooxLibrary) GetParentId(name string) (string, error) {

func (library *BooxLibrary) CreateFolder(name string, parent *BooxFile) error {
if library.Config.DryRun {
log.Printf("pretending to create folder %q", path.Join(parent.Name, name))
log.Debugf("pretending to create folder %q", path.Join(parent.Name, name))
parent.Children = append(parent.Children, &BooxFile{Name: name, Id: "dryRun", IsDir: true})
return nil
}
Expand All @@ -123,7 +127,7 @@ func (library *BooxLibrary) CreateFolder(name string, parent *BooxFile) error {
return fmt.Errorf("createFolder: marshal failed: %w", err)
}

response, err := http.Post(fmt.Sprintf("%s%s", library.Config.Host, API_PATH), "application/json", bytes.NewReader(body))
response, err := http.Post(library.Config.syncUrl.JoinPath(ApiPath).String(), "application/json", bytes.NewReader(body))

if err != nil || response.StatusCode != 200 {
return fmt.Errorf("createFolder: API call failed: %w", err)
Expand All @@ -150,7 +154,7 @@ func (library *BooxLibrary) CreateFolder(name string, parent *BooxFile) error {

func (library *BooxLibrary) Upload(localPath string, parent *BooxFile) error {
if library.Config.DryRun {
log.Printf("pretending to upload file %q", localPath)
log.Debugf("pretending to upload file %q", localPath)
return nil
}

Expand Down Expand Up @@ -190,7 +194,7 @@ func (library *BooxLibrary) Upload(localPath string, parent *BooxFile) error {
return fmt.Errorf("upload: closing form writer failed: %w", err)
}

response, err := http.Post(fmt.Sprintf("%s/api/library/upload", library.Config.Host), formWriter.FormDataContentType(), body)
response, err := http.Post(library.Config.syncUrl.JoinPath("/api/library/upload").String(), formWriter.FormDataContentType(), body)

if err != nil || response.StatusCode != 200 {
return fmt.Errorf("upload: http request failed: %w", err)
Expand All @@ -199,28 +203,20 @@ func (library *BooxLibrary) Upload(localPath string, parent *BooxFile) error {
return nil
}

func (library *BooxLibrary) PrintFileTree(stopAt int) {
printSubTree(library.Root, 0, stopAt)
log.Println()
}

func printSubTree(file *BooxFile, level int, stopAt int) {
if level == stopAt {
return
}

for _, child := range file.Children {
log.Println(strings.Repeat("\t", level), child.Name)
printSubTree(child, level+1, stopAt)
}
func buildWalkUrl(visibleLibrary visibleLibraryJson, config *SyncConfig) *url.URL {
query := url.Values{}
args := libraryApiArgs{LibraryUniqueId: visibleLibrary.IdString}
argsBytes, _ := json.Marshal(args)
query.Add("args", string(argsBytes))
requestUrl := config.syncUrl.JoinPath(ApiPath)
requestUrl.RawQuery = query.Encode()
return requestUrl
}

func walk(visibleLibrary visibleLibraryJson, config *SyncConfig) (*BooxFile, error) {
query := url.Values{}
// TODO fixme
query.Add("args", fmt.Sprintf("{\"libraryUniqueId\":\"%s\"}", visibleLibrary.IdString))

response, err := http.Get(fmt.Sprintf("%s%s?%s", config.Host, API_PATH, query.Encode()))
requestUrl := buildWalkUrl(visibleLibrary, config)
log.Debugf("reading library %q at %s", visibleLibrary.Name, requestUrl)
response, err := http.Get(requestUrl.String())

if err != nil {
return nil, fmt.Errorf("walk: http request failed: %w", err)
Expand Down Expand Up @@ -255,29 +251,38 @@ func walk(visibleLibrary visibleLibraryJson, config *SyncConfig) (*BooxFile, err
folder.Children = append(folder.Children, child)
}

if log.IsLevelEnabled(log.DebugLevel) {
var children []string
for _, child := range folder.Children {
children = append(children, child.Name)
}
log.Debugf("library %q contains\n%s", folder.Name, strings.Join(children, "', '"))
}

return &folder, nil
}

func GetBooxLibrary(config *SyncConfig) (*BooxLibrary, error) {
response, err := http.Get(fmt.Sprintf("%s%s", config.Host, API_PATH))
requestUrl := config.syncUrl.JoinPath(ApiPath).String()
response, err := http.Get(requestUrl)
if err != nil {
return nil, fmt.Errorf("getBooxLibrary: API call failed: %w", err)
return nil, fmt.Errorf("read library: API call failed: %w", err)
}

var rootLibrary visibleLibraryJson
body, err := io.ReadAll(response.Body)
if err != nil {
return nil, fmt.Errorf("getBooxLibrary: failed to read body: %w", err)
return nil, fmt.Errorf("read library: failed to read body: %w", err)
}

err = json.Unmarshal(body, &rootLibrary)
if err != nil {
return nil, fmt.Errorf("getBooxLibrary: unmarshalling failed: %w", err)
return nil, fmt.Errorf("read library: unmarshalling failed: %w", err)
}

root, err := walk(rootLibrary, config)
if err != nil {
return nil, fmt.Errorf("getBooxLibrary: walking library failed: %w", err)
return nil, fmt.Errorf("read library: walking library failed: %w", err)
}

return &BooxLibrary{Root: root, Config: config}, nil
Expand Down
101 changes: 101 additions & 0 deletions pkg/booxsync/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package booxsync

import (
"encoding/json"
"errors"
"flag"
"fmt"
"github.com/imdario/mergo"
log "github.com/sirupsen/logrus"
"io/fs"
"net/url"
"os"
)

const (
configFilePath = "./config.json"
)

type SyncConfig struct {
Host string
SyncRoot string
PathsToSkip []string
DryRun bool
Debug bool
syncUrl url.URL
}

func getCmdLineConfig() SyncConfig {
dryRun := flag.Bool("dry-run", false, "do everything except write to Boox library")
debug := flag.Bool("debug", false, "enabled debug output")
host := flag.String("host", "", "host to sync against")
syncRoot := flag.String("sync-root", "", "path of folder to sync")

log.Debug("parsing commandline flags")
flag.Parse()

return SyncConfig{DryRun: *dryRun, Host: *host, SyncRoot: *syncRoot, Debug: *debug}
}

func getFileConfig() (SyncConfig, error) {
if _, err := os.Stat(configFilePath); errors.Is(err, fs.ErrNotExist) {
log.Debugf("config file %q does not exist", configFilePath)
return SyncConfig{}, nil
}

b, err := os.ReadFile(configFilePath)

if err != nil {
return SyncConfig{}, fmt.Errorf("config: could not open file: %w", err)
}

log.Debugf("config file %q exists", configFilePath)
var config SyncConfig

err = json.Unmarshal(b, &config)
log.Debugf("read config: %v", config)

if err != nil {
return SyncConfig{}, fmt.Errorf("config: unmarshalling failed: %w", err)
}

return config, nil
}

func checkConfig(config SyncConfig) error {
if len(config.Host) == 0 {
return fmt.Errorf("check config: host cannot be empty")
}
if _, err := os.Stat(config.SyncRoot); errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("check config: sync root %q does not exist", config.SyncRoot)
}
return nil
}

func GetConfig() (SyncConfig, error) {
cmdLineConfig := getCmdLineConfig()
config, err := getFileConfig()

if err != nil {
return SyncConfig{}, err
}

if config.Debug || cmdLineConfig.Debug {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.TextFormatter{FullTimestamp: true})
log.Debug("debug mode enabled")
}

log.Debugf("command line config %#v", cmdLineConfig)
log.Debugf("file config %#v", config)

err = mergo.Merge(&config, cmdLineConfig, mergo.WithOverride)

if err = checkConfig(config); err == nil {
config.syncUrl = url.URL{Scheme: "http", Host: fmt.Sprintf("%s:%d", config.Host, 8085)}
log.Debugf("final config %#v", config)
return config, nil
} else {
return SyncConfig{}, err
}
}
Loading

0 comments on commit 57d3960

Please sign in to comment.