added proton drive integration
This commit is contained in:
+35
-23
@@ -53,15 +53,17 @@ func (s *stringSlice) Set(v string) error {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
InputPath string
|
||||
OutputPath string
|
||||
AppendMode bool
|
||||
SingleFile bool
|
||||
MaxSize int64
|
||||
MaxDepth int
|
||||
Ignores []string
|
||||
Extensions []string
|
||||
AbsRoot string
|
||||
InputPath string
|
||||
OutputPath string
|
||||
AppendMode bool
|
||||
SingleFile bool
|
||||
MaxSize int64
|
||||
MaxDepth int
|
||||
Ignores []string
|
||||
Extensions []string
|
||||
AbsRoot string
|
||||
ProtonDrive bool
|
||||
DrivePath string
|
||||
}
|
||||
|
||||
func PrintUsage() {
|
||||
@@ -74,14 +76,16 @@ func PrintUsage() {
|
||||
|
||||
func Parse() (*Config, error) {
|
||||
var (
|
||||
input string
|
||||
output string
|
||||
appendMd bool
|
||||
maxSize int64
|
||||
maxDepth int
|
||||
ignores stringSlice
|
||||
exts stringSlice
|
||||
showVer bool
|
||||
input string
|
||||
output string
|
||||
appendMd bool
|
||||
maxSize int64
|
||||
maxDepth int
|
||||
ignores stringSlice
|
||||
exts stringSlice
|
||||
showVer bool
|
||||
protonDrive bool
|
||||
drivePath string
|
||||
)
|
||||
|
||||
flag.StringVar(&input, "i", "", "single file input (append mode only)")
|
||||
@@ -92,6 +96,8 @@ func Parse() (*Config, error) {
|
||||
flag.Var(&ignores, "ignore", "additional ignore patterns (glob, repeatable)")
|
||||
flag.Var(&exts, "extensions", "additional file extensions to skip (repeatable)")
|
||||
flag.BoolVar(&showVer, "version", false, "print version and exit")
|
||||
flag.BoolVar(&protonDrive, "proton-drive", false, "upload output to Proton Drive after writing locally")
|
||||
flag.StringVar(&drivePath, "drive-path", "", "full remote path on Proton Drive (requires --proton-drive)")
|
||||
|
||||
flag.Usage = PrintUsage
|
||||
flag.Parse()
|
||||
@@ -105,13 +111,19 @@ func Parse() (*Config, error) {
|
||||
return nil, fmt.Errorf("-o is required")
|
||||
}
|
||||
|
||||
if drivePath != "" && !protonDrive {
|
||||
return nil, fmt.Errorf("--drive-path requires --proton-drive")
|
||||
}
|
||||
|
||||
cfg := &Config{
|
||||
OutputPath: output,
|
||||
AppendMode: appendMd,
|
||||
MaxSize: maxSize,
|
||||
MaxDepth: maxDepth,
|
||||
Ignores: append(DefaultIgnores, ignores...),
|
||||
Extensions: append(DefaultExts, exts...),
|
||||
OutputPath: output,
|
||||
AppendMode: appendMd,
|
||||
MaxSize: maxSize,
|
||||
MaxDepth: maxDepth,
|
||||
Ignores: append(DefaultIgnores, ignores...),
|
||||
Extensions: append(DefaultExts, exts...),
|
||||
ProtonDrive: protonDrive,
|
||||
DrivePath: drivePath,
|
||||
}
|
||||
|
||||
if input != "" {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package drive
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const binaryName = "proton-drive"
|
||||
|
||||
// Lookup returns the full path to the proton-drive binary in PATH.
|
||||
func Lookup() (string, error) {
|
||||
return exec.LookPath(binaryName)
|
||||
}
|
||||
|
||||
// CheckAuth verifies that the user is authenticated by listing /my-files.
|
||||
func CheckAuth() error {
|
||||
binary, err := Lookup()
|
||||
if err != nil {
|
||||
return fmt.Errorf("proton-drive not found in PATH: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(binary, "filesystem", "list", "/my-files")
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("not authenticated with proton-drive (run 'proton-drive auth login'): %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Upload uploads localPath to remotePath on Proton Drive.
|
||||
// remotePath is a full path including filename (e.g. /my-files/md/report.md).
|
||||
// The CLI uploads to a parent directory and preserves the local filename,
|
||||
// so if the remote filename differs from the local one, a temp copy is staged.
|
||||
// Existing remote files are overwritten (--conflict-strategy replace).
|
||||
func Upload(localPath, remotePath string) error {
|
||||
binary, err := Lookup()
|
||||
if err != nil {
|
||||
return fmt.Errorf("proton-drive not found in PATH: %w", err)
|
||||
}
|
||||
|
||||
remoteDir := filepath.Dir(remotePath)
|
||||
remoteName := filepath.Base(remotePath)
|
||||
localName := filepath.Base(localPath)
|
||||
|
||||
if remoteName == localName {
|
||||
return runUpload(binary, localPath, remoteDir)
|
||||
}
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "dirmd-upload-*")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create temp dir: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
tmpFile := filepath.Join(tmpDir, remoteName)
|
||||
if err := copyFile(localPath, tmpFile); err != nil {
|
||||
return fmt.Errorf("cannot stage temp file: %w", err)
|
||||
}
|
||||
|
||||
return runUpload(binary, tmpFile, remoteDir)
|
||||
}
|
||||
|
||||
func runUpload(binary, localPath, remoteDir string) error {
|
||||
cmd := exec.Command(binary, "filesystem", "upload", localPath, remoteDir,
|
||||
"--conflict-strategy", "replace")
|
||||
|
||||
var stderr strings.Builder
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("upload to proton-drive failed: %w: %s",
|
||||
err, strings.TrimSpace(stderr.String()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
data, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(dst, data, 0644)
|
||||
}
|
||||
Reference in New Issue
Block a user