mirror of
https://github.com/derfenix/photocatalog.git
synced 2026-03-11 21:35:34 +03:00
Compare commits
2 Commits
v2.0.0-alp
...
62ca9f2378
| Author | SHA1 | Date | |
|---|---|---|---|
| 62ca9f2378 | |||
| f73d612666 |
22
README.md
22
README.md
@@ -19,7 +19,7 @@ structure for that files.
|
||||
|
||||
## Installing
|
||||
```bash
|
||||
go install github.com/derfenix/photocatalog@latest
|
||||
go install github.com/derfenix/photocatalog/v2@latest
|
||||
```
|
||||
Optionally you could copy created binary from the GO's bin path to
|
||||
system or user $PATH, e.g. /usr/local/bin/.
|
||||
@@ -27,6 +27,10 @@ system or user $PATH, e.g. /usr/local/bin/.
|
||||
sudo cp ${GOPATH}/bin/photocatalog /usr/local/bin/photocatalog
|
||||
```
|
||||
|
||||
## Migrating from v0.*
|
||||
|
||||
TODO
|
||||
|
||||
## Supported formats
|
||||
At this moment supported jpeg files with filled exif data or any other
|
||||
files but with names matching pattern `yyymmdd_HHMMSS.ext`. Such
|
||||
@@ -40,31 +44,31 @@ at this time.
|
||||
### One-shot
|
||||
#### Copy files (make a COW if fs supports it)
|
||||
```bash
|
||||
photocalog -mode copy -target ./photos/ ./sync/photos/*
|
||||
photocalog -mode copy -target ./photos/ -source ./sync/photos/
|
||||
```
|
||||
|
||||
#### Create hardlinks (only withing one disk partition)
|
||||
```bash
|
||||
photocalog -mode hardlink -target ./photos/ ./sync/photos/*
|
||||
photocalog -mode hardlink -target ./photos/ -source ./sync/photos/
|
||||
```
|
||||
or
|
||||
```bash
|
||||
photocalog -target ./photos/ ./sync/photos/*
|
||||
photocalog -target ./photos/ -source ./sync/photos/*
|
||||
```
|
||||
|
||||
### Monitor
|
||||
### Watch mode
|
||||
#### Copy files (make a COW if fs supports it)
|
||||
```bash
|
||||
photocalog -mode copy -target ./photos -monitor ./sync/photos/*
|
||||
photocalog -mode copy -target ./photos -watch -source ./sync/photos/
|
||||
```
|
||||
|
||||
#### Create hardlinks (only withing one disk partition)
|
||||
```bash
|
||||
photocalog -mode hardlink -target ./photos/ -monitor ./sync/photos/
|
||||
photocalog -mode hardlink -target ./photos/ -watch -source ./sync/photos/
|
||||
```
|
||||
or
|
||||
```bash
|
||||
photocalog -target ./photos/ -monitor ./sync/photos/
|
||||
photocalog -target ./photos/ -watch -source ./sync/photos/
|
||||
```
|
||||
|
||||
## Install and run monitor service
|
||||
@@ -89,6 +93,6 @@ under corresponding sub-dir.
|
||||
|
||||
### Why this tool was created if there is awesome XXX tool?
|
||||
I had two good reasons:
|
||||
1. I wanted
|
||||
1. I wish
|
||||
2. I can
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ func (c *Config) Validate() error {
|
||||
return fmt.Errorf("target dir is required")
|
||||
}
|
||||
|
||||
if !slices.Contains([]Mode{ModeHardlink, ModeSymlink, ModeMove, ModeSymlink}, c.Mode) {
|
||||
if !slices.Contains([]Mode{ModeHardlink, ModeSymlink, ModeMove, ModeCopy}, c.Mode) {
|
||||
return fmt.Errorf("invalid mode %s", c.Mode)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,18 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var cowDisabled = atomic.Bool{}
|
||||
|
||||
type Copy struct{}
|
||||
|
||||
func (c Copy) PlaceIt(sourcePath, targetPath string, mode os.FileMode) error {
|
||||
targetFile, err := os.OpenFile(targetPath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, mode)
|
||||
targetFile, err := os.OpenFile(targetPath, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, mode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open target file: %w", err)
|
||||
}
|
||||
@@ -28,6 +34,17 @@ func (c Copy) PlaceIt(sourcePath, targetPath string, mode os.FileMode) error {
|
||||
_ = sourceFile.Close()
|
||||
}()
|
||||
|
||||
// Try to do a COW.
|
||||
if runtime.GOOS == "linux" && !cowDisabled.Load() {
|
||||
if err := unix.IoctlFileClone(int(targetFile.Fd()+1), int(sourceFile.Fd())); err == nil {
|
||||
return nil
|
||||
} else {
|
||||
log.Println(fmt.Errorf("COW attempt for %s failed: %w", targetPath, err))
|
||||
log.Println("Disabling COW until restart")
|
||||
cowDisabled.Store(true)
|
||||
}
|
||||
}
|
||||
|
||||
copySize, err := io.Copy(targetFile, sourceFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("copy source file: %w", err)
|
||||
|
||||
@@ -268,6 +268,7 @@ func (o *Organizer) BuildTargetPath(sourcePath string, meta metadata.Metadata) (
|
||||
o.targetDir,
|
||||
strconv.Itoa(meta.Created.Year()),
|
||||
strconv.Itoa(int(meta.Created.Month())),
|
||||
strconv.Itoa(meta.Created.Day()),
|
||||
sourcePath,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user