182 lines
4.4 KiB
Go
182 lines
4.4 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"google.golang.org/api/drive/v3"
|
|
|
|
"github.com/steipete/gogcli/internal/outfmt"
|
|
"github.com/steipete/gogcli/internal/ui"
|
|
)
|
|
|
|
type DocsCmd struct {
|
|
Export DocsExportCmd `cmd:"" name:"export" help:"Export a Google Doc (pdf|docx|txt)"`
|
|
Info DocsInfoCmd `cmd:"" name:"info" help:"Get Google Doc metadata"`
|
|
Create DocsCreateCmd `cmd:"" name:"create" help:"Create a Google Doc"`
|
|
Copy DocsCopyCmd `cmd:"" name:"copy" help:"Copy a Google Doc"`
|
|
Cat DocsCatCmd `cmd:"" name:"cat" help:"Print a Google Doc as plain text"`
|
|
}
|
|
|
|
type DocsExportCmd struct {
|
|
DocID string `arg:"" name:"docId" help:"Doc ID"`
|
|
Out string `name:"out" help:"Output file path (default: gogcli config dir)"`
|
|
Format string `name:"format" help:"Export format: pdf|docx|txt" default:"pdf"`
|
|
}
|
|
|
|
func (c *DocsExportCmd) Run(ctx context.Context, flags *RootFlags) error {
|
|
return exportViaDrive(ctx, flags, exportViaDriveOptions{
|
|
ArgName: "docId",
|
|
ExpectedMime: "application/vnd.google-apps.document",
|
|
KindLabel: "Google Doc",
|
|
DefaultFormat: "pdf",
|
|
}, c.DocID, c.Out, c.Format)
|
|
}
|
|
|
|
type DocsInfoCmd struct {
|
|
DocID string `arg:"" name:"docId" help:"Doc ID"`
|
|
}
|
|
|
|
func (c *DocsInfoCmd) Run(ctx context.Context, flags *RootFlags) error {
|
|
return infoViaDrive(ctx, flags, infoViaDriveOptions{
|
|
ArgName: "docId",
|
|
ExpectedMime: "application/vnd.google-apps.document",
|
|
KindLabel: "Google Doc",
|
|
}, c.DocID)
|
|
}
|
|
|
|
type DocsCreateCmd struct {
|
|
Title string `arg:"" name:"title" help:"Doc title"`
|
|
Parent string `name:"parent" help:"Destination folder ID"`
|
|
}
|
|
|
|
func (c *DocsCreateCmd) Run(ctx context.Context, flags *RootFlags) error {
|
|
u := ui.FromContext(ctx)
|
|
account, err := requireAccount(flags)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
title := strings.TrimSpace(c.Title)
|
|
if title == "" {
|
|
return usage("empty title")
|
|
}
|
|
|
|
svc, err := newDriveService(ctx, account)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
f := &drive.File{
|
|
Name: title,
|
|
MimeType: "application/vnd.google-apps.document",
|
|
}
|
|
parent := strings.TrimSpace(c.Parent)
|
|
if parent != "" {
|
|
f.Parents = []string{parent}
|
|
}
|
|
|
|
created, err := svc.Files.Create(f).
|
|
SupportsAllDrives(true).
|
|
Fields("id, name, mimeType, webViewLink").
|
|
Context(ctx).
|
|
Do()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if created == nil {
|
|
return errors.New("create failed")
|
|
}
|
|
|
|
if outfmt.IsJSON(ctx) {
|
|
return outfmt.WriteJSON(os.Stdout, map[string]any{"file": created})
|
|
}
|
|
|
|
u.Out().Printf("id\t%s", created.Id)
|
|
u.Out().Printf("name\t%s", created.Name)
|
|
u.Out().Printf("mime\t%s", created.MimeType)
|
|
if created.WebViewLink != "" {
|
|
u.Out().Printf("link\t%s", created.WebViewLink)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type DocsCopyCmd struct {
|
|
DocID string `arg:"" name:"docId" help:"Doc ID"`
|
|
Title string `arg:"" name:"title" help:"New title"`
|
|
Parent string `name:"parent" help:"Destination folder ID"`
|
|
}
|
|
|
|
func (c *DocsCopyCmd) Run(ctx context.Context, flags *RootFlags) error {
|
|
return copyViaDrive(ctx, flags, copyViaDriveOptions{
|
|
ArgName: "docId",
|
|
ExpectedMime: "application/vnd.google-apps.document",
|
|
KindLabel: "Google Doc",
|
|
}, c.DocID, c.Title, c.Parent)
|
|
}
|
|
|
|
type DocsCatCmd struct {
|
|
DocID string `arg:"" name:"docId" help:"Doc ID"`
|
|
MaxBytes int64 `name:"max-bytes" help:"Max bytes to read (0 = unlimited)" default:"2000000"`
|
|
}
|
|
|
|
func (c *DocsCatCmd) Run(ctx context.Context, flags *RootFlags) error {
|
|
account, err := requireAccount(flags)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
id := strings.TrimSpace(c.DocID)
|
|
if id == "" {
|
|
return usage("empty docId")
|
|
}
|
|
|
|
svc, err := newDriveService(ctx, account)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
meta, err := svc.Files.Get(id).
|
|
SupportsAllDrives(true).
|
|
Fields("id, mimeType").
|
|
Context(ctx).
|
|
Do()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if meta == nil {
|
|
return errors.New("file not found")
|
|
}
|
|
if meta.MimeType != "application/vnd.google-apps.document" {
|
|
return fmt.Errorf("file is not a Google Doc (mimeType=%q)", meta.MimeType)
|
|
}
|
|
|
|
resp, err := driveExportDownload(ctx, svc, id, "text/plain")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp == nil || resp.Body == nil {
|
|
return errors.New("empty response")
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var r io.Reader = resp.Body
|
|
if c.MaxBytes > 0 {
|
|
r = io.LimitReader(resp.Body, c.MaxBytes)
|
|
}
|
|
b, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if outfmt.IsJSON(ctx) {
|
|
return outfmt.WriteJSON(os.Stdout, map[string]any{"text": string(b)})
|
|
}
|
|
_, err = os.Stdout.Write(b)
|
|
return err
|
|
}
|