236 lines
5.9 KiB
Go
236 lines
5.9 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"mime"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"text/tabwriter"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func NewFileCmd() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "file",
|
|
Short: "Manage files in buckets",
|
|
Long: "Upload, download, list, and manage files in your buckets",
|
|
}
|
|
|
|
cmd.AddCommand(newFileUploadCmd())
|
|
cmd.AddCommand(newFileDownloadCmd())
|
|
cmd.AddCommand(newFileListCmd())
|
|
cmd.AddCommand(newFileDeleteCmd())
|
|
|
|
return cmd
|
|
}
|
|
|
|
func newFileUploadCmd() *cobra.Command {
|
|
var contentType string
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "upload <bucket-name> <local-file> [remote-key]",
|
|
Short: "Upload a file to a bucket",
|
|
Args: cobra.RangeArgs(2, 3),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
config, err := LoadConfig()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config: %w", err)
|
|
}
|
|
|
|
if !config.IsAuthenticated() {
|
|
return fmt.Errorf("not logged in. Use 'tcman account login' or 'tcman account create'")
|
|
}
|
|
|
|
bucketName := args[0]
|
|
localFile := args[1]
|
|
|
|
remoteKey := filepath.Base(localFile)
|
|
if len(args) == 3 {
|
|
remoteKey = args[2]
|
|
}
|
|
|
|
data, err := os.ReadFile(localFile)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read file: %w", err)
|
|
}
|
|
|
|
if contentType == "" {
|
|
contentType = mime.TypeByExtension(filepath.Ext(localFile))
|
|
}
|
|
|
|
client := NewClient(config.ServerURL, config.AccessToken)
|
|
ctx := context.Background()
|
|
|
|
fmt.Printf("Uploading %s to %s/%s (%s)...\n", localFile, bucketName, remoteKey, formatBytes(int64(len(data))))
|
|
|
|
err = client.PutObject(ctx, bucketName, remoteKey, data, contentType)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to upload file: %w", err)
|
|
}
|
|
|
|
fmt.Printf("File uploaded successfully!\n")
|
|
fmt.Printf("Bucket: %s\n", bucketName)
|
|
fmt.Printf("Key: %s\n", remoteKey)
|
|
fmt.Printf("Size: %s\n", formatBytes(int64(len(data))))
|
|
if contentType != "" {
|
|
fmt.Printf("Content-Type: %s\n", contentType)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Flags().StringVar(&contentType, "content-type", "", "Override content type")
|
|
return cmd
|
|
}
|
|
|
|
func newFileDownloadCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "download <bucket-name> <remote-key> [local-file]",
|
|
Short: "Download a file from a bucket",
|
|
Args: cobra.RangeArgs(2, 3),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
config, err := LoadConfig()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config: %w", err)
|
|
}
|
|
|
|
if !config.IsAuthenticated() {
|
|
return fmt.Errorf("not logged in. Use 'tcman account login' or 'tcman account create'")
|
|
}
|
|
|
|
bucketName := args[0]
|
|
remoteKey := args[1]
|
|
|
|
localFile := filepath.Base(remoteKey)
|
|
if len(args) == 3 {
|
|
localFile = args[2]
|
|
}
|
|
|
|
client := NewClient(config.ServerURL, config.AccessToken)
|
|
ctx := context.Background()
|
|
|
|
fmt.Printf("Downloading %s/%s to %s...\n", bucketName, remoteKey, localFile)
|
|
|
|
data, err := client.GetObject(ctx, bucketName, remoteKey)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to download file: %w", err)
|
|
}
|
|
|
|
err = os.WriteFile(localFile, data, 0644)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to write file: %w", err)
|
|
}
|
|
|
|
fmt.Printf("File downloaded successfully!\n")
|
|
fmt.Printf("Size: %s\n", formatBytes(int64(len(data))))
|
|
fmt.Printf("Saved to: %s\n", localFile)
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func newFileListCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "list <bucket-name>",
|
|
Short: "List files in a bucket",
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
config, err := LoadConfig()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config: %w", err)
|
|
}
|
|
|
|
if !config.IsAuthenticated() {
|
|
return fmt.Errorf("not logged in. Use 'tcman account login' or 'tcman account create'")
|
|
}
|
|
|
|
bucketName := args[0]
|
|
client := NewClient(config.ServerURL, config.AccessToken)
|
|
ctx := context.Background()
|
|
|
|
objects, err := client.ListObjects(ctx, bucketName)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list objects: %w", err)
|
|
}
|
|
|
|
if len(objects) == 0 {
|
|
fmt.Printf("No files found in bucket '%s'.\n", bucketName)
|
|
return nil
|
|
}
|
|
|
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
|
fmt.Fprintln(w, "Key\tSize\tContent-Type\tLast Modified")
|
|
fmt.Fprintln(w, "---\t----\t------------\t-------------")
|
|
|
|
for _, obj := range objects {
|
|
contentType := obj.ContentType
|
|
if contentType == "" {
|
|
contentType = "application/octet-stream"
|
|
}
|
|
|
|
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
|
|
obj.Key,
|
|
formatBytes(obj.SizeBytes),
|
|
contentType,
|
|
obj.LastModified.Format("2006-01-02 15:04:05"),
|
|
)
|
|
}
|
|
w.Flush()
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func newFileDeleteCmd() *cobra.Command {
|
|
var force bool
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "delete <bucket-name> <remote-key>",
|
|
Short: "Delete a file from a bucket",
|
|
Args: cobra.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
config, err := LoadConfig()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config: %w", err)
|
|
}
|
|
|
|
if !config.IsAuthenticated() {
|
|
return fmt.Errorf("not logged in. Use 'tcman account login' or 'tcman account create'")
|
|
}
|
|
|
|
bucketName := args[0]
|
|
remoteKey := args[1]
|
|
client := NewClient(config.ServerURL, config.AccessToken)
|
|
ctx := context.Background()
|
|
|
|
if !force {
|
|
fmt.Printf("Are you sure you want to delete '%s' from bucket '%s'? (y/N): ", remoteKey, bucketName)
|
|
var response string
|
|
fmt.Scanln(&response)
|
|
response = strings.ToLower(response)
|
|
if response != "y" && response != "yes" {
|
|
fmt.Printf("Cancelled.\n")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
err = client.DeleteObject(ctx, bucketName, remoteKey)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete file: %w", err)
|
|
}
|
|
|
|
fmt.Printf("File '%s' deleted from bucket '%s'.\n", remoteKey, bucketName)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Flags().BoolVar(&force, "force", false, "Force deletion without confirmation")
|
|
return cmd
|
|
}
|