Commit ca7f924b authored by Mickaël Desfrênes's avatar Mickaël Desfrênes
Browse files

climax basex command to forward all cli flags to the java cli

parent 3f971414
Loading
Loading
Loading
Loading
+58 −1
Changes for cli.go: 58 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@ package main

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/spf13/cobra"
)
@@ -221,14 +223,23 @@ func newSyncCmd() *cobra.Command {
	return cmd
}

// newBasexCmd is intentionally wired differently from the other climax
// commands: BaseX has its own CLI flags, so Cobra must not parse or reject
// unknown options before Java sees them. Only climax-owned options are handled
// here; everything else is forwarded to org.basex.BaseX.
func newBasexCmd() *cobra.Command {
	directory := cwd()
	verbose := false
	cmd := &cobra.Command{
		Use:                "basex",
		Short:              T("cmd.basex.short"),
		DisableFlagParsing: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runBasex(directory, verbose)
			opts, err := parseBasexArgs(args, directory, verbose)
			if err != nil {
				return err
			}
			return runBasex(opts.directory, opts.verbose, opts.forwarded)
		},
	}
	cmd.Flags().StringVar(&directory, "directory", directory, T("flag.common.directory"))
@@ -236,6 +247,52 @@ func newBasexCmd() *cobra.Command {
	return cmd
}

type basexArgs struct {
	directory string
	verbose   bool
	forwarded []string
}

// parseBasexArgs recognizes only climax's wrapper options and leaves BaseX
// arguments untouched. --directory and --verbose affect climax; -- stops
// wrapper parsing; --help is deliberately forwarded to BaseX, so local command
// help remains available via `climax help basex`.
func parseBasexArgs(args []string, directory string, verbose bool) (basexArgs, error) {
	opts := basexArgs{
		directory: directory,
		verbose:   verbose,
		forwarded: make([]string, 0, len(args)),
	}
	for i := 0; i < len(args); i++ {
		arg := args[i]
		switch {
		case arg == "--":
			opts.forwarded = append(opts.forwarded, args[i+1:]...)
			return opts, nil
		case arg == "--directory":
			if i+1 >= len(args) {
				return opts, fmt.Errorf(T("err.flag_needs_argument"), "--directory")
			}
			i++
			opts.directory = args[i]
		case strings.HasPrefix(arg, "--directory="):
			opts.directory = strings.TrimPrefix(arg, "--directory=")
		case arg == "--verbose":
			opts.verbose = true
		case strings.HasPrefix(arg, "--verbose="):
			value := strings.TrimPrefix(arg, "--verbose=")
			parsed, err := strconv.ParseBool(value)
			if err != nil {
				return opts, fmt.Errorf(T("err.invalid_bool_flag"), value, "--verbose")
			}
			opts.verbose = parsed
		default:
			opts.forwarded = append(opts.forwarded, arg)
		}
	}
	return opts, nil
}

func newBasexGUICmd() *cobra.Command {
	directory := cwd()
	verbose := false
+1 −1
Changes for cli_commands_test.go: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -128,7 +128,7 @@ func TestHelpRunsForAllCLICommands(t *testing.T) {
			{"bundles-remove", "dummy", "--help"},
			{"feed", "dummy", "--help"},
			{"sync", "--help"},
			{"basex", "--help"},
			{"help", "basex"},
			{"basex-gui", "--help"},
			{"templates-list", "--help"},
			{"static-list", "--help"},
+2 −2
Changes for commands.go: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -408,12 +408,12 @@ func runSync(directory string) error {
	return errors.New(T("err.no_max_use_new"))
}

func runBasex(directory string, verbose bool) error {
func runBasex(directory string, verbose bool, args []string) error {
	abs, _, err := loadProject(directory)
	if err != nil {
		return err
	}
	cmd, err := newBaseXCommand(abs, "org.basex.BaseX")
	cmd, err := newBaseXCommand(abs, "org.basex.BaseX", args...)
	if err != nil {
		return err
	}
+4 −0
Changes for i18n.go: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -129,6 +129,8 @@ commandes new, projects et cache-clear qui peuvent être lancées aussi en dehor
		"err.invalid_max_archive":     "archive MaX invalide ou non prise en charge: %s",
		"err.invalid_mirrored_path":   "chemin de copie statique invalide %s",
		"err.not_max_config":          "%s n'est pas un fichier de configuration MaX",
		"err.flag_needs_argument":     "l'option %s attend une valeur",
		"err.invalid_bool_flag":       "valeur booléenne invalide %q pour %s",
	},
	localeEN: {
		"app.short": "CLI tool for MaX",
@@ -245,6 +247,8 @@ which can also be run outside a MaX directory.`,
		"err.invalid_max_archive":     "invalid or unsupported MaX archive: %s",
		"err.invalid_mirrored_path":   "invalid mirrored path %s",
		"err.not_max_config":          "%s is not a MaX configuration file",
		"err.flag_needs_argument":     "flag %s needs an argument",
		"err.invalid_bool_flag":       "invalid boolean value %q for %s",
	},
}

+56 −0
Changes for main_test.go: 56 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -1052,6 +1052,62 @@ func TestBasexGUICommandRunsGUIClass(t *testing.T) {
	}
}

func TestBasexCommandForwardsBaseXFlags(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("test uses a shell script as fake bundled java")
	}

	tmpHome := t.TempDir()
	prevHome := userMaxDir
	prevCache := cacheDir
	userMaxDir = tmpHome
	cacheDir = filepath.Join(userMaxDir, "cache")
	t.Cleanup(func() {
		userMaxDir = prevHome
		cacheDir = prevCache
	})

	projectDir := filepath.Join(t.TempDir(), "project")
	if err := os.MkdirAll(projectDir, 0o755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(filepath.Join(projectDir, maxConfigFile), []byte(configInitTemplate), 0o644); err != nil {
		t.Fatal(err)
	}

	logPath := filepath.Join(t.TempDir(), "java.log")
	t.Setenv("CLIMAX_TEST_JAVA_LOG", logPath)
	if err := installFakeBundledJava(tmpHome); err != nil {
		t.Fatal(err)
	}

	root := newRootCmd()
	root.SetArgs([]string{
		"basex",
		"--directory", projectDir,
		"--help",
		"-q", "1",
		"--serialize", "method=json",
	})
	if err := root.Execute(); err != nil {
		t.Fatalf("basex command failed: %v", err)
	}

	lines, err := readLogLines(logPath)
	if err != nil {
		t.Fatal(err)
	}
	if len(lines) != 1 {
		t.Fatalf("expected one java invocation, got %d:\n%v", len(lines), lines)
	}
	if !strings.Contains(lines[0], "org.basex.BaseX --help -q 1 --serialize method=json") {
		t.Fatalf("expected BaseX flags to be forwarded, got:\n%s", lines[0])
	}
	if strings.Contains(lines[0], "--directory "+projectDir) {
		t.Fatalf("expected climax --directory flag not to be forwarded, got:\n%s", lines[0])
	}
}

// Ensures bundle installation runs with the project as the working directory,
// regardless of where the CLI process was started.
func TestBundleInstallRunsFromProjectDirectory(t *testing.T) {