From d69c11a3144044f354af5c30fb5a9bb902939b96 Mon Sep 17 00:00:00 2001 From: simulot Date: Thu, 16 Nov 2023 21:37:19 +0100 Subject: [PATCH 1/4] move the logger package at root of the project --- cmdduplicate/duplicate.go | 2 +- cmdmetadata/metadatacmd.go | 2 +- cmdstack/cmdstack.go | 2 +- cmdtool/cmdalbum/cmdalbum.go | 2 +- cmdtool/cmdtool.go | 2 +- cmdupload/e2e_upload_folder_test.go | 63 ++++++++++++++++------------- cmdupload/upload.go | 36 ++++++++++++++++- cmdupload/upload_test.go | 2 +- go.mod | 2 +- helpers/fshelper/parseArgs.go | 12 ++++-- immich/immich.go | 2 - {immich/logger => logger}/logger.go | 0 main.go | 2 +- 13 files changed, 87 insertions(+), 42 deletions(-) rename {immich/logger => logger}/logger.go (100%) diff --git a/cmdduplicate/duplicate.go b/cmdduplicate/duplicate.go index 3aab1fa1..74857714 100644 --- a/cmdduplicate/duplicate.go +++ b/cmdduplicate/duplicate.go @@ -8,7 +8,7 @@ import ( "flag" "immich-go/helpers/gen" "immich-go/immich" - "immich-go/immich/logger" + "immich-go/logger" "immich-go/ui" "path" "sort" diff --git a/cmdmetadata/metadatacmd.go b/cmdmetadata/metadatacmd.go index f7045a4d..e1cb68d0 100644 --- a/cmdmetadata/metadatacmd.go +++ b/cmdmetadata/metadatacmd.go @@ -5,8 +5,8 @@ import ( "flag" "immich-go/helpers/docker" "immich-go/immich" - "immich-go/immich/logger" "immich-go/immich/metadata" + "immich-go/logger" "math" "path" "strings" diff --git a/cmdstack/cmdstack.go b/cmdstack/cmdstack.go index 7bdce7cc..95ecda8e 100644 --- a/cmdstack/cmdstack.go +++ b/cmdstack/cmdstack.go @@ -5,7 +5,7 @@ import ( "flag" "immich-go/helpers/stacking" "immich-go/immich" - "immich-go/immich/logger" + "immich-go/logger" "immich-go/ui" "path" "sort" diff --git a/cmdtool/cmdalbum/cmdalbum.go b/cmdtool/cmdalbum/cmdalbum.go index ce7f090a..ec2aa625 100644 --- a/cmdtool/cmdalbum/cmdalbum.go +++ b/cmdtool/cmdalbum/cmdalbum.go @@ -5,7 +5,7 @@ import ( "flag" "fmt" "immich-go/immich" - "immich-go/immich/logger" + "immich-go/logger" "immich-go/ui" "regexp" "sort" diff --git a/cmdtool/cmdtool.go b/cmdtool/cmdtool.go index 54b45f76..5b37e604 100644 --- a/cmdtool/cmdtool.go +++ b/cmdtool/cmdtool.go @@ -5,7 +5,7 @@ import ( "fmt" "immich-go/cmdtool/cmdalbum" "immich-go/immich" - "immich-go/immich/logger" + "immich-go/logger" ) func CommandTool(ctx context.Context, ic *immich.ImmichClient, logger *logger.Logger, args []string) error { diff --git a/cmdupload/e2e_upload_folder_test.go b/cmdupload/e2e_upload_folder_test.go index 1ab60737..8eace724 100644 --- a/cmdupload/e2e_upload_folder_test.go +++ b/cmdupload/e2e_upload_folder_test.go @@ -8,7 +8,7 @@ import ( "errors" "fmt" "immich-go/immich" - "immich-go/immich/logger" + "immich-go/logger" "testing" "time" @@ -39,35 +39,33 @@ func TestE2eUpload(t *testing.T) { resetImmich bool expectError bool }{ - /* - { - name: "upload google photos", - args: []string{ - "-google-photos", - "../../test-data/low_high/Takeout", - }, - resetImmich: true, - expectError: false, + { + name: "upload google photos", + args: []string{ + "-google-photos", + "../../test-data/low_high/Takeout", }, - { - name: "upload folder", - args: []string{ - "../../test-data/low_high/high", - }, - // resetImmich: true, - - expectError: false, + resetImmich: true, + expectError: false, + }, + { + name: "upload folder", + args: []string{ + "../../test-data/low_high/high", }, - { - name: "upload folder", - args: []string{ - "../../test-data/low_high/high", - }, - - // resetImmich: true, - expectError: false, + // resetImmich: true, + + expectError: false, + }, + { + name: "upload folder", + args: []string{ + "../../test-data/low_high/high", }, - */ + + // resetImmich: true, + expectError: false, + }, { name: "upload folder *.jpg", args: []string{ @@ -87,6 +85,17 @@ func TestE2eUpload(t *testing.T) { // resetImmich: true, expectError: false, }, + + { + name: "upload folder *.jpg - dry run", + args: []string{ + "-dry-run", + "../../test-data/full_takeout (copy)/Takeout/Google Photos/Photos from 2023", + }, + + // resetImmich: true, + expectError: false, + }, } logger := logger.NewLogger(logger.Debug, true, false) diff --git a/cmdupload/upload.go b/cmdupload/upload.go index 88c4f501..9e772c24 100644 --- a/cmdupload/upload.go +++ b/cmdupload/upload.go @@ -14,8 +14,8 @@ import ( "immich-go/helpers/gen" "immich-go/helpers/stacking" "immich-go/immich" - "immich-go/immich/logger" "immich-go/immich/metadata" + "immich-go/logger" "io/fs" "math" "path" @@ -62,6 +62,7 @@ type UpCmd struct { DryRun bool // Display actions but don't change anything ForceSidecar bool // Generate a sidecar file for each file (default: TRUE) CreateStacks bool // Stack jpg/raw/burst (Default: TRUE) + SelectTypes StringList // List of extensions to be imported AssetIndex *AssetIndex // List of assets present on the server deleteServerList []*immich.Asset // List of server assets to remove @@ -138,11 +139,32 @@ func NewUpCmd(ctx context.Context, ic iClient, log *logger.Logger, args []string "Stack jpg/raw or bursts (default TRUE)") // cmd.BoolVar(&app.Delete, "delete", false, "Delete local assets after upload") + + cmd.Var(&app.SelectTypes, "select-types", "list of selected extensions separated by a comma") + err = cmd.Parse(args) if err != nil { return nil, err } + if len(app.SelectTypes) > 0 { + l := []string{} + for _, e := range app.SelectTypes { + if !strings.HasPrefix(e, ".") { + e = "." + e + } + e = strings.ToLower(e) + if _, err = fshelper.MimeFromExt(e); err != nil { + err = errors.Join(err, fmt.Errorf("unsupported extension '%s'", e)) + } + l = append(l, e) + } + if err != nil { + return nil, err + } + app.SelectTypes = l + } + app.fsys, err = fshelper.ParsePath(cmd.Args(), app.GooglePhotos) if err != nil { return nil, err @@ -758,3 +780,15 @@ func keys[M ~map[K]V, K comparable, V any](m M) []K { } return r } + +type StringList []string + +func (sl *StringList) Set(s string) error { + l := strings.Split(s, ",") + (*sl) = append((*sl), l...) + return nil +} + +func (sl StringList) String() string { + return strings.Join(sl, ", ") +} diff --git a/cmdupload/upload_test.go b/cmdupload/upload_test.go index 8aad3978..3ca3aaac 100644 --- a/cmdupload/upload_test.go +++ b/cmdupload/upload_test.go @@ -7,7 +7,7 @@ import ( "immich-go/assets" "immich-go/helpers/gen" "immich-go/immich" - "immich-go/immich/logger" + "immich-go/logger" "reflect" "slices" "testing" diff --git a/go.mod b/go.mod index d970a2b4..f535cbad 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module immich-go -go 1.20 +go 1.21 require ( github.com/google/uuid v1.3.1 diff --git a/helpers/fshelper/parseArgs.go b/helpers/fshelper/parseArgs.go index a141d46b..289b94b5 100644 --- a/helpers/fshelper/parseArgs.go +++ b/helpers/fshelper/parseArgs.go @@ -61,11 +61,15 @@ func ParsePath(args []string, googlePhoto bool) ([]fs.FS, error) { } for pa, l := range p.paths { - f, err := newPathFS(pa, l) - if err != nil { - p.err = errors.Join(err) + if len(l) > 0 { + f, err := newPathFS(pa, l) + if err != nil { + p.err = errors.Join(err) + } else { + fsys = append(fsys, f) + } } else { - fsys = append(fsys, f) + fsys = append(fsys, os.DirFS(pa)) } } diff --git a/immich/immich.go b/immich/immich.go index 715e7d34..bf4c2332 100644 --- a/immich/immich.go +++ b/immich/immich.go @@ -76,8 +76,6 @@ func (l *List[T]) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &l.list) } -type StringList struct{ List[string] } - type myBool bool func (b myBool) String() string { diff --git a/immich/logger/logger.go b/logger/logger.go similarity index 100% rename from immich/logger/logger.go rename to logger/logger.go diff --git a/main.go b/main.go index 435bd5dd..8fdf1fdd 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ import ( "immich-go/cmdupload" "immich-go/helpers/tzone" "immich-go/immich" - "immich-go/immich/logger" + "immich-go/logger" "os" "os/signal" ) From a5bed00c5f13524e37eaf9839dce8b9ddb298603 Mon Sep 17 00:00:00 2001 From: simulot Date: Thu, 16 Nov 2023 22:46:10 +0100 Subject: [PATCH 2/4] implement nologger --- assets/files/localassets.go | 32 +++- assets/files/localassets_test.go | 3 +- assets/gp/googlephotos.go | 10 +- assets/gp/testgp_bigread_test.go | 3 +- assets/gp/testgp_test.go | 5 +- cmdduplicate/duplicate.go | 6 +- cmdmetadata/metadatacmd.go | 6 +- cmdstack/cmdstack.go | 6 +- cmdtool/cmdalbum/cmdalbum.go | 6 +- cmdtool/cmdtool.go | 2 +- cmdupload/e2e_upload_folder_test.go | 2 +- cmdupload/upload.go | 14 +- cmdupload/upload_test.go | 2 +- logger/log.go | 232 +++++++++++++++++++++++++++ logger/logger.go | 239 ++-------------------------- logger/nologger.go | 15 ++ main.go | 4 +- 17 files changed, 324 insertions(+), 263 deletions(-) create mode 100644 logger/log.go create mode 100644 logger/nologger.go diff --git a/assets/files/localassets.go b/assets/files/localassets.go index cbb9ef5a..eeee0243 100644 --- a/assets/files/localassets.go +++ b/assets/files/localassets.go @@ -3,7 +3,9 @@ package files import ( "context" "immich-go/assets" + "immich-go/helpers/fshelper" "immich-go/immich/metadata" + "immich-go/logger" "io/fs" "path" "path/filepath" @@ -14,12 +16,14 @@ import ( type LocalAssetBrowser struct { fsys fs.FS albums map[string]string + log logger.Logger } -func NewLocalFiles(ctx context.Context, fsys fs.FS) (*LocalAssetBrowser, error) { +func NewLocalFiles(ctx context.Context, fsys fs.FS, log logger.Logger) (*LocalAssetBrowser, error) { return &LocalAssetBrowser{ fsys: fsys, albums: map[string]string{}, + log: log, }, nil } @@ -54,6 +58,11 @@ func (la *LocalAssetBrowser) Browse(ctx context.Context) chan *assets.LocalAsset return nil } + ext := path.Ext(name) + if _, err := fshelper.MimeFromExt(strings.ToLower(ext)); err != nil { + return nil + } + la.log.Debug("file '%s'", name) f := assets.LocalAssetFile{ FSys: la.fsys, FileName: name, @@ -76,12 +85,8 @@ func (la *LocalAssetBrowser) Browse(ctx context.Context) chan *assets.LocalAsset f.DateTaken = time.Now() } } - _, err = fs.Stat(la.fsys, name+".xmp") - if err == nil { - f.SideCar = &metadata.SideCar{ - FileName: name + ".xmp", - OnFSsys: true, - } + if !la.checkSidecar(&f, name+".xmp") { + la.checkSidecar(&f, strings.TrimSuffix(name, ext)+".xmp") } } fileChan <- &f @@ -104,6 +109,19 @@ func (la *LocalAssetBrowser) Browse(ctx context.Context) chan *assets.LocalAsset return fileChan } +func (la *LocalAssetBrowser) checkSidecar(f *assets.LocalAssetFile, name string) bool { + _, err := fs.Stat(la.fsys, name+".xmp") + if err == nil { + la.log.Debug(" found sidecar: '%s'", name) + f.SideCar = &metadata.SideCar{ + FileName: name + ".xmp", + OnFSsys: true, + } + return true + } + return false +} + func (la *LocalAssetBrowser) addAlbum(dir string) { base := path.Base(dir) la.albums[dir] = base diff --git a/assets/files/localassets_test.go b/assets/files/localassets_test.go index f8973ab6..0dc0e5cf 100644 --- a/assets/files/localassets_test.go +++ b/assets/files/localassets_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "immich-go/assets/files" + "immich-go/logger" "path" "reflect" "sort" @@ -73,7 +74,7 @@ func TestLocalAssets(t *testing.T) { } ctx := context.Background() - b, err := files.NewLocalFiles(ctx, fsys) + b, err := files.NewLocalFiles(ctx, fsys, logger.NoLogger{}) if err != nil { t.Error(err) } diff --git a/assets/gp/googlephotos.go b/assets/gp/googlephotos.go index b055b1c6..f084f010 100644 --- a/assets/gp/googlephotos.go +++ b/assets/gp/googlephotos.go @@ -5,6 +5,7 @@ import ( "fmt" "immich-go/assets" "immich-go/helpers/fshelper" + "immich-go/logger" "io/fs" "path" "strings" @@ -16,6 +17,7 @@ type Takeout struct { filesByDir map[string][]fileKey // files name mapped by dir jsonByYear map[jsonKey]*GoogleMetaData // JSON by year of capture and full path albumsByDir map[string]assets.LocalAlbum // album title mapped by dir + log logger.Logger } type fileKey struct { @@ -31,12 +33,13 @@ type Album struct { Title string } -func NewTakeout(ctx context.Context, fsys fs.FS) (*Takeout, error) { +func NewTakeout(ctx context.Context, fsys fs.FS, log logger.Logger) (*Takeout, error) { to := Takeout{ fsys: fsys, filesByDir: map[string][]fileKey{}, jsonByYear: map[jsonKey]*GoogleMetaData{}, albumsByDir: map[string]assets.LocalAlbum{}, + log: log, } err := to.walk(ctx, fsys) @@ -49,6 +52,7 @@ func (to *Takeout) walk(ctx context.Context, fsys fs.FS) error { if err != nil { return err } + to.log.Debug("walk file '%s'", name) select { case <-ctx.Done(): // Check if the context has been cancelled @@ -116,10 +120,12 @@ func (to *Takeout) Browse(ctx context.Context) chan *assets.LocalAssetFile { go func() { defer close(c) for k, md := range to.jsonByYear { + to.log.Debug("Checking '%s', %d", k.name, k.year) assets := to.jsonAssets(k, md) for _, a := range assets { fk := fileKey{name: path.Base(a.FileName), size: int64(a.FileSize)} if _, exist := passed[fk]; !exist { + to.log.Debug(" associated with '%s'", fk.name) passed[fk] = nil select { case <-ctx.Done(): @@ -127,6 +133,8 @@ func (to *Takeout) Browse(ctx context.Context) chan *assets.LocalAssetFile { default: c <- a } + } else { + to.log.Debug(" associated with '%s', but already seen", fk.name) } } } diff --git a/assets/gp/testgp_bigread_test.go b/assets/gp/testgp_bigread_test.go index 0c2bb301..3176c5dc 100644 --- a/assets/gp/testgp_bigread_test.go +++ b/assets/gp/testgp_bigread_test.go @@ -6,6 +6,7 @@ package gp import ( "context" "immich-go/helpers/fshelper" + "immich-go/logger" "path/filepath" "testing" ) @@ -19,7 +20,7 @@ func TestReadBigTakeout(t *testing.T) { cnt := 0 fsyss, err := fshelper.ParsePath(m, true) for _, fsys := range fsyss { - to, err := NewTakeout(context.Background(), fsys) + to, err := NewTakeout(context.Background(), fsys, logger.NoLogger{}) if err != nil { t.Error(err) return diff --git a/assets/gp/testgp_test.go b/assets/gp/testgp_test.go index 0418f6ec..4de435bf 100644 --- a/assets/gp/testgp_test.go +++ b/assets/gp/testgp_test.go @@ -2,6 +2,7 @@ package gp import ( "context" + "immich-go/logger" "path" "reflect" "testing" @@ -85,7 +86,7 @@ func TestBrowse(t *testing.T) { } ctx := context.Background() - b, err := NewTakeout(ctx, fsys) + b, err := NewTakeout(ctx, fsys, logger.NoLogger{}) if err != nil { t.Error(err) } @@ -160,7 +161,7 @@ func TestAlbums(t *testing.T) { t.Error(fsys.err) return } - b, err := NewTakeout(ctx, fsys) + b, err := NewTakeout(ctx, fsys, logger.NoLogger{}) if err != nil { t.Error(err) } diff --git a/cmdduplicate/duplicate.go b/cmdduplicate/duplicate.go index 74857714..5377c42f 100644 --- a/cmdduplicate/duplicate.go +++ b/cmdduplicate/duplicate.go @@ -18,7 +18,7 @@ import ( ) type DuplicateCmd struct { - logger *logger.Logger + logger *logger.Log Immich *immich.ImmichClient // Immich client AssumeYes bool // When true, doesn't ask to the user @@ -34,7 +34,7 @@ type duplicateKey struct { Name string } -func NewDuplicateCmd(ctx context.Context, ic *immich.ImmichClient, logger *logger.Logger, args []string) (*DuplicateCmd, error) { +func NewDuplicateCmd(ctx context.Context, ic *immich.ImmichClient, logger *logger.Log, args []string) (*DuplicateCmd, error) { cmd := flag.NewFlagSet("duplicate", flag.ExitOnError) validRange := immich.DateRange{} validRange.Set("1850-01-04,2030-01-01") @@ -57,7 +57,7 @@ func NewDuplicateCmd(ctx context.Context, ic *immich.ImmichClient, logger *logge return &app, err } -func DuplicateCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Logger, args []string) error { +func DuplicateCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Log, args []string) error { app, err := NewDuplicateCmd(ctx, ic, log, args) if err != nil { return err diff --git a/cmdmetadata/metadatacmd.go b/cmdmetadata/metadatacmd.go index e1cb68d0..21cba3a9 100644 --- a/cmdmetadata/metadatacmd.go +++ b/cmdmetadata/metadatacmd.go @@ -15,14 +15,14 @@ import ( type MetadataCmd struct { Immich *immich.ImmichClient // Immich client - Log *logger.Logger + Log *logger.Log DryRun bool MissingDateDespiteName bool MissingDate bool DockerHost string } -func NewMetadataCmd(ctx context.Context, ic *immich.ImmichClient, logger *logger.Logger, args []string) (*MetadataCmd, error) { +func NewMetadataCmd(ctx context.Context, ic *immich.ImmichClient, logger *logger.Log, args []string) (*MetadataCmd, error) { var err error cmd := flag.NewFlagSet("metadata", flag.ExitOnError) app := MetadataCmd{ @@ -38,7 +38,7 @@ func NewMetadataCmd(ctx context.Context, ic *immich.ImmichClient, logger *logger return &app, err } -func MetadataCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Logger, args []string) error { +func MetadataCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Log, args []string) error { app, err := NewMetadataCmd(ctx, ic, log, args) if err != nil { return err diff --git a/cmdstack/cmdstack.go b/cmdstack/cmdstack.go index 95ecda8e..b9c3cd10 100644 --- a/cmdstack/cmdstack.go +++ b/cmdstack/cmdstack.go @@ -14,13 +14,13 @@ import ( type StackCmd struct { Immich *immich.ImmichClient // Immich client - logger *logger.Logger + logger *logger.Log AssumeYes bool DateRange immich.DateRange // Set capture date range } -func initSack(xtx context.Context, ic *immich.ImmichClient, log *logger.Logger, args []string) (*StackCmd, error) { +func initSack(xtx context.Context, ic *immich.ImmichClient, log *logger.Log, args []string) (*StackCmd, error) { cmd := flag.NewFlagSet("stack", flag.ExitOnError) validRange := immich.DateRange{} @@ -40,7 +40,7 @@ func initSack(xtx context.Context, ic *immich.ImmichClient, log *logger.Logger, err := cmd.Parse(args) return &app, err } -func NewStackCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Logger, args []string) error { +func NewStackCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Log, args []string) error { app, err := initSack(ctx, ic, log, args) if err != nil { return err diff --git a/cmdtool/cmdalbum/cmdalbum.go b/cmdtool/cmdalbum/cmdalbum.go index ec2aa625..de28abe1 100644 --- a/cmdtool/cmdalbum/cmdalbum.go +++ b/cmdtool/cmdalbum/cmdalbum.go @@ -12,7 +12,7 @@ import ( "strconv" ) -func AlbumCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Logger, args []string) error { +func AlbumCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Log, args []string) error { if len(args) > 0 { cmd := args[0] args = args[1:] @@ -26,13 +26,13 @@ func AlbumCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.Logg } type DeleteAlbumCmd struct { - log *logger.Logger + log *logger.Log Immich *immich.ImmichClient // Immich client pattern *regexp.Regexp // album pattern AssumeYes bool } -func deleteAlbum(ctx context.Context, ic *immich.ImmichClient, log *logger.Logger, args []string) error { +func deleteAlbum(ctx context.Context, ic *immich.ImmichClient, log *logger.Log, args []string) error { app := &DeleteAlbumCmd{ log: log, Immich: ic, diff --git a/cmdtool/cmdtool.go b/cmdtool/cmdtool.go index 5b37e604..e5aa0d9b 100644 --- a/cmdtool/cmdtool.go +++ b/cmdtool/cmdtool.go @@ -8,7 +8,7 @@ import ( "immich-go/logger" ) -func CommandTool(ctx context.Context, ic *immich.ImmichClient, logger *logger.Logger, args []string) error { +func CommandTool(ctx context.Context, ic *immich.ImmichClient, logger *logger.Log, args []string) error { if len(args) > 0 { cmd := args[0] args = args[1:] diff --git a/cmdupload/e2e_upload_folder_test.go b/cmdupload/e2e_upload_folder_test.go index 8eace724..17598f61 100644 --- a/cmdupload/e2e_upload_folder_test.go +++ b/cmdupload/e2e_upload_folder_test.go @@ -98,7 +98,7 @@ func TestE2eUpload(t *testing.T) { }, } - logger := logger.NewLogger(logger.Debug, true, false) + logger := logger.NoLogger{} ic, err := immich.NewImmichClient(host, key) if err != nil { diff --git a/cmdupload/upload.go b/cmdupload/upload.go index 9e772c24..1b740852 100644 --- a/cmdupload/upload.go +++ b/cmdupload/upload.go @@ -39,9 +39,9 @@ type iClient interface { } type UpCmd struct { - client iClient // Immich client - log *logger.Logger // Application loader - fsys []fs.FS // pseudo file system to browse + client iClient // Immich client + log logger.Logger // Application loader + fsys []fs.FS // pseudo file system to browse Recursive bool // Explore sub folders GooglePhotos bool // For reading Google Photos takeout files @@ -73,7 +73,7 @@ type UpCmd struct { stacks *stacking.StackBuilder } -func NewUpCmd(ctx context.Context, ic iClient, log *logger.Logger, args []string) (*UpCmd, error) { +func NewUpCmd(ctx context.Context, ic iClient, log logger.Logger, args []string) (*UpCmd, error) { var err error cmd := flag.NewFlagSet("upload", flag.ExitOnError) @@ -196,7 +196,7 @@ func NewUpCmd(ctx context.Context, ic iClient, log *logger.Logger, args []string } -func UploadCommand(ctx context.Context, ic iClient, log *logger.Logger, args []string) error { +func UploadCommand(ctx context.Context, ic iClient, log logger.Logger, args []string) error { app, err := NewUpCmd(ctx, ic, log, args) if err != nil { return err @@ -413,11 +413,11 @@ func (app *UpCmd) isInAlbum(a *assets.LocalAssetFile, album string) bool { func (a *UpCmd) ReadGoogleTakeOut(ctx context.Context, fsys fs.FS) (assets.Browser, error) { a.Delete = false - return gp.NewTakeout(ctx, fsys) + return gp.NewTakeout(ctx, fsys, a.log) } func (a *UpCmd) ExploreLocalFolder(ctx context.Context, fsys fs.FS) (assets.Browser, error) { - return files.NewLocalFiles(ctx, fsys) + return files.NewLocalFiles(ctx, fsys, a.log) } // UploadAsset upload the asset on the server diff --git a/cmdupload/upload_test.go b/cmdupload/upload_test.go index 3ca3aaac..214b5dd7 100644 --- a/cmdupload/upload_test.go +++ b/cmdupload/upload_test.go @@ -336,7 +336,7 @@ func TestUpload(t *testing.T) { ic := &icCatchUploadsAssets{ albums: map[string][]string{}, } - log := logger.NewLogger(logger.OK, false, false).Writer(nil) + log := logger.NoLogger{} ctx := context.Background() app, err := NewUpCmd(ctx, ic, log, tc.args) diff --git a/logger/log.go b/logger/log.go new file mode 100644 index 00000000..ca4a3aae --- /dev/null +++ b/logger/log.go @@ -0,0 +1,232 @@ +package logger + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "os" + "strings" + + "github.com/ttacon/chalk" +) + +type Level int + +const ( + Fatal Level = iota + Error + Warning + OK + Info + Debug +) + +func (l Level) String() string { + switch l { + case Fatal: + return "Fatal" + case Error: + return "Error" + case Warning: + return "Warning" + case OK: + return "OK" + case Info: + return "Info" + case Debug: + return "Debug" + default: + return fmt.Sprintf("Log Level %d", l) + } +} + +func StringToLevel(s string) (Level, error) { + s = strings.ToLower(s) + for l := Fatal; l <= Debug; l++ { + if strings.ToLower(l.String()) == s { + return l, nil + } + } + return Error, fmt.Errorf("unknown log level: %s", s) +} + +var colorLevel = map[Level]string{ + Fatal: chalk.Red.String(), + Error: chalk.Red.String(), + Warning: chalk.Yellow.String(), + OK: chalk.Green.String(), + Info: chalk.White.String(), + Debug: chalk.Cyan.String(), +} + +type Log struct { + needCR bool + needSpace bool + displayLevel Level + noColors bool + colorStrings map[Level]string + debug bool + out io.Writer +} + +func NewLogger(DisplayLevel Level, noColors bool, debug bool) *Log { + l := Log{ + displayLevel: DisplayLevel, + noColors: noColors, + colorStrings: map[Level]string{}, + debug: debug, + out: os.Stdout, + } + if !noColors { + l.colorStrings = colorLevel + } + return &l +} + +func (l *Log) Writer(w io.Writer) *Log { + if l != nil { + l.out = w + } + return l +} + +func (l *Log) Debug(f string, v ...any) { + if l == nil || l.out == nil { + return + } + l.Message(Debug, f, v...) +} + +type DebugObject interface { + DebugObject() any +} + +func (l *Log) DebugObject(name string, v any) { + if l == nil || !l.debug { + return + } + if l.out == nil { + return + } + if d, ok := v.(DebugObject); ok { + v = d.DebugObject() + } + b := bytes.NewBuffer(nil) + enc := json.NewEncoder(b) + enc.SetIndent("", " ") + err := enc.Encode(v) + if err != nil { + l.Error("can't display object %s: %s", name, err) + return + } + if l.needCR { + fmt.Println() + l.needCR = false + } + l.needSpace = false + fmt.Fprint(l.out, l.colorStrings[Debug]) + fmt.Fprintf(l.out, "%s:\n%s", name, b.String()) + if !l.noColors { + fmt.Fprint(l.out, chalk.ResetColor) + } + fmt.Fprintln(l.out) +} +func (l *Log) Info(f string, v ...any) { + if l == nil || l.out == nil { + return + } + l.Message(Info, f, v...) +} +func (l *Log) OK(f string, v ...any) { + if l == nil || l.out == nil { + return + } + l.Message(OK, f, v...) +} +func (l *Log) Warning(f string, v ...any) { + if l == nil || l.out == nil { + return + } + l.Message(Warning, f, v...) +} +func (l *Log) Error(f string, v ...any) { + if l == nil || l.out == nil { + return + } + l.Message(Error, f, v...) +} +func (l *Log) Fatal(f string, v ...any) { + if l == nil || l.out == nil { + return + } + l.Message(Fatal, f, v...) +} + +func (l *Log) Message(level Level, f string, v ...any) { + if l == nil || l.out == nil { + return + } + if level > l.displayLevel { + return + } + if l.needCR { + fmt.Fprintln(l.out) + l.needCR = false + } + l.needSpace = false + fmt.Fprint(l.out, l.colorStrings[level]) + fmt.Fprintf(l.out, f, v...) + if !l.noColors { + fmt.Fprint(l.out, chalk.ResetColor) + } + fmt.Fprintln(l.out) +} + +func (l *Log) Progress(level Level, f string, v ...any) { + if l == nil || l.out == nil { + return + } + if level > l.displayLevel { + return + } + fmt.Fprintf(l.out, "\r\033[2K"+f, v...) + l.needCR = true +} + +func (l *Log) MessageContinue(level Level, f string, v ...any) { + if l == nil || l.out == nil { + return + } + if level > l.displayLevel { + return + } + if l.needCR { + fmt.Fprintln(l.out) + l.needCR = false + } + if l.needSpace { + fmt.Print(" ") + } + fmt.Fprint(l.out, l.colorStrings[level]) + fmt.Fprintf(l.out, f, v...) + l.needSpace = true + l.needCR = false +} + +func (l *Log) MessageTerminate(level Level, f string, v ...any) { + if l == nil || l.out == nil { + return + } + if level > l.displayLevel { + return + } + fmt.Fprint(l.out, l.colorStrings[level]) + fmt.Fprintf(l.out, f, v...) + if !l.noColors { + fmt.Fprint(l.out, chalk.ResetColor) + } + fmt.Fprintln(l.out) + l.needSpace = false + l.needCR = false +} diff --git a/logger/logger.go b/logger/logger.go index 76659ecc..4f204ea0 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -1,230 +1,15 @@ package logger -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "os" - "strings" - - "github.com/ttacon/chalk" -) - -type Level int - -const ( - Fatal Level = iota - Error - Warning - OK - Info - Debug -) - -func (l Level) String() string { - switch l { - case Fatal: - return "Fatal" - case Error: - return "Error" - case Warning: - return "Warning" - case OK: - return "OK" - case Info: - return "Info" - case Debug: - return "Debug" - default: - return fmt.Sprintf("Log Level %d", l) - } -} - -func StringToLevel(s string) (Level, error) { - s = strings.ToLower(s) - for l := Fatal; l <= Debug; l++ { - if strings.ToLower(l.String()) == s { - return l, nil - } - } - return Error, fmt.Errorf("unknown log level: %s", s) -} - -var colorLevel = map[Level]string{ - Fatal: chalk.Red.String(), - Error: chalk.Red.String(), - Warning: chalk.Yellow.String(), - OK: chalk.Green.String(), - Info: chalk.White.String(), - Debug: chalk.Cyan.String(), -} - -type Logger struct { - needCR bool - needSpace bool - displayLevel Level - noColors bool - colorStrings map[Level]string - debug bool - out io.Writer -} - -func NewLogger(DisplayLevel Level, noColors bool, debug bool) *Logger { - l := Logger{ - displayLevel: DisplayLevel, - noColors: noColors, - colorStrings: map[Level]string{}, - debug: debug, - out: os.Stdout, - } - if !noColors { - l.colorStrings = colorLevel - } - return &l -} - -func (l *Logger) Writer(w io.Writer) *Logger { - l.out = w - return l -} - -func (l *Logger) Debug(f string, v ...any) { - if l.out == nil { - return - } - l.Message(Debug, f, v...) -} - -type DebugObject interface { - DebugObject() any -} - -func (l *Logger) DebugObject(name string, v any) { - if !l.debug { - return - } - if l.out == nil { - return - } - if d, ok := v.(DebugObject); ok { - v = d.DebugObject() - } - b := bytes.NewBuffer(nil) - enc := json.NewEncoder(b) - enc.SetIndent("", " ") - err := enc.Encode(v) - if err != nil { - l.Error("can't display object %s: %s", name, err) - return - } - if l.needCR { - fmt.Println() - l.needCR = false - } - l.needSpace = false - fmt.Fprint(l.out, l.colorStrings[Debug]) - fmt.Fprintf(l.out, "%s:\n%s", name, b.String()) - if !l.noColors { - fmt.Fprint(l.out, chalk.ResetColor) - } - fmt.Fprintln(l.out) -} -func (l *Logger) Info(f string, v ...any) { - if l.out == nil { - return - } - l.Message(Info, f, v...) -} -func (l *Logger) OK(f string, v ...any) { - if l.out == nil { - return - } - l.Message(OK, f, v...) -} -func (l *Logger) Warning(f string, v ...any) { - if l.out == nil { - return - } - l.Message(Warning, f, v...) -} -func (l *Logger) Error(f string, v ...any) { - if l.out == nil { - return - } - l.Message(Error, f, v...) -} -func (l *Logger) Fatal(f string, v ...any) { - if l.out == nil { - return - } - l.Message(Fatal, f, v...) -} - -func (l *Logger) Message(level Level, f string, v ...any) { - if l.out == nil { - return - } - if level > l.displayLevel { - return - } - if l.needCR { - fmt.Fprintln(l.out) - l.needCR = false - } - l.needSpace = false - fmt.Fprint(l.out, l.colorStrings[level]) - fmt.Fprintf(l.out, f, v...) - if !l.noColors { - fmt.Fprint(l.out, chalk.ResetColor) - } - fmt.Fprintln(l.out) -} - -func (l *Logger) Progress(level Level, f string, v ...any) { - if l.out == nil { - return - } - if level > l.displayLevel { - return - } - fmt.Fprintf(l.out, "\r\033[2K"+f, v...) - l.needCR = true -} - -func (l *Logger) MessageContinue(level Level, f string, v ...any) { - if l.out == nil { - return - } - if level > l.displayLevel { - return - } - if l.needCR { - fmt.Fprintln(l.out) - l.needCR = false - } - if l.needSpace { - fmt.Print(" ") - } - fmt.Fprint(l.out, l.colorStrings[level]) - fmt.Fprintf(l.out, f, v...) - l.needSpace = true - l.needCR = false -} - -func (l *Logger) MessageTerminate(level Level, f string, v ...any) { - if l.out == nil { - return - } - if level > l.displayLevel { - return - } - fmt.Fprint(l.out, l.colorStrings[level]) - fmt.Fprintf(l.out, f, v...) - if !l.noColors { - fmt.Fprint(l.out, chalk.ResetColor) - } - fmt.Fprintln(l.out) - l.needSpace = false - l.needCR = false +type Logger interface { + Debug(f string, v ...any) + DebugObject(name string, v any) + Info(f string, v ...any) + OK(f string, v ...any) + Warning(f string, v ...any) + Error(f string, v ...any) + Fatal(f string, v ...any) + Message(level Level, f string, v ...any) + Progress(level Level, f string, v ...any) + MessageContinue(level Level, f string, v ...any) + MessageTerminate(level Level, f string, v ...any) } diff --git a/logger/nologger.go b/logger/nologger.go new file mode 100644 index 00000000..ec379b4b --- /dev/null +++ b/logger/nologger.go @@ -0,0 +1,15 @@ +package logger + +type NoLogger struct{} + +func (NoLogger) Debug(f string, v ...any) {} +func (NoLogger) DebugObject(name string, v any) {} +func (NoLogger) Info(f string, v ...any) {} +func (NoLogger) OK(f string, v ...any) {} +func (NoLogger) Warning(f string, v ...any) {} +func (NoLogger) Error(f string, v ...any) {} +func (NoLogger) Fatal(f string, v ...any) {} +func (NoLogger) Message(level Level, f string, v ...any) {} +func (NoLogger) Progress(level Level, f string, v ...any) {} +func (NoLogger) MessageContinue(level Level, f string, v ...any) {} +func (NoLogger) MessageTerminate(level Level, f string, v ...any) {} diff --git a/main.go b/main.go index 8fdf1fdd..b4d13808 100644 --- a/main.go +++ b/main.go @@ -64,11 +64,11 @@ type Application struct { Debug bool // Enable the debug mode Immich *immich.ImmichClient // Immich client - Logger *logger.Logger // Program's logger + Logger *logger.Log // Program's logger } -func Run(ctx context.Context, log *logger.Logger) (*logger.Logger, error) { +func Run(ctx context.Context, log *logger.Log) (*logger.Log, error) { var err error deviceID, err := os.Hostname() if err != nil { From df77d9b4731e3142ca46632d10423dc7e2d81633 Mon Sep 17 00:00:00 2001 From: simulot Date: Thu, 16 Nov 2023 23:33:12 +0100 Subject: [PATCH 3/4] wip #69 --- immich/metadata/search.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/immich/metadata/search.go b/immich/metadata/search.go index ecf1a3be..a19716c4 100644 --- a/immich/metadata/search.go +++ b/immich/metadata/search.go @@ -30,11 +30,11 @@ func searchPattern(r io.Reader, pattern []byte, maxDataLen int) ([]byte, error) } ofs = index } else { - ofs = bytesRead - maxDataLen - 1 + ofs = max(bytesRead-maxDataLen-1, 0) } // Check if end of file is reached - if err == io.EOF { + if err == io.EOF || ofs > bytesRead { break } From c62e7a06f50f81e5e82d5758159246756fdfa85b Mon Sep 17 00:00:00 2001 From: simulot Date: Fri, 17 Nov 2023 00:05:00 +0100 Subject: [PATCH 4/4] add trimpath to goreleaser.ymal --- .goreleaser.yaml | 2 ++ go.sum | 1 + 2 files changed, 3 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index aa892a3c..80d7835c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -20,6 +20,8 @@ builds: - amd64 - arm - arm64 + flags: + - -trimpath ldflags: - '-s -w "-extldflags=-static" -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser' diff --git a/go.sum b/go.sum index 43a0b18d..06265513 100644 --- a/go.sum +++ b/go.sum @@ -76,6 +76,7 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=