From 71bb85659baa11d14023166d835487e39b0c9391 Mon Sep 17 00:00:00 2001 From: Joseph Date: Thu, 24 Jul 2025 12:42:06 -0400 Subject: [PATCH] Help text and makefile --- Makefile | 126 +++++++++++++++++++++++++++++++++++++++++++++++++--- README.md | 16 +++++-- cmd/root.go | 35 ++++++++++++++- 3 files changed, 166 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 336d5c35..81dcda0b 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # Variables BINARY_NAME = kubectl-oadp -INSTALL_PATH ?= /usr/local/bin +INSTALL_PATH ?= $(HOME)/.local/bin VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") # Centralized platform definitions to avoid duplication @@ -30,6 +30,17 @@ help: ## Show this help message @echo "Available targets:" @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) @echo "" + @echo "Installation options:" + @echo " \033[36mmake install\033[0m # Install to ~/.local/bin (recommended, no sudo)" + @echo " \033[36mmake install-user\033[0m # Same as install (legacy alias)" + @echo " \033[36mmake install-bin\033[0m # Install to ~/bin (alternative, no sudo)" + @echo " \033[36mmake install-system\033[0m # Install to /usr/local/bin (requires sudo)" + @echo "" + @echo "Uninstall options:" + @echo " \033[36mmake uninstall\033[0m # Remove from user locations (no sudo)" + @echo " \033[36mmake uninstall-system\033[0m # Remove from system locations (requires sudo)" + @echo " \033[36mmake uninstall-all\033[0m # Remove from all locations (user + system)" + @echo "" @echo "Build with different platforms:" @echo " make build PLATFORM=linux/amd64" @echo " make build PLATFORM=linux/arm64" @@ -59,11 +70,116 @@ build: ## Build the kubectl plugin binary (use PLATFORM=os/arch for cross-compil # Installation targets .PHONY: install -install: build ## Build and install the kubectl plugin +install: build ## Build and install the kubectl plugin to ~/.local/bin (no sudo required) @echo "Installing $(BINARY_NAME) to $(INSTALL_PATH)..." - mv $(BINARY_NAME) $(INSTALL_PATH)/ - @echo "✅ $(BINARY_NAME) installed successfully!" - @echo "You can now use: kubectl oadp --help" + @mkdir -p $(INSTALL_PATH) + cp $(BINARY_NAME) $(INSTALL_PATH)/ + @echo "✅ Installed to $(INSTALL_PATH)" + @echo "" + @PATH_UPDATED=false; \ + PATH_IN_CONFIG=false; \ + if [[ ":$$PATH:" != *":$(INSTALL_PATH):"* ]]; then \ + if [[ "$$SHELL" == */zsh* ]] && [[ -f "$$HOME/.zshrc" ]]; then \ + if ! grep -q "/.local/bin" "$$HOME/.zshrc" 2>/dev/null; then \ + echo 'export PATH="$$HOME/.local/bin:$$PATH"' >> "$$HOME/.zshrc"; \ + echo "✅ Added to ~/.zshrc"; \ + PATH_UPDATED=true; \ + else \ + echo "ℹ️ Already configured in ~/.zshrc"; \ + PATH_IN_CONFIG=true; \ + fi; \ + elif [[ "$$SHELL" == */bash* ]] && [[ -f "$$HOME/.bashrc" ]]; then \ + if ! grep -q "/.local/bin" "$$HOME/.bashrc" 2>/dev/null; then \ + echo 'export PATH="$$HOME/.local/bin:$$PATH"' >> "$$HOME/.bashrc"; \ + echo "✅ Added to ~/.bashrc"; \ + PATH_UPDATED=true; \ + else \ + echo "ℹ️ Already configured in ~/.bashrc"; \ + PATH_IN_CONFIG=true; \ + fi; \ + else \ + echo "⚠️ Add to your shell config: export PATH=\"$(INSTALL_PATH):$$PATH\""; \ + PATH_UPDATED=true; \ + fi; \ + else \ + echo "✅ PATH already configured"; \ + fi; \ + echo ""; \ + if [[ "$$PATH_UPDATED" == "true" ]] || [[ "$$PATH_IN_CONFIG" == "true" ]]; then \ + echo "🔄 Restart terminal or run: source ~/.zshrc"; \ + fi; \ + echo "Test: kubectl oadp --help" + +.PHONY: install-user +install-user: build ## Build and install the kubectl plugin to ~/.local/bin (no sudo required) + @echo "Installing $(BINARY_NAME) to ~/.local/bin..." + @mkdir -p ~/.local/bin + cp $(BINARY_NAME) ~/.local/bin/ + @echo "✅ Installed to ~/.local/bin" + @echo "Add to PATH: export PATH=\"\$$HOME/.local/bin:\$$PATH\"" + @echo "Test: kubectl oadp --help" + +.PHONY: install-bin +install-bin: build ## Build and install the kubectl plugin to ~/bin (no sudo required) + @echo "Installing $(BINARY_NAME) to ~/bin..." + @mkdir -p ~/bin + cp $(BINARY_NAME) ~/bin/ + @echo "✅ Installed to ~/bin" + @echo "Add to PATH: export PATH=\"\$$HOME/bin:\$$PATH\"" + @echo "Test: kubectl oadp --help" + +.PHONY: install-system +install-system: build ## Build and install the kubectl plugin to /usr/local/bin (requires sudo) + @echo "Installing $(BINARY_NAME) to /usr/local/bin..." + @sudo mv $(BINARY_NAME) /usr/local/bin/ + @echo "✅ Installed to /usr/local/bin" + @echo "Test: kubectl oadp --help" + +.PHONY: uninstall +uninstall: ## Uninstall the kubectl plugin from user locations + @echo "Removing $(BINARY_NAME) from user locations..." + @removed=false; \ + if [ -f "$(INSTALL_PATH)/$(BINARY_NAME)" ]; then \ + rm -f "$(INSTALL_PATH)/$(BINARY_NAME)"; \ + echo "✅ Removed from $(INSTALL_PATH)"; \ + removed=true; \ + fi; \ + if [ -f "$$HOME/.local/bin/$(BINARY_NAME)" ] && [ "$(INSTALL_PATH)" != "$$HOME/.local/bin" ]; then \ + rm -f "$$HOME/.local/bin/$(BINARY_NAME)"; \ + echo "✅ Removed from ~/.local/bin"; \ + removed=true; \ + fi; \ + if [ -f "$$HOME/bin/$(BINARY_NAME)" ] && [ "$(INSTALL_PATH)" != "$$HOME/bin" ]; then \ + rm -f "$$HOME/bin/$(BINARY_NAME)"; \ + echo "✅ Removed from ~/bin"; \ + removed=true; \ + fi; \ + if [ "$$removed" = "false" ]; then \ + echo "⚠️ Not found in user locations"; \ + fi + +.PHONY: uninstall-system +uninstall-system: ## Uninstall the kubectl plugin from system locations (requires sudo) + @echo "Removing $(BINARY_NAME) from system locations..." + @removed=false; \ + if [ -f "/usr/local/bin/$(BINARY_NAME)" ]; then \ + sudo rm -f "/usr/local/bin/$(BINARY_NAME)"; \ + echo "✅ Removed from /usr/local/bin"; \ + removed=true; \ + fi; \ + if [ -f "/usr/bin/$(BINARY_NAME)" ]; then \ + sudo rm -f "/usr/bin/$(BINARY_NAME)"; \ + echo "✅ Removed from /usr/bin"; \ + removed=true; \ + fi; \ + if [ "$$removed" = "false" ]; then \ + echo "⚠️ Not found in system locations"; \ + fi + +.PHONY: uninstall-all +uninstall-all: ## Uninstall the kubectl plugin from all locations (user + system) + @make --no-print-directory uninstall + @make --no-print-directory uninstall-system # Testing targets .PHONY: test diff --git a/README.md b/README.md index d0712418..5e76999c 100644 --- a/README.md +++ b/README.md @@ -46,14 +46,22 @@ kubectl oadp --help ### Manual Build and Install ```sh -# Build and install directly +# Recommended: Rootless install (no sudo required) make install -# Or build manually -make build -sudo mv kubectl-oadp /usr/local/bin/ +# After install, refresh your terminal: +source ~/.zshrc # or ~/.bashrc +# OR restart your terminal + +# Test the installation +kubectl oadp --help + +# Alternative: System-wide install (requires sudo) +make install-system ``` +**💡 Important:** After installation, you may need to refresh your terminal or run `source ~/.zshrc` (or `~/.bashrc`) for the `kubectl oadp` command to work. + ## Usage Guide ### Non-Admin Backup Operations diff --git a/cmd/root.go b/cmd/root.go index c0e8fc39..53c95f65 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -67,10 +67,18 @@ func NewVeleroRootCommand() *cobra.Command { // This factory uses the current kubeconfig context namespace instead of hardcoded openshift-adp nonAdminFactory := nonadmin.NewNonAdminFactory() + // Create the commands and modify their help text before adding them + backupCmd := backup.NewCommand(veleroFactory) + restoreCmd := restore.NewCommand(veleroFactory) + + // Modify help text to replace "velero" with "oadp" + updateCommandHelpText(backupCmd, usagePrefix) + updateCommandHelpText(restoreCmd, usagePrefix) + // Add subcommands to the root command rootCmd.AddCommand(version.NewCommand(veleroFactory)) - rootCmd.AddCommand(backup.NewCommand(veleroFactory)) - rootCmd.AddCommand(restore.NewCommand(veleroFactory)) + rootCmd.AddCommand(backupCmd) + rootCmd.AddCommand(restoreCmd) // Custom subcommands - use NonAdmin factory rootCmd.AddCommand(nonadmin.NewNonAdminCommand(nonAdminFactory)) @@ -78,6 +86,29 @@ func NewVeleroRootCommand() *cobra.Command { return rootCmd } +// updateCommandHelpText recursively updates help text in commands and subcommands +func updateCommandHelpText(cmd *cobra.Command, usagePrefix string) { + // Update examples that contain "velero" + if strings.Contains(cmd.Example, "velero") { + cmd.Example = strings.ReplaceAll(cmd.Example, "velero", usagePrefix) + } + + // Update long description if it contains "velero" + if strings.Contains(cmd.Long, "velero") { + cmd.Long = strings.ReplaceAll(cmd.Long, "velero", "oadp") + } + + // Update short description if it contains "velero" + if strings.Contains(cmd.Short, "velero") { + cmd.Short = strings.ReplaceAll(cmd.Short, "velero", "oadp") + } + + // Recursively update subcommands + for _, subCmd := range cmd.Commands() { + updateCommandHelpText(subCmd, usagePrefix) + } +} + func Execute() { if err := NewVeleroRootCommand().Execute(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err)