Skip to content

Commit

Permalink
add colors
Browse files Browse the repository at this point in the history
  • Loading branch information
anibaldeboni committed Jul 19, 2024
1 parent 10f913a commit afd10ed
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 110 deletions.
96 changes: 59 additions & 37 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,45 @@ import (
"log"
"os"
"runtime"
"sync"

"github.com/anibaldeboni/rx/files"
"github.com/anibaldeboni/rx/styles"
"github.com/spf13/cobra"
)

var (
rootCmd = &cobra.Command{
Use: "rx",
Short: "rx is a cli tool to zip and unzip individual rom files.",
Long: `Rom eXpander is a cli tool designed to help you to manage your rom collection.
It can compress individual rom files into zip files and inflate content files from zip files.
`,
Version: Version,
}
var Version = "dev"

options *Options
walkRecursive bool
outputDir string
workers int
Version = "dev"
)
const ZipExtension = ".zip"

type Options struct {
FindFunc files.FindFilesFunc
Workers int
Output string
type Cli struct {
Workers int
Output string
Version string
Recursive bool
errs chan error
wg *sync.WaitGroup
}

func init() {
rootCmd.PersistentFlags().BoolVarP(&walkRecursive, "recursive", "r", false, "walk recursively through directories")
cwd, _ := os.Getwd()
rootCmd.PersistentFlags().StringVarP(&outputDir, "output", "o", cwd, "output directory")
rootCmd.PersistentFlags().IntVarP(&workers, "workers", "w", runtime.NumCPU(), "number of workers to use")
type WorkerFunc func(<-chan string)

func (c *Cli) SetupWorkers(worker WorkerFunc, path string) {
log.Printf("Looking for files at %s\n", styles.DarkPink(path))
files := c.FindFiles()(path, c.errs)

log.Printf("Using %s workers\n", styles.LightBlue(fmt.Sprintf("%d", c.Workers)))

c.wg.Add(c.Workers)
for i := 0; i < c.Workers; i++ {
go worker(files)
}

c.wg.Wait()
log.Println(styles.Green("Done!"))
}

func FindFilesStrategy() files.FindFilesFunc {
if walkRecursive {
func (c *Cli) FindFiles() files.FindFilesFunc {
if c.Recursive {
return files.FindRecursive
}

Expand All @@ -65,33 +67,53 @@ func validateCmdPath(cmd *cobra.Command, args []string) error {
return fmt.Errorf("Could not run: %w", err)
}

if flag := cmd.Flag("output").Value.String(); flag != "" {
options.Output = flag
}

return nil
}

func checkPath(path string) error {
switch p, err := os.Stat(path); {
case err != nil:
return fmt.Errorf("Invalid path %s: %w", path, err)
return fmt.Errorf("Invalid path %s: %w", styles.DarkRed(path), err)
case p == nil:
return fmt.Errorf("Path %s does not exist", path)
return fmt.Errorf("Path %s does not exist", styles.DarkRed(path))
case !p.IsDir():
return fmt.Errorf("Path %s is not a directory", path)
return fmt.Errorf("Path %s is not a directory", styles.DarkRed(path))
default:
return nil
}
}

func Execute() {
options = &Options{
FindFunc: FindFilesStrategy(),
Workers: workers,
Output: outputDir,
errs := make(chan error)
defer close(errs)

HandleErrors(errs)

cli := &Cli{
Version: Version,
errs: errs,
wg: &sync.WaitGroup{},
}

rootCmd := &cobra.Command{
Use: "rx",
Short: "rx is a cli tool to zip and unzip individual rom files.",
Long: `Rom eXpander is a cli tool designed to help you to manage your rom collection.
It can compress individual rom files into zip files and inflate content files from zip files.
`,
Version: Version,
SilenceUsage: true,
SilenceErrors: true,
}

rootCmd.PersistentFlags().BoolVarP(&cli.Recursive, "recursive", "r", false, "walk recursively through directories")
cwd, _ := os.Getwd()
rootCmd.PersistentFlags().StringVarP(&cli.Output, "output", "o", cwd, "output directory")
rootCmd.PersistentFlags().IntVarP(&cli.Workers, "workers", "w", runtime.NumCPU(), "number of workers to use")

rootCmd.AddCommand(cli.zipCmd())
rootCmd.AddCommand(cli.unzipCmd())

if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
Expand Down
62 changes: 21 additions & 41 deletions cmd/unzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,27 @@ import (
"log"
"os"
"path/filepath"
"sync"

"github.com/anibaldeboni/rx/files"
"github.com/anibaldeboni/rx/styles"
"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(unzipCmd)
}

var unzipCmd = &cobra.Command{
Use: "unzip [path]",
Short: "inflate rom files.",
Long: `Inflate content files from zip files`,
PreRunE: validateCmdPath,
Run: executeUnzip,
}

func executeUnzip(cmd *cobra.Command, args []string) {
errs := make(chan error)
defer close(errs)

HandleErrors(errs)
SetupWorkers(unzipWorker, options.FindFunc, args[0], errs)
}

type WorkerFunc func(*sync.WaitGroup, <-chan string, chan<- error)

func SetupWorkers(worker WorkerFunc, findFiles files.FindFilesFunc, path string, errs chan<- error) {
var wg sync.WaitGroup
files := findFiles(path, errs)
wg.Add(options.Workers)
for i := 0; i < options.Workers; i++ {
go worker(&wg, files, errs)
func (c *Cli) unzipCmd() *cobra.Command {
return &cobra.Command{
Use: "unzip [path]",
Short: "inflate rom files.",
Long: `Inflate content files from zip files`,
PreRunE: validateCmdPath,
Run: c.unzip,
}
}

wg.Wait()
func (c *Cli) unzip(cmd *cobra.Command, args []string) {
c.SetupWorkers(c.unzipWorker, args[0])
}

func unzipWorker(wg *sync.WaitGroup, files <-chan string, errs chan<- error) {
defer wg.Done()
func (c *Cli) unzipWorker(files <-chan string) {
defer c.wg.Done()

for file := range files {
if filepath.Ext(file) != ZipExtension {
Expand All @@ -56,36 +36,36 @@ func unzipWorker(wg *sync.WaitGroup, files <-chan string, errs chan<- error) {

zipFile, err := zip.OpenReader(file)
if err != nil {
errs <- fmt.Errorf("Error opening zip archive %s: %w", file, err)
c.errs <- fmt.Errorf("Error opening zip archive %s: %w", styles.DarkRed(file), err)
}
defer zipFile.Close()
for _, zipContent := range zipFile.File {
outputFilePath := filepath.Join(options.Output, zipContent.Name)
outputFilePath := filepath.Join(c.Output, zipContent.Name)

log.Println("Extracting file", outputFilePath)
log.Println("Inflating", styles.LightBlue(filepath.Base(file)))

if zipContent.FileInfo().IsDir() {
if err := os.MkdirAll(outputFilePath, os.ModePerm); err != nil {
errs <- fmt.Errorf("Error creating directory %s: %w", outputFilePath, err)
c.errs <- fmt.Errorf("Error creating directory %s: %w", styles.DarkRed(outputFilePath), err)
}
continue
}

if err := os.MkdirAll(filepath.Dir(outputFilePath), os.ModePerm); err != nil {
errs <- fmt.Errorf("Error creating directory %s: %w", filepath.Dir(outputFilePath), err)
c.errs <- fmt.Errorf("Error creating directory %s: %w", styles.DarkRed(filepath.Dir(outputFilePath)), err)
}

dstFile, err := os.OpenFile(outputFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, zipContent.Mode())
if err != nil {
errs <- fmt.Errorf("Error creating file %s: %w", outputFilePath, err)
c.errs <- fmt.Errorf("Error creating file %s: %w", styles.DarkRed(outputFilePath), err)
}

srcFile, err := zipContent.Open()
if err != nil {
errs <- fmt.Errorf("Error compressed file %s: %w", zipContent.Name, err)
c.errs <- fmt.Errorf("Error compressed file %s: %w", styles.DarkRed(zipContent.Name), err)
}
if _, err := io.Copy(dstFile, srcFile); err != nil {
errs <- fmt.Errorf("Error inflating file %s: %w", zipContent.Name, err)
c.errs <- fmt.Errorf("Error inflating file %s: %w", styles.DarkRed(zipContent.Name), err)
}

dstFile.Close()
Expand Down
54 changes: 22 additions & 32 deletions cmd/zip.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,63 @@ import (
"archive/zip"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
"sync"

"github.com/anibaldeboni/rx/styles"
"github.com/spf13/cobra"
)

const ZipExtension = ".zip"

func init() {
rootCmd.AddCommand(zipCmd)
}

var zipCmd = &cobra.Command{
Use: "zip [path]",
Short: "compress rom files.",
Long: `Compress rom files into individual zip files.`,
PreRunE: validateCmdPath,
Run: executeZip,
func (c *Cli) zipCmd() *cobra.Command {
return &cobra.Command{
Use: "zip [path]",
Short: "compress rom files.",
Long: `Compress rom files into individual zip files.`,
PreRunE: validateCmdPath,
Run: c.zip,
}
}

func executeZip(cmd *cobra.Command, args []string) {
errs := make(chan error)
defer close(errs)

HandleErrors(errs)
SetupWorkers(zipWorker, options.FindFunc, args[0], errs)

log.Println("Done!")
func (c *Cli) zip(cmd *cobra.Command, args []string) {
c.SetupWorkers(c.zipWorker, args[0])
}

func zipWorker(wg *sync.WaitGroup, files <-chan string, errs chan<- error) {
defer wg.Done()
func (c *Cli) zipWorker(files <-chan string) {
defer c.wg.Done()

for file := range files {
func() {
outputFileName := strings.TrimSuffix(filepath.Base(file), filepath.Ext(file)) + ZipExtension
outputFilePath := filepath.Join(options.Output, outputFileName)
zipFile := filepath.Base(file)
outputFileName := strings.TrimSuffix(zipFile, filepath.Ext(file)) + ZipExtension
outputFilePath := filepath.Join(c.Output, outputFileName)

outputFile, err := os.Create(outputFilePath)
defer outputFile.Close()
if err != nil {
errs <- fmt.Errorf("Error creating file %s: %w", outputFilePath, err)
c.errs <- fmt.Errorf("Error creating file %s: %w", outputFilePath, err)
return
}

inputFile, err := os.Open(file)
defer inputFile.Close()
if err != nil {
errs <- fmt.Errorf("Error opening file %s: %w", file, err)
c.errs <- fmt.Errorf("Error opening file %s: %w", file, err)
return
}

zipWriter := zip.NewWriter(outputFile)

fileWriter, err := zipWriter.Create(filepath.Base(file))
fileWriter, err := zipWriter.Create(zipFile)
if err != nil {
errs <- fmt.Errorf("Error creating file %s in zip: %w", file, err)
c.errs <- fmt.Errorf("Error creating file %s in zip: %w", file, err)
return
}

fmt.Printf("Zipping %s\n", file)
fmt.Printf("Compressing %s\n", styles.LightBlue(zipFile))

if _, err := io.Copy(fileWriter, inputFile); err != nil {
errs <- fmt.Errorf("Error compressing file %s to zip: %w", file, err)
c.errs <- fmt.Errorf("Error compressing file %s to zip: %w", file, err)
return
}

Expand Down
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ module github.com/anibaldeboni/rx
go 1.22.1

require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/lipgloss v0.12.1 // indirect
github.com/charmbracelet/x/ansi v0.1.4 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/karrick/godirwalk v1.17.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.22.0 // indirect
)
20 changes: 20 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwSWoI=
github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading

0 comments on commit afd10ed

Please sign in to comment.