Files
zipprine/internal/cli/cli.go

232 lines
7.6 KiB
Go
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cli
import (
"flag"
"fmt"
"os"
"strings"
"zipprine/internal/archiver"
"zipprine/internal/fetcher"
"zipprine/internal/models"
"zipprine/internal/version"
)
func Run() bool {
// Define flags
compress := flag.String("compress", "", "Compress files/folders (source path)")
extract := flag.String("extract", "", "Extract archive (archive path)")
analyze := flag.String("analyze", "", "Analyze archive (archive path)")
output := flag.String("output", "", "Output path for compression or extraction")
archiveType := flag.String("type", "zip", "Archive type (zip, tar, tar.gz, gzip, rar)")
level := flag.Int("level", 6, "Compression level (1=fast, 6=balanced, 9=best)")
overwrite := flag.Bool("overwrite", false, "Overwrite existing files during extraction")
preservePerms := flag.Bool("preserve-perms", true, "Preserve file permissions during extraction")
exclude := flag.String("exclude", "", "Comma-separated list of patterns to exclude")
include := flag.String("include", "", "Comma-separated list of patterns to include")
verify := flag.Bool("verify", false, "Verify archive integrity after compression")
remoteURL := flag.String("url", "", "Remote URL to download and extract archive from")
showVersion := flag.Bool("version", false, "Show version information")
help := flag.Bool("help", false, "Show help information")
flag.Parse()
if *showVersion {
fmt.Println(version.FullVersion())
return true
}
if *help {
printHelp()
return true
}
if flag.NFlag() == 0 {
return false
}
if *remoteURL != "" {
if *output == "" {
fmt.Println("❌ Error: --output is required when using --url")
os.Exit(1)
}
if !fetcher.IsValidArchiveURL(*remoteURL) {
fmt.Println("⚠️ Warning: URL does not appear to point to a supported archive format")
}
if err := fetcher.FetchAndExtract(*remoteURL, *output, *overwrite, *preservePerms); err != nil {
fmt.Printf("❌ Error: %v\n", err)
os.Exit(1)
}
fmt.Println("✨ Remote archive fetched and extracted successfully!")
return true
}
if *compress != "" {
if *output == "" {
fmt.Println("❌ Error: --output is required for compression")
os.Exit(1)
}
archType := parseArchiveType(*archiveType)
if archType == models.RAR {
fmt.Println("❌ Error: RAR compression is not supported (proprietary format)")
os.Exit(1)
}
config := &models.CompressConfig{
SourcePath: *compress,
OutputPath: *output,
ArchiveType: archType,
CompressionLevel: *level,
VerifyIntegrity: *verify,
}
if *exclude != "" {
config.ExcludePaths = strings.Split(*exclude, ",")
}
if *include != "" {
config.IncludePaths = strings.Split(*include, ",")
}
fmt.Printf("📦 Compressing %s to %s (%s)...\n", *compress, *output, archType)
if err := archiver.Compress(config); err != nil {
fmt.Printf("❌ Error: %v\n", err)
os.Exit(1)
}
fmt.Println("✨ Compression completed successfully!")
return true
}
if *extract != "" {
if *output == "" {
fmt.Println("❌ Error: --output is required for extraction")
os.Exit(1)
}
// Detect archive type if not specified or set to auto
archType := parseArchiveType(*archiveType)
if archType == models.AUTO || *archiveType == "" {
detectedType, err := archiver.DetectArchiveType(*extract)
if err != nil {
fmt.Printf("❌ Error detecting archive type: %v\n", err)
os.Exit(1)
}
archType = detectedType
fmt.Printf("🔍 Detected archive type: %s\n", archType)
}
config := &models.ExtractConfig{
ArchivePath: *extract,
DestPath: *output,
ArchiveType: archType,
OverwriteAll: *overwrite,
PreservePerms: *preservePerms,
}
fmt.Printf("📂 Extracting %s to %s...\n", *extract, *output)
if err := archiver.Extract(config); err != nil {
fmt.Printf("❌ Error: %v\n", err)
os.Exit(1)
}
fmt.Println("✨ Extraction completed successfully!")
return true
}
// Handle analysis
if *analyze != "" {
info, err := archiver.Analyze(*analyze)
if err != nil {
fmt.Printf("❌ Error: %v\n", err)
os.Exit(1)
}
fmt.Println("\n📊 Archive Analysis")
fmt.Println("==================")
fmt.Printf("Type: %s\n", info.Type)
fmt.Printf("File Count: %d\n", info.FileCount)
fmt.Printf("Total Size: %d bytes\n", info.TotalSize)
fmt.Printf("Compressed Size: %d bytes\n", info.CompressedSize)
if info.CompressionRatio > 0 {
fmt.Printf("Compression Ratio: %.2f%%\n", info.CompressionRatio*100)
}
if info.Checksum != "" {
fmt.Printf("Checksum (SHA256): %s\n", info.Checksum)
}
fmt.Println("\n📁 Files:")
for i, file := range info.Files {
if i >= 20 {
fmt.Printf("... and %d more files\n", len(info.Files)-20)
break
}
fmt.Printf(" - %s (%d bytes)\n", file.Name, file.Size)
}
return true
}
fmt.Println("❌ Error: No valid operation specified. Use --help for usage information.")
os.Exit(1)
return true
}
func parseArchiveType(typeStr string) models.ArchiveType {
switch strings.ToLower(typeStr) {
case "zip":
return models.ZIP
case "tar":
return models.TAR
case "tar.gz", "targz", "tgz":
return models.TARGZ
case "gzip", "gz":
return models.GZIP
case "rar":
return models.RAR
case "auto":
return models.AUTO
default:
return models.ZIP
}
}
func printHelp() {
fmt.Println(version.FullVersion())
fmt.Println("\n🗜 A modern TUI/CLI archiving tool with support for multiple formats")
fmt.Println("\nUSAGE:")
fmt.Println(" Interactive mode (default):")
fmt.Println(" zipprine")
fmt.Println("\n Command-line mode:")
fmt.Println(" zipprine [OPTIONS]")
fmt.Println("\nOPTIONS:")
fmt.Println(" --compress <path> Compress files/folders at the specified path")
fmt.Println(" --extract <path> Extract archive at the specified path")
fmt.Println(" --analyze <path> Analyze archive at the specified path")
fmt.Println(" --output <path> Output path for compression or extraction")
fmt.Println(" --type <type> Archive type: zip, tar, tar.gz, gzip, rar (default: zip)")
fmt.Println(" --level <1-9> Compression level: 1=fast, 6=balanced, 9=best (default: 6)")
fmt.Println(" --overwrite Overwrite existing files during extraction")
fmt.Println(" --preserve-perms Preserve file permissions (default: true)")
fmt.Println(" --exclude <patterns> Comma-separated patterns to exclude")
fmt.Println(" --include <patterns> Comma-separated patterns to include")
fmt.Println(" --verify Verify archive integrity after compression")
fmt.Println(" --url <url> Download and extract archive from remote URL")
fmt.Println(" --version Show version information")
fmt.Println(" --help Show this help message")
fmt.Println("\nEXAMPLES:")
fmt.Println(" # Compress a directory")
fmt.Println(" zipprine --compress /path/to/source --output archive.zip --type zip")
fmt.Println("\n # Extract an archive")
fmt.Println(" zipprine --extract archive.tar.gz --output /path/to/dest")
fmt.Println("\n # Analyze an archive")
fmt.Println(" zipprine --analyze archive.zip")
fmt.Println("\n # Download and extract from URL")
fmt.Println(" zipprine --url https://example.com/archive.zip --output /path/to/dest")
fmt.Println("\n # Compress with exclusions")
fmt.Println(" zipprine --compress /project --output project.tar.gz --type tar.gz --exclude '*.log,*.tmp'")
fmt.Println("\nSUPPORTED FORMATS:")
fmt.Println(" Compression: ZIP, TAR, TAR.GZ, GZIP")
fmt.Println(" Extraction: ZIP, TAR, TAR.GZ, GZIP, RAR")
fmt.Println("\nNOTE:")
fmt.Println(" RAR compression is not supported due to proprietary format.")
fmt.Println(" RAR extraction is supported for reading existing RAR archives.")
}