From 1fa54e193696d15ef2902e7d2b9d6be587ec71ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:07:44 +0000 Subject: [PATCH 1/8] Initial plan From a2feca6ccae899d4267087d0acc30a69ac5cdb40 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:19:10 +0000 Subject: [PATCH 2/8] Fix format flag crash and add comprehensive tests - Remove NoOptDefVal which caused the format flag to fail with space-separated values - Add 5 comprehensive unit tests for format flag: space syntax, short form, equals syntax, default value, and case-insensitive - Update README with detailed format flag documentation and examples - Format flag now works with all syntaxes: --format webp, -f webp, --format=webp - Default value (webp) is preserved and shown in help text Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com> --- README.md | 20 +- cmd/cbzoptimizer/commands/optimize_command.go | 3 +- .../commands/optimize_command_test.go | 237 ++++++++++++++++++ cmd/cbzoptimizer/commands/watch_command.go | 5 +- 4 files changed, 259 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a882293..e01b24c 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,22 @@ Optimize all CBZ/CBR files in a folder recursively: cbzconverter optimize [folder] --quality 85 --parallelism 2 --override --format webp --split ``` +The format flag can be specified in multiple ways: + +```sh +# Using space-separated syntax +cbzconverter optimize [folder] --format webp + +# Using short form with space +cbzconverter optimize [folder] -f webp + +# Using equals syntax +cbzconverter optimize [folder] --format=webp + +# Format is case-insensitive +cbzconverter optimize [folder] --format WEBP +``` + With timeout to avoid hanging on problematic chapters: ```sh @@ -74,7 +90,9 @@ docker run -v /path/to/comics:/comics ghcr.io/belphemur/cbzoptimizer:latest watc - `--parallelism`, `-n`: Number of chapters to convert in parallel. Default is 2. - `--override`, `-o`: Override the original files. For CBZ files, overwrites the original. For CBR files, deletes the original CBR and creates a new CBZ. Default is false. - `--split`, `-s`: Split long pages into smaller chunks. Default is false. -- `--format`, `-f`: Format to convert the images to (e.g., webp). Default is webp. +- `--format`, `-f`: Format to convert the images to (currently supports: webp). Default is webp. + - Can be specified as: `--format webp`, `-f webp`, or `--format=webp` + - Case-insensitive: `webp`, `WEBP`, and `WebP` are all valid - `--timeout`, `-t`: Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout. Default is 0. - `--log`, `-l`: Set log level; can be 'panic', 'fatal', 'error', 'warn', 'info', 'debug', or 'trace'. Default is info. diff --git a/cmd/cbzoptimizer/commands/optimize_command.go b/cmd/cbzoptimizer/commands/optimize_command.go index 9149f3a..82a483a 100644 --- a/cmd/cbzoptimizer/commands/optimize_command.go +++ b/cmd/cbzoptimizer/commands/optimize_command.go @@ -33,11 +33,10 @@ func init() { command.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") command.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") command.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout") - command.PersistentFlags().VarP( + command.Flags().VarP( formatFlag, "format", "f", fmt.Sprintf("Format to convert the images to: %s", constant.ListAll())) - command.PersistentFlags().Lookup("format").NoOptDefVal = constant.DefaultConversion.String() AddCommand(command) } diff --git a/cmd/cbzoptimizer/commands/optimize_command_test.go b/cmd/cbzoptimizer/commands/optimize_command_test.go index 92f6484..c758e37 100644 --- a/cmd/cbzoptimizer/commands/optimize_command_test.go +++ b/cmd/cbzoptimizer/commands/optimize_command_test.go @@ -15,6 +15,7 @@ import ( "github.com/belphemur/CBZOptimizer/v2/pkg/converter" "github.com/belphemur/CBZOptimizer/v2/pkg/converter/constant" "github.com/spf13/cobra" + "github.com/thediveo/enumflag/v2" ) // MockConverter is a mock implementation of the Converter interface @@ -172,3 +173,239 @@ func TestConvertCbzCommand(t *testing.T) { // Log summary t.Logf("Found %d converted files", len(convertedFiles)) } + +// TestFormatFlagWithSpace tests that the format flag works with space-separated values +func TestFormatFlagWithSpace(t *testing.T) { + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "test_format_space") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer os.RemoveAll(tempDir) + + // Mock the converter.Get function + originalGet := converter.Get + converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { + return &MockConverter{}, nil + } + defer func() { converter.Get = originalGet }() + + // Set up the command + cmd := &cobra.Command{ + Use: "optimize", + } + cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") + cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") + cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") + cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") + cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") + + // Reset converterType to default before test + converterType = constant.WebP + formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) + cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + + // Test with space-separated format flag (--format webp) + cmd.ParseFlags([]string{"--format", "webp"}) + + // Execute the command + err = ConvertCbzCommand(cmd, []string{tempDir}) + if err != nil { + t.Fatalf("Command execution failed with --format webp: %v", err) + } + + // Verify the format was set correctly + if converterType != constant.WebP { + t.Errorf("Expected format to be WebP, got %v", converterType) + } +} + +// TestFormatFlagWithShortForm tests that the short form of format flag works with space-separated values +func TestFormatFlagWithShortForm(t *testing.T) { + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "test_format_short") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer os.RemoveAll(tempDir) + + // Mock the converter.Get function + originalGet := converter.Get + converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { + return &MockConverter{}, nil + } + defer func() { converter.Get = originalGet }() + + // Set up the command + cmd := &cobra.Command{ + Use: "optimize", + } + cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") + cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") + cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") + cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") + cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") + + // Reset converterType to default before test + converterType = constant.WebP + formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) + cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + + // Test with short form and space (-f webp) + cmd.ParseFlags([]string{"-f", "webp"}) + + // Execute the command + err = ConvertCbzCommand(cmd, []string{tempDir}) + if err != nil { + t.Fatalf("Command execution failed with -f webp: %v", err) + } + + // Verify the format was set correctly + if converterType != constant.WebP { + t.Errorf("Expected format to be WebP, got %v", converterType) + } +} + +// TestFormatFlagWithEquals tests that the format flag works with equals syntax +func TestFormatFlagWithEquals(t *testing.T) { + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "test_format_equals") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer os.RemoveAll(tempDir) + + // Mock the converter.Get function + originalGet := converter.Get + converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { + return &MockConverter{}, nil + } + defer func() { converter.Get = originalGet }() + + // Set up the command + cmd := &cobra.Command{ + Use: "optimize", + } + cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") + cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") + cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") + cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") + cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") + + // Reset converterType to default before test + converterType = constant.WebP + formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) + cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + + // Test with equals syntax (--format=webp) + cmd.ParseFlags([]string{"--format=webp"}) + + // Execute the command + err = ConvertCbzCommand(cmd, []string{tempDir}) + if err != nil { + t.Fatalf("Command execution failed with --format=webp: %v", err) + } + + // Verify the format was set correctly + if converterType != constant.WebP { + t.Errorf("Expected format to be WebP, got %v", converterType) + } +} + +// TestFormatFlagDefaultValue tests that the default format is used when flag is not provided +func TestFormatFlagDefaultValue(t *testing.T) { + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "test_format_default") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer os.RemoveAll(tempDir) + + // Mock the converter.Get function + originalGet := converter.Get + converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { + return &MockConverter{}, nil + } + defer func() { converter.Get = originalGet }() + + // Set up the command + cmd := &cobra.Command{ + Use: "optimize", + } + cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") + cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") + cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") + cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") + cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") + + // Reset converterType to default before test + converterType = constant.DefaultConversion + formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) + cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + + // Don't set format flag - should use default + cmd.ParseFlags([]string{}) + + // Execute the command + err = ConvertCbzCommand(cmd, []string{tempDir}) + if err != nil { + t.Fatalf("Command execution failed with default format: %v", err) + } + + // Verify the default format is used + if converterType != constant.DefaultConversion { + t.Errorf("Expected format to be default (%v), got %v", constant.DefaultConversion, converterType) + } +} + +// TestFormatFlagCaseInsensitive tests that the format flag is case-insensitive +func TestFormatFlagCaseInsensitive(t *testing.T) { + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "test_format_case") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer os.RemoveAll(tempDir) + + // Mock the converter.Get function + originalGet := converter.Get + converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { + return &MockConverter{}, nil + } + defer func() { converter.Get = originalGet }() + + testCases := []string{"webp", "WEBP", "WebP", "WeBp"} + + for _, formatValue := range testCases { + t.Run(formatValue, func(t *testing.T) { + // Set up the command + cmd := &cobra.Command{ + Use: "optimize", + } + cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") + cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") + cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") + cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") + cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") + + // Reset converterType to default before test + converterType = constant.WebP + formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) + cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + + // Test with different case variations + cmd.ParseFlags([]string{"--format", formatValue}) + + // Execute the command + err = ConvertCbzCommand(cmd, []string{tempDir}) + if err != nil { + t.Fatalf("Command execution failed with format '%s': %v", formatValue, err) + } + + // Verify the format was set correctly + if converterType != constant.WebP { + t.Errorf("Expected format to be WebP for input '%s', got %v", formatValue, converterType) + } + }) + } +} diff --git a/cmd/cbzoptimizer/commands/watch_command.go b/cmd/cbzoptimizer/commands/watch_command.go index 5a9105b..8dfcdc4 100644 --- a/cmd/cbzoptimizer/commands/watch_command.go +++ b/cmd/cbzoptimizer/commands/watch_command.go @@ -42,12 +42,11 @@ func init() { command.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout") _ = viper.BindPFlag("timeout", command.Flags().Lookup("timeout")) - command.PersistentFlags().VarP( + command.Flags().VarP( formatFlag, "format", "f", fmt.Sprintf("Format to convert the images to: %s", constant.ListAll())) - command.PersistentFlags().Lookup("format").NoOptDefVal = constant.DefaultConversion.String() - _ = viper.BindPFlag("format", command.PersistentFlags().Lookup("format")) + _ = viper.BindPFlag("format", command.Flags().Lookup("format")) AddCommand(command) } From cd0f056648c0ab55dd6ebbeb521b629ce63e7354 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:22:58 +0000 Subject: [PATCH 3/8] Eliminate code duplication with shared setupFormatFlag function - Extract format flag setup logic into shared flags.go file - Create setupFormatFlag function to eliminate duplication between optimize and watch commands - Add bindViper parameter to support different flag binding strategies - Remove duplicate enumflag imports from command files - All tests continue to pass Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com> --- cmd/cbzoptimizer/commands/flags.go | 26 +++++++++++++++++++ cmd/cbzoptimizer/commands/optimize_command.go | 9 ++----- cmd/cbzoptimizer/commands/watch_command.go | 11 ++------ 3 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 cmd/cbzoptimizer/commands/flags.go diff --git a/cmd/cbzoptimizer/commands/flags.go b/cmd/cbzoptimizer/commands/flags.go new file mode 100644 index 0000000..b6478f2 --- /dev/null +++ b/cmd/cbzoptimizer/commands/flags.go @@ -0,0 +1,26 @@ +package commands + +import ( + "fmt" + + "github.com/belphemur/CBZOptimizer/v2/pkg/converter/constant" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/thediveo/enumflag/v2" +) + +// setupFormatFlag sets up the format flag for a command +// If bindViper is true, it will also bind the flag to viper +func setupFormatFlag(cmd *cobra.Command, converterType *constant.ConversionFormat, bindViper bool) { + formatFlag := enumflag.New(converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) + _ = formatFlag.RegisterCompletion(cmd, "format", constant.HelpText) + + cmd.Flags().VarP( + formatFlag, + "format", "f", + fmt.Sprintf("Format to convert the images to: %s", constant.ListAll())) + + if bindViper { + _ = viper.BindPFlag("format", cmd.Flags().Lookup("format")) + } +} diff --git a/cmd/cbzoptimizer/commands/optimize_command.go b/cmd/cbzoptimizer/commands/optimize_command.go index 82a483a..a512067 100644 --- a/cmd/cbzoptimizer/commands/optimize_command.go +++ b/cmd/cbzoptimizer/commands/optimize_command.go @@ -12,7 +12,6 @@ import ( "github.com/belphemur/CBZOptimizer/v2/pkg/converter/constant" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "github.com/thediveo/enumflag/v2" ) var converterType constant.ConversionFormat @@ -25,18 +24,14 @@ func init() { RunE: ConvertCbzCommand, Args: cobra.ExactArgs(1), } - formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) - _ = formatFlag.RegisterCompletion(command, "format", constant.HelpText) + + setupFormatFlag(command, &converterType, false) command.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") command.Flags().IntP("parallelism", "n", 2, "Number of chapters to convert in parallel") command.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") command.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") command.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout") - command.Flags().VarP( - formatFlag, - "format", "f", - fmt.Sprintf("Format to convert the images to: %s", constant.ListAll())) AddCommand(command) } diff --git a/cmd/cbzoptimizer/commands/watch_command.go b/cmd/cbzoptimizer/commands/watch_command.go index 8dfcdc4..0a95016 100644 --- a/cmd/cbzoptimizer/commands/watch_command.go +++ b/cmd/cbzoptimizer/commands/watch_command.go @@ -13,7 +13,6 @@ import ( "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/thediveo/enumflag/v2" ) func init() { @@ -27,8 +26,8 @@ func init() { RunE: WatchCommand, Args: cobra.ExactArgs(1), } - formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) - _ = formatFlag.RegisterCompletion(command, "format", constant.HelpText) + + setupFormatFlag(command, &converterType, true) command.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") _ = viper.BindPFlag("quality", command.Flags().Lookup("quality")) @@ -42,12 +41,6 @@ func init() { command.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout") _ = viper.BindPFlag("timeout", command.Flags().Lookup("timeout")) - command.Flags().VarP( - formatFlag, - "format", "f", - fmt.Sprintf("Format to convert the images to: %s", constant.ListAll())) - _ = viper.BindPFlag("format", command.Flags().Lookup("format")) - AddCommand(command) } func WatchCommand(_ *cobra.Command, args []string) error { From c5de49a310f988bdf54f4cd56951a650c288c535 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:25:59 +0000 Subject: [PATCH 4/8] Refactor tests to use shared setupFormatFlag and helper function - Create setupTestCommand helper function to reduce test duplication - Update all format flag tests to use shared setupFormatFlag function - Remove unused enumflag import from test file - Ensures test consistency with production code - All tests continue to pass Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com> --- .../commands/optimize_command_test.go | 128 ++++-------------- 1 file changed, 30 insertions(+), 98 deletions(-) diff --git a/cmd/cbzoptimizer/commands/optimize_command_test.go b/cmd/cbzoptimizer/commands/optimize_command_test.go index c758e37..a01a520 100644 --- a/cmd/cbzoptimizer/commands/optimize_command_test.go +++ b/cmd/cbzoptimizer/commands/optimize_command_test.go @@ -15,7 +15,6 @@ import ( "github.com/belphemur/CBZOptimizer/v2/pkg/converter" "github.com/belphemur/CBZOptimizer/v2/pkg/converter/constant" "github.com/spf13/cobra" - "github.com/thediveo/enumflag/v2" ) // MockConverter is a mock implementation of the Converter interface @@ -174,22 +173,17 @@ func TestConvertCbzCommand(t *testing.T) { t.Logf("Found %d converted files", len(convertedFiles)) } -// TestFormatFlagWithSpace tests that the format flag works with space-separated values -func TestFormatFlagWithSpace(t *testing.T) { - // Create a temporary directory for testing - tempDir, err := os.MkdirTemp("", "test_format_space") - if err != nil { - t.Fatalf("Failed to create temp directory: %v", err) - } - defer os.RemoveAll(tempDir) - +// setupTestCommand creates a test command with all required flags +func setupTestCommand(t *testing.T) (*cobra.Command, func()) { + t.Helper() + // Mock the converter.Get function originalGet := converter.Get converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { return &MockConverter{}, nil } - defer func() { converter.Get = originalGet }() - + cleanup := func() { converter.Get = originalGet } + // Set up the command cmd := &cobra.Command{ Use: "optimize", @@ -202,8 +196,22 @@ func TestFormatFlagWithSpace(t *testing.T) { // Reset converterType to default before test converterType = constant.WebP - formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) - cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + setupFormatFlag(cmd, &converterType, false) + + return cmd, cleanup +} + +// TestFormatFlagWithSpace tests that the format flag works with space-separated values +func TestFormatFlagWithSpace(t *testing.T) { + // Create a temporary directory for testing + tempDir, err := os.MkdirTemp("", "test_format_space") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer os.RemoveAll(tempDir) + + cmd, cleanup := setupTestCommand(t) + defer cleanup() // Test with space-separated format flag (--format webp) cmd.ParseFlags([]string{"--format", "webp"}) @@ -229,27 +237,8 @@ func TestFormatFlagWithShortForm(t *testing.T) { } defer os.RemoveAll(tempDir) - // Mock the converter.Get function - originalGet := converter.Get - converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { - return &MockConverter{}, nil - } - defer func() { converter.Get = originalGet }() - - // Set up the command - cmd := &cobra.Command{ - Use: "optimize", - } - cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") - cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") - cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") - cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") - cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") - - // Reset converterType to default before test - converterType = constant.WebP - formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) - cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + cmd, cleanup := setupTestCommand(t) + defer cleanup() // Test with short form and space (-f webp) cmd.ParseFlags([]string{"-f", "webp"}) @@ -275,27 +264,8 @@ func TestFormatFlagWithEquals(t *testing.T) { } defer os.RemoveAll(tempDir) - // Mock the converter.Get function - originalGet := converter.Get - converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { - return &MockConverter{}, nil - } - defer func() { converter.Get = originalGet }() - - // Set up the command - cmd := &cobra.Command{ - Use: "optimize", - } - cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") - cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") - cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") - cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") - cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") - - // Reset converterType to default before test - converterType = constant.WebP - formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) - cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + cmd, cleanup := setupTestCommand(t) + defer cleanup() // Test with equals syntax (--format=webp) cmd.ParseFlags([]string{"--format=webp"}) @@ -321,27 +291,8 @@ func TestFormatFlagDefaultValue(t *testing.T) { } defer os.RemoveAll(tempDir) - // Mock the converter.Get function - originalGet := converter.Get - converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { - return &MockConverter{}, nil - } - defer func() { converter.Get = originalGet }() - - // Set up the command - cmd := &cobra.Command{ - Use: "optimize", - } - cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") - cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") - cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") - cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") - cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") - - // Reset converterType to default before test - converterType = constant.DefaultConversion - formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) - cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + cmd, cleanup := setupTestCommand(t) + defer cleanup() // Don't set format flag - should use default cmd.ParseFlags([]string{}) @@ -367,31 +318,12 @@ func TestFormatFlagCaseInsensitive(t *testing.T) { } defer os.RemoveAll(tempDir) - // Mock the converter.Get function - originalGet := converter.Get - converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { - return &MockConverter{}, nil - } - defer func() { converter.Get = originalGet }() - testCases := []string{"webp", "WEBP", "WebP", "WeBp"} for _, formatValue := range testCases { t.Run(formatValue, func(t *testing.T) { - // Set up the command - cmd := &cobra.Command{ - Use: "optimize", - } - cmd.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") - cmd.Flags().IntP("parallelism", "n", 1, "Number of chapters to convert in parallel") - cmd.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") - cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") - cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") - - // Reset converterType to default before test - converterType = constant.WebP - formatFlag := enumflag.New(&converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) - cmd.Flags().VarP(formatFlag, "format", "f", "Format to convert the images to") + cmd, cleanup := setupTestCommand(t) + defer cleanup() // Test with different case variations cmd.ParseFlags([]string{"--format", formatValue}) From 3a2fb2a97ec295f8dce8c9e86a9fc7f1cd9695d3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:27:28 +0000 Subject: [PATCH 5/8] Add comprehensive documentation to shared functions - Add detailed docstring to setupFormatFlag explaining parameters and usage - Add detailed docstring to setupTestCommand explaining return values - Use constant.DefaultConversion instead of hard-coded constant.WebP for better maintainability - Clarify when bindViper should be true vs false Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com> --- cmd/cbzoptimizer/commands/flags.go | 10 ++++++++-- cmd/cbzoptimizer/commands/optimize_command_test.go | 11 ++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cmd/cbzoptimizer/commands/flags.go b/cmd/cbzoptimizer/commands/flags.go index b6478f2..6bd6db6 100644 --- a/cmd/cbzoptimizer/commands/flags.go +++ b/cmd/cbzoptimizer/commands/flags.go @@ -9,8 +9,14 @@ import ( "github.com/thediveo/enumflag/v2" ) -// setupFormatFlag sets up the format flag for a command -// If bindViper is true, it will also bind the flag to viper +// setupFormatFlag sets up the format flag for a command. +// +// Parameters: +// - cmd: The Cobra command to add the format flag to +// - converterType: Pointer to the ConversionFormat variable that will store the flag value +// - bindViper: If true, binds the flag to viper for configuration file support. +// Set to true for commands that use viper for configuration (e.g., watch command), +// and false for commands that don't (e.g., optimize command). func setupFormatFlag(cmd *cobra.Command, converterType *constant.ConversionFormat, bindViper bool) { formatFlag := enumflag.New(converterType, "format", constant.CommandValue, enumflag.EnumCaseInsensitive) _ = formatFlag.RegisterCompletion(cmd, "format", constant.HelpText) diff --git a/cmd/cbzoptimizer/commands/optimize_command_test.go b/cmd/cbzoptimizer/commands/optimize_command_test.go index a01a520..65e92ef 100644 --- a/cmd/cbzoptimizer/commands/optimize_command_test.go +++ b/cmd/cbzoptimizer/commands/optimize_command_test.go @@ -173,7 +173,12 @@ func TestConvertCbzCommand(t *testing.T) { t.Logf("Found %d converted files", len(convertedFiles)) } -// setupTestCommand creates a test command with all required flags +// setupTestCommand creates a test command with all required flags for testing. +// It mocks the converter.Get function and sets up a complete command with all flags. +// +// Returns: +// - *cobra.Command: A configured command ready for testing +// - func(): A cleanup function that must be deferred to restore the original converter.Get func setupTestCommand(t *testing.T) (*cobra.Command, func()) { t.Helper() @@ -194,8 +199,8 @@ func setupTestCommand(t *testing.T) (*cobra.Command, func()) { cmd.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter") - // Reset converterType to default before test - converterType = constant.WebP + // Reset converterType to default before test for consistency + converterType = constant.DefaultConversion setupFormatFlag(cmd, &converterType, false) return cmd, cleanup From b80535d211f6e265b4bfbd3da0483f4ce199aa33 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:28:36 +0000 Subject: [PATCH 6/8] Fix formatting in setupTestCommand function - Remove extra blank line after t.Helper() for Go formatting consistency Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com> --- cmd/cbzoptimizer/commands/optimize_command_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/cbzoptimizer/commands/optimize_command_test.go b/cmd/cbzoptimizer/commands/optimize_command_test.go index 65e92ef..5fd853b 100644 --- a/cmd/cbzoptimizer/commands/optimize_command_test.go +++ b/cmd/cbzoptimizer/commands/optimize_command_test.go @@ -181,7 +181,6 @@ func TestConvertCbzCommand(t *testing.T) { // - func(): A cleanup function that must be deferred to restore the original converter.Get func setupTestCommand(t *testing.T) (*cobra.Command, func()) { t.Helper() - // Mock the converter.Get function originalGet := converter.Get converter.Get = func(format constant.ConversionFormat) (converter.Converter, error) { From 9b6a7330121d12f338b8cd803e792d5843465b3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:29:34 +0000 Subject: [PATCH 7/8] Complete format flag fix with all requirements met All changes completed and verified Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com> --- go.sum | 46 ++++------------------------------------------ 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/go.sum b/go.sum index 4f899f6..6fd0934 100644 --- a/go.sum +++ b/go.sum @@ -124,18 +124,12 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D 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.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mholt/archives v0.1.3 h1:aEAaOtNra78G+TvV5ohmXrJOAzf++dIlYeDW3N9q458= -github.com/mholt/archives v0.1.3/go.mod h1:LUCGp++/IbV/I0Xq4SzcIR6uwgeh2yjnQWamjRQfLTU= -github.com/mholt/archives v0.1.4 h1:sU+/lLNgafUontWFv3AVwO8VUWye3rrtN6hgC2dU11c= -github.com/mholt/archives v0.1.4/go.mod h1:I2ia+SQTtQHej9w1GZM/mz7qfdgQv+BHr3hEKqDcGuk= github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ= github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4= github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0= github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc= github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A= github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= -github.com/nwaples/rardecode/v2 v2.1.1 h1:OJaYalXdliBUXPmC8CZGQ7oZDxzX1/5mQmgn0/GASew= -github.com/nwaples/rardecode/v2 v2.1.1/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= @@ -166,8 +160,6 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= -github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI= -github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg= @@ -181,8 +173,6 @@ github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= -github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -235,32 +225,10 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= -golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= -golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= -golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A= -golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA= -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= -golang.org/x/exp v0.0.0-20251017212417-90e834f514db h1:by6IehL4BH5k3e3SJmcoNbOobMey2SLpAF79iPOEBvw= -golang.org/x/exp v0.0.0-20251017212417-90e834f514db/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= -golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= -golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= -golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0= -golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.31.0 h1:mLChjE2MV6g1S7oqbXC0/UcKijjm5fnJLUYKIYrLESA= -golang.org/x/image v0.31.0/go.mod h1:R9ec5Lcp96v9FTF+ajwaH3uGxPH4fKfHHAVbUILxghA= -golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ= -golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc= -golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ= -golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc= golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8= golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -309,8 +277,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -343,12 +311,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -378,8 +340,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= -golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 44e2469e34100e518ff475ed54d1773a90649078 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:38:58 +0000 Subject: [PATCH 8/8] Consolidate all common flags into flags.go - Create individual setup functions for each common flag (quality, override, split, timeout) - Create setupCommonFlags function that sets up all common flags in one call - Simplify optimize_command.go and watch_command.go by using setupCommonFlags - All flags now centralized in flags.go for better maintainability - All tests continue to pass Co-authored-by: Belphemur <197810+Belphemur@users.noreply.github.com> --- cmd/cbzoptimizer/commands/flags.go | 68 +++++++++++++++++++ cmd/cbzoptimizer/commands/optimize_command.go | 10 ++- cmd/cbzoptimizer/commands/watch_command.go | 15 +--- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/cmd/cbzoptimizer/commands/flags.go b/cmd/cbzoptimizer/commands/flags.go index 6bd6db6..81b26fb 100644 --- a/cmd/cbzoptimizer/commands/flags.go +++ b/cmd/cbzoptimizer/commands/flags.go @@ -30,3 +30,71 @@ func setupFormatFlag(cmd *cobra.Command, converterType *constant.ConversionForma _ = viper.BindPFlag("format", cmd.Flags().Lookup("format")) } } + +// setupQualityFlag sets up the quality flag for a command. +// +// Parameters: +// - cmd: The Cobra command to add the quality flag to +// - defaultValue: The default quality value (0-100) +// - bindViper: If true, binds the flag to viper for configuration file support +func setupQualityFlag(cmd *cobra.Command, defaultValue uint8, bindViper bool) { + cmd.Flags().Uint8P("quality", "q", defaultValue, "Quality for conversion (0-100)") + if bindViper { + _ = viper.BindPFlag("quality", cmd.Flags().Lookup("quality")) + } +} + +// setupOverrideFlag sets up the override flag for a command. +// +// Parameters: +// - cmd: The Cobra command to add the override flag to +// - defaultValue: The default override value +// - bindViper: If true, binds the flag to viper for configuration file support +func setupOverrideFlag(cmd *cobra.Command, defaultValue bool, bindViper bool) { + cmd.Flags().BoolP("override", "o", defaultValue, "Override the original CBZ/CBR files") + if bindViper { + _ = viper.BindPFlag("override", cmd.Flags().Lookup("override")) + } +} + +// setupSplitFlag sets up the split flag for a command. +// +// Parameters: +// - cmd: The Cobra command to add the split flag to +// - defaultValue: The default split value +// - bindViper: If true, binds the flag to viper for configuration file support +func setupSplitFlag(cmd *cobra.Command, defaultValue bool, bindViper bool) { + cmd.Flags().BoolP("split", "s", defaultValue, "Split long pages into smaller chunks") + if bindViper { + _ = viper.BindPFlag("split", cmd.Flags().Lookup("split")) + } +} + +// setupTimeoutFlag sets up the timeout flag for a command. +// +// Parameters: +// - cmd: The Cobra command to add the timeout flag to +// - bindViper: If true, binds the flag to viper for configuration file support +func setupTimeoutFlag(cmd *cobra.Command, bindViper bool) { + cmd.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout") + if bindViper { + _ = viper.BindPFlag("timeout", cmd.Flags().Lookup("timeout")) + } +} + +// setupCommonFlags sets up all common flags for optimize and watch commands. +// +// Parameters: +// - cmd: The Cobra command to add the flags to +// - converterType: Pointer to the ConversionFormat variable that will store the format flag value +// - qualityDefault: The default quality value (0-100) +// - overrideDefault: The default override value +// - splitDefault: The default split value +// - bindViper: If true, binds all flags to viper for configuration file support +func setupCommonFlags(cmd *cobra.Command, converterType *constant.ConversionFormat, qualityDefault uint8, overrideDefault bool, splitDefault bool, bindViper bool) { + setupFormatFlag(cmd, converterType, bindViper) + setupQualityFlag(cmd, qualityDefault, bindViper) + setupOverrideFlag(cmd, overrideDefault, bindViper) + setupSplitFlag(cmd, splitDefault, bindViper) + setupTimeoutFlag(cmd, bindViper) +} diff --git a/cmd/cbzoptimizer/commands/optimize_command.go b/cmd/cbzoptimizer/commands/optimize_command.go index a512067..0ab6427 100644 --- a/cmd/cbzoptimizer/commands/optimize_command.go +++ b/cmd/cbzoptimizer/commands/optimize_command.go @@ -25,13 +25,11 @@ func init() { Args: cobra.ExactArgs(1), } - setupFormatFlag(command, &converterType, false) - - command.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") + // Setup common flags (format, quality, override, split, timeout) + setupCommonFlags(command, &converterType, 85, false, false, false) + + // Setup optimize-specific flags command.Flags().IntP("parallelism", "n", 2, "Number of chapters to convert in parallel") - command.Flags().BoolP("override", "o", false, "Override the original CBZ/CBR files") - command.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") - command.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout") AddCommand(command) } diff --git a/cmd/cbzoptimizer/commands/watch_command.go b/cmd/cbzoptimizer/commands/watch_command.go index 0a95016..ad322d5 100644 --- a/cmd/cbzoptimizer/commands/watch_command.go +++ b/cmd/cbzoptimizer/commands/watch_command.go @@ -27,19 +27,8 @@ func init() { Args: cobra.ExactArgs(1), } - setupFormatFlag(command, &converterType, true) - - command.Flags().Uint8P("quality", "q", 85, "Quality for conversion (0-100)") - _ = viper.BindPFlag("quality", command.Flags().Lookup("quality")) - - command.Flags().BoolP("override", "o", true, "Override the original CBZ/CBR files") - _ = viper.BindPFlag("override", command.Flags().Lookup("override")) - - command.Flags().BoolP("split", "s", false, "Split long pages into smaller chunks") - _ = viper.BindPFlag("split", command.Flags().Lookup("split")) - - command.Flags().DurationP("timeout", "t", 0, "Maximum time allowed for converting a single chapter (e.g., 30s, 5m, 1h). 0 means no timeout") - _ = viper.BindPFlag("timeout", command.Flags().Lookup("timeout")) + // Setup common flags (format, quality, override, split, timeout) with viper binding + setupCommonFlags(command, &converterType, 85, true, false, true) AddCommand(command) }