Skip to content

Commit 1ba4abe

Browse files
committed
Refactor rclone code
1 parent bfce772 commit 1ba4abe

File tree

3 files changed

+76
-94
lines changed

3 files changed

+76
-94
lines changed

cmd/tess.go

Lines changed: 12 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"html"
1010
"log"
1111
"os"
12-
"os/exec"
1312
"path/filepath"
1413
"sort"
1514
"strings"
@@ -233,8 +232,8 @@ func main() {
233232
}
234233
uploadedURL := ""
235234
if strings.TrimSpace(*rcloneFolderID) != "" {
236-
if _, err := exec.LookPath("rclone"); err != nil {
237-
log.Fatalf("rclone not found in PATH; install from https://rclone.org")
235+
if err := api.RcloneAvailable(); err != nil {
236+
log.Fatalf("%v; install from https://rclone.org", err)
238237
}
239238
// Normalize format
240239
fmtStr := strings.ToLower(strings.TrimSpace(*uploadFormat))
@@ -267,48 +266,29 @@ func main() {
267266
log.Fatalf("pandoc conversion failed: %v", err)
268267
}
269268
// Upload as a regular PDF file (no import)
270-
_, err = runWithSpinner(ctx, "Uploading PDF via rclone...", func(c context.Context) (any, error) {
271-
dest := fmt.Sprintf("%s:%s.pdf", remoteName, docTitle)
272-
args := []string{"copyto", pdfPath, dest, "--drive-root-folder-id=" + *rcloneFolderID}
273-
cmd := exec.CommandContext(c, "rclone", args...)
274-
out, err := cmd.CombinedOutput()
275-
if err != nil {
276-
return nil, fmt.Errorf("rclone copyto failed: %v: %s", err, string(out))
277-
}
278-
return string(out), nil
269+
uploadAny, err := runWithSpinner(ctx, "Uploading PDF via rclone...", func(c context.Context) (any, error) {
270+
return api.CopyToAndLink(c, remoteName, *rcloneFolderID, pdfPath, docTitle+".pdf", "")
279271
})
280272
if err != nil {
281273
log.Fatalf("rclone upload failed: %v", err)
282274
}
283-
linkArgs := []string{"link", fmt.Sprintf("%s:%s.pdf", remoteName, docTitle), "--drive-root-folder-id=" + *rcloneFolderID}
284-
if linkOut, err := exec.Command("rclone", linkArgs...).CombinedOutput(); err == nil {
285-
if ln := strings.TrimSpace(string(linkOut)); ln != "" {
286-
uploadedURL = ln
287-
}
275+
if ln, ok := uploadAny.(string); ok && strings.TrimSpace(ln) != "" {
276+
uploadedURL = ln
288277
}
289278
} else {
290279
docxPath := filepath.Join(os.TempDir(), docTitle+".docx")
291280
_, err := runWithSpinner(ctx, "Converting to DOCX...", func(c context.Context) (any, error) { return nil, api.ConvertMarkdownToDOCX(c, fname, docxPath) })
292281
if err != nil {
293282
log.Fatalf("pandoc conversion failed: %v", err)
294283
}
295-
_, err = runWithSpinner(ctx, "Uploading via rclone...", func(c context.Context) (any, error) {
296-
args := []string{"copyto", docxPath, fmt.Sprintf("%s:%s", remoteName, docTitle), "--drive-root-folder-id=" + *rcloneFolderID, "--drive-import-formats", "docx"}
297-
cmd := exec.CommandContext(c, "rclone", args...)
298-
out, err := cmd.CombinedOutput()
299-
if err != nil {
300-
return nil, fmt.Errorf("rclone copyto failed: %v: %s", err, string(out))
301-
}
302-
return string(out), nil
284+
uploadAny, err := runWithSpinner(ctx, "Uploading via rclone...", func(c context.Context) (any, error) {
285+
return api.CopyToAndLink(c, remoteName, *rcloneFolderID, docxPath, docTitle, "docx")
303286
})
304287
if err != nil {
305288
log.Fatalf("rclone upload failed: %v", err)
306289
}
307-
linkArgs := []string{"link", fmt.Sprintf("%s:%s", remoteName, docTitle), "--drive-root-folder-id=" + *rcloneFolderID}
308-
if linkOut, err := exec.Command("rclone", linkArgs...).CombinedOutput(); err == nil {
309-
if ln := strings.TrimSpace(string(linkOut)); ln != "" {
310-
uploadedURL = ln
311-
}
290+
if ln, ok := uploadAny.(string); ok && strings.TrimSpace(ln) != "" {
291+
uploadedURL = ln
312292
}
313293
}
314294
}
@@ -326,7 +306,7 @@ func main() {
326306
fmt.Println()
327307
if strings.TrimSpace(*rcloneFolderID) == "" {
328308
fmt.Fprintln(os.Stderr, "--copy-templates requires --rclone-folder-id to be set")
329-
} else if _, err := exec.LookPath("rclone"); err != nil {
309+
} else if err := api.RcloneAvailable(); err != nil {
330310
fmt.Fprintln(os.Stderr, "rclone not found; cannot copy templates")
331311
} else {
332312
remoteName := *rcloneRemote
@@ -363,15 +343,7 @@ func main() {
363343
}
364344
title := fmt.Sprintf("Copying template: %s...", cp.name)
365345
_, err := runWithSpinner(ctx, title, func(c context.Context) (any, error) {
366-
// Server-side copy by ID to destination folder FS, preserving original name.
367-
dstFs := fmt.Sprintf("%s,root_folder_id=%s:", remoteName, *rcloneFolderID)
368-
args := []string{"backend", "copyid", remoteName + ":", cp.id, dstFs, "--drive-server-side-across-configs"}
369-
cmd := exec.CommandContext(c, "rclone", args...)
370-
out, err := cmd.CombinedOutput()
371-
if err != nil {
372-
return nil, fmt.Errorf("rclone backend copyid failed: %v: %s", err, string(out))
373-
}
374-
return dstFs, nil
346+
return nil, api.CopyByIDToFolder(c, remoteName, *rcloneFolderID, cp.id)
375347
})
376348
if err != nil {
377349
fmt.Fprintf(os.Stderr, "failed to copy template %s: %v\n", cp.name, err)

internal/drive.go

Lines changed: 0 additions & 54 deletions
This file was deleted.

internal/rclone.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package internal
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os/exec"
7+
"strings"
8+
)
9+
10+
// RcloneAvailable returns an error if rclone is not available in PATH.
11+
func RcloneAvailable() error {
12+
if _, err := exec.LookPath("rclone"); err != nil {
13+
return fmt.Errorf("rclone not found in PATH: %w", err)
14+
}
15+
return nil
16+
}
17+
18+
// CopyToAndLink copies a local file to Drive using rclone and returns a shareable link.
19+
// If importFormat is non-empty (e.g. "docx" or "html"), it is passed via
20+
// --drive-import-formats to let Drive import the content as a native Google Doc.
21+
func CopyToAndLink(ctx context.Context, remoteName, folderID, srcPath, destRemote string, importFormat string) (string, error) {
22+
if err := RcloneAvailable(); err != nil {
23+
return "", err
24+
}
25+
args := []string{"copyto", srcPath, fmt.Sprintf("%s:%s", remoteName, destRemote)}
26+
if strings.TrimSpace(folderID) != "" {
27+
args = append(args, "--drive-root-folder-id="+folderID)
28+
}
29+
if strings.TrimSpace(importFormat) != "" {
30+
args = append(args, "--drive-import-formats", importFormat)
31+
}
32+
cmd := exec.CommandContext(ctx, "rclone", args...)
33+
if out, err := cmd.CombinedOutput(); err != nil {
34+
return "", fmt.Errorf("rclone copyto failed: %v: %s", err, string(out))
35+
}
36+
// Attempt to fetch a link to the uploaded file
37+
linkArgs := []string{"link", fmt.Sprintf("%s:%s", remoteName, destRemote)}
38+
if strings.TrimSpace(folderID) != "" {
39+
linkArgs = append(linkArgs, "--drive-root-folder-id="+folderID)
40+
}
41+
if out, err := exec.CommandContext(ctx, "rclone", linkArgs...).CombinedOutput(); err == nil {
42+
return strings.TrimSpace(string(out)), nil
43+
}
44+
return "", nil
45+
}
46+
47+
// CopyByIDToFolder performs a server-side copy of a Drive file (by file ID) into the
48+
// specified Drive folder, preserving the original name and type. It does not return a link.
49+
func CopyByIDToFolder(ctx context.Context, remoteName, folderID, fileID string) error {
50+
if err := RcloneAvailable(); err != nil {
51+
return err
52+
}
53+
if strings.TrimSpace(folderID) == "" {
54+
return fmt.Errorf("folderID is empty")
55+
}
56+
// Use destination fs with embedded root_folder_id to copy into the specific folder.
57+
dstFs := fmt.Sprintf("%s,root_folder_id=%s:", remoteName, folderID)
58+
args := []string{"backend", "copyid", remoteName + ":", fileID, dstFs, "--drive-server-side-across-configs"}
59+
cmd := exec.CommandContext(ctx, "rclone", args...)
60+
if out, err := cmd.CombinedOutput(); err != nil {
61+
return fmt.Errorf("rclone backend copyid failed: %v: %s", err, string(out))
62+
}
63+
return nil
64+
}

0 commit comments

Comments
 (0)