From 00ec3f5f541de77fbd6e508da905473e3caee34b Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Mon, 23 Dec 2024 09:26:43 -0600 Subject: [PATCH 01/25] fix makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 406d8486bf79..ae1fbf841734 100644 --- a/Makefile +++ b/Makefile @@ -151,7 +151,7 @@ dump-test-schema: # GO_TEST_EXTRA_FLAGS: Used to specify other arguments to `go test`. # GO_TEST_MAKE_FLAGS: Internal var used by other targets to add arguments to `go test`. # -PKG_TO_TEST := "" # default to empty string; can be overridden on command line. +PKG_TO_TEST := "" go_test_pkg_to_test := $(addprefix ./,$(PKG_TO_TEST)) # set paths for packages to test dlv_test_pkg_to_test := $(addprefix github.com/fleetdm/fleet/v4/,$(PKG_TO_TEST)) # set URIs for packages to debug From ffeba6e29aaa2e83bf8f8ad728303821c33c56d7 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Mon, 23 Dec 2024 11:02:32 -0600 Subject: [PATCH 02/25] start help --- Makefile | 23 +++++++++ tools/fdm/main.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 tools/fdm/main.go diff --git a/Makefile b/Makefile index ae1fbf841734..f3efb556d815 100644 --- a/Makefile +++ b/Makefile @@ -117,6 +117,9 @@ help: build: fleet fleetctl +fdm: + go build -o build/fdm ./tools/fdm + fleet: .prefix .pre-build .pre-fleet CGO_ENABLED=1 go build -race=${GO_BUILD_RACE_ENABLED_VAR} -tags full,fts5,netgo -o build/${OUTPUT} -ldflags ${LDFLAGS_VERSION} ./cmd/fleet @@ -582,3 +585,23 @@ db-replica-reset: fleet # db-replica-run runs fleet serve with one main and one read MySQL instance. db-replica-run: fleet FLEET_MYSQL_ADDRESS=127.0.0.1:3308 FLEET_MYSQL_READ_REPLICA_ADDRESS=127.0.0.1:3309 FLEET_MYSQL_READ_REPLICA_USERNAME=fleet FLEET_MYSQL_READ_REPLICA_DATABASE=fleet FLEET_MYSQL_READ_REPLICA_PASSWORD=insecure ./build/fleet serve --dev --dev_license + +.help-short--do-help: + @echo do something + +.help-short--do-help2: + @echo do another thing + +.help-short--some-very-long-command-name: + @echo here's some help + + +do-help: + @echo Available Commands: + @targets=$$(awk '/^[^#[:space:]].*:/ {print $$1}' Makefile | grep '^\.help-short--' | sed 's/:$$//'); \ + if [ -n "$$targets" ]; then \ + output=$$(make --no-print-directory $$targets 2>/dev/null); \ + paste <(echo "$$targets" | sed 's/^\.help-short--/make /') <(echo "-- $$output") | column -t -s $$'\t'; \ + else \ + echo "No help targets found."; \ + fi \ No newline at end of file diff --git a/tools/fdm/main.go b/tools/fdm/main.go new file mode 100644 index 000000000000..72b69104ba83 --- /dev/null +++ b/tools/fdm/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + // Ensure there's a make target specified + if len(os.Args) < 2 { + fmt.Println("Usage: fdm [--option=value ...] -- [make-options]") + os.Exit(1) + } + + // Determine the path to the top-level directory (where the Makefile resides) + repoRoot, err := getRepoRoot() + if err != nil { + fmt.Printf("Error determining repo root: %v\n", err) + os.Exit(1) + } + + // Change the working directory to the repo root + if err := os.Chdir(repoRoot); err != nil { + fmt.Printf("Error changing directory to repo root: %v\n", err) + os.Exit(1) + } + + // Extract the make target + makeTarget := os.Args[1] + + // Split arguments into options and make arguments + options, makeArgs := splitArgs(os.Args[2:]) + + // Transform options into Makefile-compatible environment variables + envVars := transformToMakeVars(options) + + // Call the Makefile with the specified target, environment variables, and additional arguments + err = callMake(makeTarget, envVars, makeArgs) + if err != nil { + fmt.Printf("Error: %v\n", err) + os.Exit(1) + } +} + +// splitArgs splits the arguments into options and make arguments based on the `--` delimiter +func splitArgs(args []string) (map[string]string, []string) { + options := make(map[string]string) + var makeArgs []string + isMakeArgs := false + skipNext := false + + for idx, arg := range args { + if skipNext == true { + skipNext = false + continue + } + + if arg == "--" { + isMakeArgs = true + continue + } + + if isMakeArgs { + makeArgs = append(makeArgs, arg) + } else if strings.HasPrefix(arg, "--") { + parts := strings.SplitN(arg[2:], "=", 2) // Remove "--" and split by "=" + if len(parts) == 2 { + options[parts[0]] = parts[1] + } else if idx+1 < len(args) && !strings.HasPrefix(args[idx+1], "--") { + options[arg[2:]] = args[idx+1] + skipNext = true + } else { + // Flags without values default to "true" + options[parts[0]] = "true" + } + } + } + return options, makeArgs +} + +// transformToMakeVars converts kebab-cased options to snake-cased Makefile env variables +func transformToMakeVars(options map[string]string) []string { + var makeVars []string + + for key, value := range options { + // Convert kebab-case to snake_case and uppercase + envKey := strings.ToUpper(strings.ReplaceAll(key, "-", "_")) + makeVars = append(makeVars, fmt.Sprintf("%s=%s", envKey, value)) + } + + return makeVars +} + +// callMake invokes the `make` command with the given target, environment variables, and additional arguments +func callMake(target string, makeVars []string, makeArgs []string) error { + // Construct the command with target and makeArgs + finalArgs := []string{target} + finalArgs = append(finalArgs, makeVars...) + finalArgs = append(finalArgs, makeArgs...) + cmd := exec.Command("make", finalArgs...) + + // Use the same stdin, stdout, and stderr as the parent process + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + // Run the command + return cmd.Run() +} + +// getRepoRoot determines the repo root (top-level directory) relative to this binary +func getRepoRoot() (string, error) { + // Get the path of the currently executing binary + executable, err := os.Executable() + if err != nil { + return "", err + } + + // Get the directory of the binary + execDir := filepath.Dir(executable) + + // Compute the repo root relative to the binary's location + repoRoot := filepath.Join(execDir, "../") // Adjust based on your repo structure + + return filepath.Abs(repoRoot) // Return the absolute path +} From f48c0d256f7855305ffe4dd6ad93de1ecfa69a1c Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Mon, 23 Dec 2024 14:34:08 -0600 Subject: [PATCH 03/25] more makefile improvements --- Makefile | 148 ++++++++++++++++++++++++++++------------------ tools/fdm/main.go | 18 +++++- 2 files changed, 108 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index f3efb556d815..36e16ce0dc8e 100644 --- a/Makefile +++ b/Makefile @@ -59,47 +59,6 @@ LDFLAGS_VERSION = "\ all: build -define HELP_TEXT - - Makefile commands - - make deps - Install dependent programs and libraries - make generate - Generate and bundle required all code - make generate-go - Generate and bundle required go code - make generate-js - Generate and bundle required js code - make generate-dev - Generate and bundle required code in a watch loop - - make migration - create a database migration file (supply name=TheNameOfYourMigration) - - make generate-doc - Generate updated API documentation for activities, osquery flags - make dump-test-schema - update schema.sql from current migrations - make generate-mock - update mock data store - - make clean - Clean all build artifacts - make clean-assets - Clean assets only - - make build - Build the code - make package - Build rpm and deb packages for linux - - make run-go-tests - Run Go tests in specific packages - make debug-go-tests - Debug Go tests in specific packages (with Delve) - make test-js - Run the JavaScript tests - - make lint - Run all linters - make lint-go - Run the Go linters - make lint-js - Run the JavaScript linters - make lint-scss - Run the SCSS linters - make lint-ts - Run the TypeScript linters - - For use in CI: - - make test - Run the full test suite (lint, Go and Javascript) - make test-go - Run the Go tests (all packages and tests) - -endef - -help: - $(info $(HELP_TEXT)) .prefix: mkdir -p build/linux @@ -115,7 +74,25 @@ help: .pre-fleetctl: $(eval APP_NAME = fleetctl) -build: fleet fleetctl +BINS_TO_BUILD = fleet fleetctl +ifdef FLEET + BINS_TO_BUILD = fleet +else ifdef FLEETCTL + BINS_TO_BUILD = fleetctl +endif +.help-short--build: + @echo "Build binaries" +.help-long--build: + @echo " Builds the specified binaries (defaults to building fleet and fleetctl)" +.help-options--build: + @echo "FLEET" + @echo "Build the fleet binary only" + @echo "FLEETCTL" + @echo "Build the fleetctl binary only" + @echo "GO_BUILD_RACE_ENABLED_VAR" + @echo "Turn on data race detection when building" + +build: $(BINS_TO_BUILD) fdm: go build -o build/fdm ./tools/fdm @@ -135,14 +112,22 @@ fleetctl: .prefix .pre-build .pre-fleetctl fleetctl-dev: GO_BUILD_RACE_ENABLED_VAR=true fleetctl-dev: fleetctl +.help-short--lint-js: + @echo "Run the JavaScript linters" lint-js: yarn lint +.help-short--lint-go: + @echo "Run the Go linters" lint-go: golangci-lint run --exclude-dirs ./node_modules --timeout 15m +.help-short--lint: + @echo "Run all linters" lint: lint-go lint-js +.help-short--dump-test-schema: + @echo "Update schema.sql from current migrations" dump-test-schema: go run ./tools/dbutils ./server/datastore/mysql/schema.sql @@ -180,34 +165,50 @@ else dlv test ${dlv_test_pkg_to_test} --api-version=2 --listen=127.0.0.1:61179 ${DEBUG_TEST_EXTRA_FLAGS} -- -test.v -test.run=${TESTS_TO_RUN} ${GO_TEST_EXTRA_FLAGS} endif +.help-short--run-go-tests: + @echo "Run Go tests in specific packages" # Command to run specific tests in development. Can run all tests for one or more packages, or specific tests within packages. run-go-tests: @MYSQL_TEST=1 REDIS_TEST=1 MINIO_STORAGE_TEST=1 SAML_IDP_TEST=1 NETWORK_TEST=1 make .run-go-tests GO_TEST_MAKE_FLAGS="-v" +.help-short--debug-go-tests: + @echo "Debug Go tests in specific packages (with Delve)" debug-go-tests: @MYSQL_TEST=1 REDIS_TEST=1 MINIO_STORAGE_TEST=1 SAML_IDP_TEST=1 NETWORK_TEST=1 make .debug-go-tests # Command used in CI to run all tests. +.help-short--test-go: + @echo "Run the Go tests (all packages and tests -- used in CI)" test-go: dump-test-schema generate-mock make .run-go-tests PKG_TO_TEST="./cmd/... ./ee/... ./orbit/pkg/... ./orbit/cmd/orbit ./pkg/... ./server/... ./tools/..." analyze-go: go test -tags full,fts5,netgo -race -cover ./... +.help-short--test-js: + @echo "Run the JavaScript tests" test-js: yarn test +.help-short--test: + @echo "Run the full test suite (lint, Go and Javascript -- used in CI)" test: lint test-go test-js +.help-short--generate: + @echo "Generate and bundle required all code" generate: clean-assets generate-js generate-go generate-ci: NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=development yarn run webpack make generate-go +.help-short--generate-js: + @echo "Generate and bundle required js code" generate-js: clean-assets .prefix NODE_ENV=production yarn run webpack --progress +.help-short--generate-go: + @echo "Generate and bundle required go code" generate-go: .prefix go run github.com/kevinburke/go-bindata/go-bindata -pkg=bindata -tags full \ -o=server/bindata/generated.go \ @@ -216,6 +217,8 @@ generate-go: .prefix # we first generate the webpack bundle so that bindata knows to atch the # output bundle file. then, generate debug bindata source file. finally, we # run webpack in watch mode to continuously re-generate the bundle +.help-short--generate-dev: + @echo "Generate and bundle required code in a watch loop" generate-dev: .prefix NODE_ENV=development yarn run webpack --progress go run github.com/kevinburke/go-bindata/go-bindata -debug -pkg=bindata -tags full \ @@ -223,13 +226,19 @@ generate-dev: .prefix frontend/templates/ assets/... server/mail/templates NODE_ENV=development yarn run webpack --progress --watch +.help-short--generate-mock: + @echo "Update mock data store" generate-mock: .prefix go generate github.com/fleetdm/fleet/v4/server/mock github.com/fleetdm/fleet/v4/server/mock/mockresult github.com/fleetdm/fleet/v4/server/service/mock +.help-short--generate-doc: + @echo "Generate updated API documentation for activities, osquery flags" generate-doc: .prefix go generate github.com/fleetdm/fleet/v4/server/fleet go generate github.com/fleetdm/fleet/v4/server/service/osquery_utils +.help-short--deps: + @echo "Install dependent programs and libraries" deps: deps-js deps-go deps-js: @@ -248,14 +257,20 @@ check-go-cloner: update-go-cloner: go run ./tools/cloner-check/main.go --update +.help-short--migration: + @echo "Create a database migration file (supply name=TheNameOfYourMigration)" migration: go run ./server/goose/cmd/goose -dir server/datastore/mysql/migrations/tables create $(name) gofmt -w server/datastore/mysql/migrations/tables/*_$(name)*.go +.help-short--clean: + @echo "Clean all build artifacts" clean: clean-assets rm -rf build vendor rm -f assets/bundle.js +.help-short--clean-assets: + @echo "Clean assets only" clean-assets: git clean -fx assets @@ -586,22 +601,41 @@ db-replica-reset: fleet db-replica-run: fleet FLEET_MYSQL_ADDRESS=127.0.0.1:3308 FLEET_MYSQL_READ_REPLICA_ADDRESS=127.0.0.1:3309 FLEET_MYSQL_READ_REPLICA_USERNAME=fleet FLEET_MYSQL_READ_REPLICA_DATABASE=fleet FLEET_MYSQL_READ_REPLICA_PASSWORD=insecure ./build/fleet serve --dev --dev_license -.help-short--do-help: - @echo do something - -.help-short--do-help2: - @echo do another thing -.help-short--some-very-long-command-name: - @echo here's some help +.help-short--foo: + @echo Do some stuff +.help-long--foo: + @echo " Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command " -do-help: - @echo Available Commands: - @targets=$$(awk '/^[^#[:space:]].*:/ {print $$1}' Makefile | grep '^\.help-short--' | sed 's/:$$//'); \ - if [ -n "$$targets" ]; then \ - output=$$(make --no-print-directory $$targets 2>/dev/null); \ - paste <(echo "$$targets" | sed 's/^\.help-short--/make /') <(echo "-- $$output") | column -t -s $$'\t'; \ +HELP_CMD_PREFIX ?= make +help: + @if [ -n "$(SPECIFIC_CMD)" ]; then \ + short_target=".help-short--$(SPECIFIC_CMD)"; \ + long_target=".help-long--$(SPECIFIC_CMD)"; \ + options_target=".help-options--$(SPECIFIC_CMD)"; \ + if make --no-print-directory $$short_target >/dev/null 2>&1; then \ + echo "NAME:"; \ + short_desc=$$(make $$short_target); \ + echo " ${SPECIFIC_CMD} - $$short_desc"; \ + if make --no-print-directory $$long_target >/dev/null 2>&1; then \ + echo; \ + echo "DESCRIPTION:"; \ + make $$long_target | fmt -w 80; \ + fi; \ + if make --no-print-directory $$options_target >/dev/null 2>&1; then \ + echo; \ + echo "OPTIONS:"; \ + paste -s -d '\t\n' <(make $$options_target) | column -t -s $$'\t'; \ + fi; \ + fi; \ else \ - echo "No help targets found."; \ - fi \ No newline at end of file + targets=$$(awk '/^[^#[:space:]].*:/ {print $$1}' Makefile | grep '^\.help-short--' | sed 's/:$$//' | sort); \ + if [ -n "$$targets" ]; then \ + output=$$(make --no-print-directory $$targets 2>/dev/null); \ + paste <(echo "$$targets" | sed 's/^\.help-short--/ ${HELP_CMD_PREFIX} /') <(echo "$$output") | column -t -s $$'\t'; echo; \ + else \ + echo "No help targets found."; \ + fi \ + fi + diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 72b69104ba83..8fa34dd63b5c 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -11,7 +11,7 @@ import ( func main() { // Ensure there's a make target specified if len(os.Args) < 2 { - fmt.Println("Usage: fdm [--option=value ...] -- [make-options]") + fmt.Println("Usage: fdm [--option=value ...] -- [make-options]") os.Exit(1) } @@ -34,6 +34,21 @@ func main() { // Split arguments into options and make arguments options, makeArgs := splitArgs(os.Args[2:]) + // Special logic for the help command + if makeTarget == "help" { + if len(os.Args) > 2 && !strings.HasPrefix(os.Args[2], "--") { + options["SPECIFIC_CMD"] = os.Args[2] + } else { + fmt.Println("fdm - developer tools for fleet device management") + fmt.Println() + fmt.Println("USAGE:") + fmt.Println(" fdm [--option=value ...] -- [make-options]") + fmt.Println() + fmt.Println("COMMANDS:") + options["HELP_CMD_PREFIX"] = "fdm" + } + } + // Transform options into Makefile-compatible environment variables envVars := transformToMakeVars(options) @@ -78,6 +93,7 @@ func splitArgs(args []string) (map[string]string, []string) { } } } + return options, makeArgs } From e709ab2f1d13c2fefe312fc35bf39b43ff369c52 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Mon, 23 Dec 2024 15:18:15 -0600 Subject: [PATCH 04/25] more help --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 36e16ce0dc8e..d1044905b71e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build clean clean-assets e2e-reset-db e2e-serve e2e-setup changelog db-reset db-backup db-restore check-go-cloner update-go-cloner help +.PHONY: build clean clean-assets e2e-reset-db e2e-serve e2e-setup changelog db-reset db-backup db-restore check-go-cloner update-go-cloner help .help-short--build .help-long--build .help-options--build export GO111MODULE=on @@ -626,7 +626,11 @@ help: if make --no-print-directory $$options_target >/dev/null 2>&1; then \ echo; \ echo "OPTIONS:"; \ - paste -s -d '\t\n' <(make $$options_target) | column -t -s $$'\t'; \ + if [ -n "$(REFORMAT_OPTIONS)" ]; then \ + paste -s -d '\t\n' <(make $$options_target | awk 'NR % 2 == 1 { option = $$0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $$0 }') | column -t -s $$'\t'; \ + else \ + paste -s -d '\t\n' <(make $$options_target) | column -t -s $$'\t'; \ + fi; \ fi; \ fi; \ else \ From c237e33c4cf4b27a818631c40b6af8eb4fa32a7e Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Mon, 23 Dec 2024 15:38:51 -0600 Subject: [PATCH 05/25] better experience --- Makefile | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d1044905b71e..e96798ef1927 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ endif .help-short--build: @echo "Build binaries" .help-long--build: - @echo " Builds the specified binaries (defaults to building fleet and fleetctl)" + @echo "Builds the specified binaries (defaults to building fleet and fleetctl)" .help-options--build: @echo "FLEET" @echo "Build the fleet binary only" @@ -615,21 +615,29 @@ help: long_target=".help-long--$(SPECIFIC_CMD)"; \ options_target=".help-options--$(SPECIFIC_CMD)"; \ if make --no-print-directory $$short_target >/dev/null 2>&1; then \ - echo "NAME:"; \ + echo -n "Gathering help..."; \ short_desc=$$(make $$short_target); \ - echo " ${SPECIFIC_CMD} - $$short_desc"; \ if make --no-print-directory $$long_target >/dev/null 2>&1; then \ + long_desc=$$(make $$long_target); \ + fi; \ + if make --no-print-directory $$options_target >/dev/null 2>&1; then \ + options_text=$$(make $$options_target); \ + fi; \ + echo -ne "\r\033[K"; \ + echo "NAME:"; \ + echo " ${SPECIFIC_CMD} - $$short_desc"; \ + if [ -n "$$long_desc" ]; then \ echo; \ echo "DESCRIPTION:"; \ - make $$long_target | fmt -w 80; \ + echo " $$long_desc" | fmt -w 80; \ fi; \ - if make --no-print-directory $$options_target >/dev/null 2>&1; then \ + if [ -n "$$options_text" ]; then \ echo; \ echo "OPTIONS:"; \ if [ -n "$(REFORMAT_OPTIONS)" ]; then \ - paste -s -d '\t\n' <(make $$options_target | awk 'NR % 2 == 1 { option = $$0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $$0 }') | column -t -s $$'\t'; \ + paste -s -d '\t\n' <(echo "$$options_text" | awk 'NR % 2 == 1 { option = $$0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $$0 }') | column -t -s $$'\t'; \ else \ - paste -s -d '\t\n' <(make $$options_target) | column -t -s $$'\t'; \ + paste -s -d '\t\n' <(echo "$$options_text") | column -t -s $$'\t'; \ fi; \ fi; \ fi; \ From 649e373f4b0d13a0c50c94271df05e2ead767f93 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Mon, 23 Dec 2024 15:49:26 -0600 Subject: [PATCH 06/25] cleanup --- Makefile | 33 +++++++++++++-------------------- tools/fdm/main.go | 1 + 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index e96798ef1927..363a65f68b43 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ endif .help-short--build: @echo "Build binaries" .help-long--build: - @echo "Builds the specified binaries (defaults to building fleet and fleetctl)" + @echo " Builds the specified binaries (defaults to building fleet and fleetctl)" .help-options--build: @echo "FLEET" @echo "Build the fleet binary only" @@ -601,27 +601,22 @@ db-replica-reset: fleet db-replica-run: fleet FLEET_MYSQL_ADDRESS=127.0.0.1:3308 FLEET_MYSQL_READ_REPLICA_ADDRESS=127.0.0.1:3309 FLEET_MYSQL_READ_REPLICA_USERNAME=fleet FLEET_MYSQL_READ_REPLICA_DATABASE=fleet FLEET_MYSQL_READ_REPLICA_PASSWORD=insecure ./build/fleet serve --dev --dev_license - -.help-short--foo: - @echo Do some stuff - -.help-long--foo: - @echo " Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command Here is some stuff about the command " - HELP_CMD_PREFIX ?= make help: @if [ -n "$(SPECIFIC_CMD)" ]; then \ short_target=".help-short--$(SPECIFIC_CMD)"; \ long_target=".help-long--$(SPECIFIC_CMD)"; \ options_target=".help-options--$(SPECIFIC_CMD)"; \ - if make --no-print-directory $$short_target >/dev/null 2>&1; then \ - echo -n "Gathering help..."; \ + if make --no-print-directory $$long_target >/dev/null 2>&1; then \ + echo -n "Gathering help for $$SPECIFIC_CMD command..."; \ short_desc=$$(make $$short_target); \ - if make --no-print-directory $$long_target >/dev/null 2>&1; then \ - long_desc=$$(make $$long_target); \ - fi; \ + long_desc=$$(make $$long_target); \ if make --no-print-directory $$options_target >/dev/null 2>&1; then \ - options_text=$$(make $$options_target); \ + if [ -n "$(REFORMAT_OPTIONS)" ]; then \ + options_text=$$(paste -s -d '\t\n' <(make $$options_target | awk 'NR % 2 == 1 { option = $$0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $$0 }') | column -t -s $$'\t'); \ + else \ + options_text=$$(paste -s -d '\t\n' <(make $$options_target) | column -t -s $$'\t'); \ + fi; \ fi; \ echo -ne "\r\033[K"; \ echo "NAME:"; \ @@ -629,17 +624,15 @@ help: if [ -n "$$long_desc" ]; then \ echo; \ echo "DESCRIPTION:"; \ - echo " $$long_desc" | fmt -w 80; \ + echo "$$long_desc" | fmt -w 80; \ fi; \ if [ -n "$$options_text" ]; then \ echo; \ echo "OPTIONS:"; \ - if [ -n "$(REFORMAT_OPTIONS)" ]; then \ - paste -s -d '\t\n' <(echo "$$options_text" | awk 'NR % 2 == 1 { option = $$0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $$0 }') | column -t -s $$'\t'; \ - else \ - paste -s -d '\t\n' <(echo "$$options_text") | column -t -s $$'\t'; \ - fi; \ + echo "$$options_text"; \ fi; \ + else \ + echo "No help found for $$SPECIFIC_CMD command."; \ fi; \ else \ targets=$$(awk '/^[^#[:space:]].*:/ {print $$1}' Makefile | grep '^\.help-short--' | sed 's/:$$//' | sort); \ diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 8fa34dd63b5c..5320edaf02f2 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -38,6 +38,7 @@ func main() { if makeTarget == "help" { if len(os.Args) > 2 && !strings.HasPrefix(os.Args[2], "--") { options["SPECIFIC_CMD"] = os.Args[2] + options["REFORMAT_OPTIONS"] = "true" } else { fmt.Println("fdm - developer tools for fleet device management") fmt.Println() From d9d411934dcf17ecb2f78946c881a8dbc6c33cf5 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 11:00:23 -0600 Subject: [PATCH 07/25] externalize help script --- Makefile | 74 +++++++++++++++-------------------------------- tools/makehelp.sh | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 50 deletions(-) create mode 100755 tools/makehelp.sh diff --git a/Makefile b/Makefile index 363a65f68b43..6061d929b84d 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ REVISION = $(shell git rev-parse HEAD) REVSHORT = $(shell git rev-parse --short HEAD) USER = $(shell whoami) DOCKER_IMAGE_NAME = fleetdm/fleet +TOOL_CMD = "make" ifdef GO_BUILD_RACE_ENABLED GO_BUILD_RACE_ENABLED_VAR := true @@ -91,6 +92,8 @@ endif @echo "Build the fleetctl binary only" @echo "GO_BUILD_RACE_ENABLED_VAR" @echo "Turn on data race detection when building" + @echo "EXTRA_FLEETCTL_LDFLAGS=\"--flag1 --flag2...\"" + @echo "Flags to provide to the Go linker when building fleetctl" build: $(BINS_TO_BUILD) @@ -134,9 +137,6 @@ dump-test-schema: # This is the base command to run Go tests. # Wrap this to run tests with presets (see `run-go-tests` and `test-go` targets). -# PKG_TO_TEST: Go packages to test, e.g. "server/datastore/mysql". Separate multiple packages with spaces. -# TESTS_TO_RUN: Name specific tests to run in the specified packages. Leave blank to run all tests in the specified packages. -# GO_TEST_EXTRA_FLAGS: Used to specify other arguments to `go test`. # GO_TEST_MAKE_FLAGS: Internal var used by other targets to add arguments to `go test`. # PKG_TO_TEST := "" @@ -145,7 +145,7 @@ dlv_test_pkg_to_test := $(addprefix github.com/fleetdm/fleet/v4/,$(PKG_TO_TEST)) .run-go-tests: ifeq ($(PKG_TO_TEST), "") - @echo "Please specify one or more packages to test with argument PKG_TO_TEST=\"/path/to/pkg/1 /path/to/pkg/2\"..."; + @echo "Please specify one or more packages to test. See '$(TOOL_CMD) help run-go-tests' for more info."; else @echo Running Go tests with command: go test -tags full,fts5,netgo -run=${TESTS_TO_RUN} ${GO_TEST_MAKE_FLAGS} ${GO_TEST_EXTRA_FLAGS} -parallel 8 -coverprofile=coverage.txt -covermode=atomic -coverpkg=github.com/fleetdm/fleet/v4/... $(go_test_pkg_to_test) @@ -153,13 +153,10 @@ endif # This is the base command to debug Go tests. # Wrap this to run tests with presets (see `debug-go-tests`) -# PKG_TO_TEST: Go packages to test, e.g. "server/datastore/mysql". Separate multiple packages with spaces. -# TESTS_TO_RUN: Name specific tests to debug in the specified packages. Leave blank to debug all tests in the specified packages. # DEBUG_TEST_EXTRA_FLAGS: Internal var used by other targets to add arguments to `dlv test`. -# GO_TEST_EXTRA_FLAGS: Used to specify other arguments to `go test`. .debug-go-tests: ifeq ($(PKG_TO_TEST), "") - @echo "Please specify one or more packages to debug with argument PKG_TO_TEST=\"/path/to/pkg/1 /path/to/pkg/2\"..."; + @echo "Please specify one or more packages to debug. See '$(TOOL_CMD) help run-go-tests' for more info."; else @echo Debugging tests with command: dlv test ${dlv_test_pkg_to_test} --api-version=2 --listen=127.0.0.1:61179 ${DEBUG_TEST_EXTRA_FLAGS} -- -test.v -test.run=${TESTS_TO_RUN} ${GO_TEST_EXTRA_FLAGS} @@ -167,12 +164,29 @@ endif .help-short--run-go-tests: @echo "Run Go tests in specific packages" -# Command to run specific tests in development. Can run all tests for one or more packages, or specific tests within packages. +.help-long--run-go-tests: + @echo Command to run specific tests in development. Can run all tests for one or more packages, or specific tests within packages. +.help-options--run-go-tests: + @echo "PKG_TO_TEST=\"pkg1 pkg2...\"" + @echo "Go packages to test, e.g. \"server/datastore/mysql\". Separate multiple packages with spaces." + @echo "TESTS_TO_RUN=\"test\"" + @echo Name specific tests to debug in the specified packages. Leave blank to debug all tests in the specified packages. + @echo "GO_TEST_EXTRA_FLAGS=\"--flag1 --flag2...\"" + @echo "Arguments to send to \"go test\"." run-go-tests: @MYSQL_TEST=1 REDIS_TEST=1 MINIO_STORAGE_TEST=1 SAML_IDP_TEST=1 NETWORK_TEST=1 make .run-go-tests GO_TEST_MAKE_FLAGS="-v" .help-short--debug-go-tests: @echo "Debug Go tests in specific packages (with Delve)" +.help-long--debug-go-tests: + @echo Command to run specific tests in the Go debugger. Can run all tests for one or more packages, or specific tests within packages. +.help-options--debug-go-tests: + @echo "PKG_TO_TEST=\"pkg1 pkg2...\"" + @echo "Go packages to test, e.g. \"server/datastore/mysql\". Separate multiple packages with spaces." + @echo "TESTS_TO_RUN=\"test\"" + @echo Name specific tests to debug in the specified packages. Leave blank to debug all tests in the specified packages. + @echo "GO_TEST_EXTRA_FLAGS=\"--flag1 --flag2...\"" + @echo "Arguments to send to \"go test\"." debug-go-tests: @MYSQL_TEST=1 REDIS_TEST=1 MINIO_STORAGE_TEST=1 SAML_IDP_TEST=1 NETWORK_TEST=1 make .debug-go-tests @@ -603,44 +617,4 @@ db-replica-run: fleet HELP_CMD_PREFIX ?= make help: - @if [ -n "$(SPECIFIC_CMD)" ]; then \ - short_target=".help-short--$(SPECIFIC_CMD)"; \ - long_target=".help-long--$(SPECIFIC_CMD)"; \ - options_target=".help-options--$(SPECIFIC_CMD)"; \ - if make --no-print-directory $$long_target >/dev/null 2>&1; then \ - echo -n "Gathering help for $$SPECIFIC_CMD command..."; \ - short_desc=$$(make $$short_target); \ - long_desc=$$(make $$long_target); \ - if make --no-print-directory $$options_target >/dev/null 2>&1; then \ - if [ -n "$(REFORMAT_OPTIONS)" ]; then \ - options_text=$$(paste -s -d '\t\n' <(make $$options_target | awk 'NR % 2 == 1 { option = $$0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $$0 }') | column -t -s $$'\t'); \ - else \ - options_text=$$(paste -s -d '\t\n' <(make $$options_target) | column -t -s $$'\t'); \ - fi; \ - fi; \ - echo -ne "\r\033[K"; \ - echo "NAME:"; \ - echo " ${SPECIFIC_CMD} - $$short_desc"; \ - if [ -n "$$long_desc" ]; then \ - echo; \ - echo "DESCRIPTION:"; \ - echo "$$long_desc" | fmt -w 80; \ - fi; \ - if [ -n "$$options_text" ]; then \ - echo; \ - echo "OPTIONS:"; \ - echo "$$options_text"; \ - fi; \ - else \ - echo "No help found for $$SPECIFIC_CMD command."; \ - fi; \ - else \ - targets=$$(awk '/^[^#[:space:]].*:/ {print $$1}' Makefile | grep '^\.help-short--' | sed 's/:$$//' | sort); \ - if [ -n "$$targets" ]; then \ - output=$$(make --no-print-directory $$targets 2>/dev/null); \ - paste <(echo "$$targets" | sed 's/^\.help-short--/ ${HELP_CMD_PREFIX} /') <(echo "$$output") | column -t -s $$'\t'; echo; \ - else \ - echo "No help targets found."; \ - fi \ - fi - + @SPECIFIC_CMD=$(SPECIFIC_CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makehelp.sh \ No newline at end of file diff --git a/tools/makehelp.sh b/tools/makehelp.sh new file mode 100755 index 000000000000..497eb8b7c346 --- /dev/null +++ b/tools/makehelp.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# If a command was specified like `make help SPECIFIC_CMD=build` then try to +# gather help for that command. +if [ -n "$SPECIFIC_CMD" ]; then + # Get the make targets for generating different help sections + short_target=".help-short--$SPECIFIC_CMD"; + long_target=".help-long--$SPECIFIC_CMD"; + options_target=".help-options--$SPECIFIC_CMD"; + # Try and get the additional "long" help for the command. + if make --no-print-directory $long_target >/dev/null 2>&1; then + # Print a loading message since make takes a second to run. + echo -n "Gathering help for $SPECIFIC_CMD command..."; + short_desc=$(make $short_target); + long_desc=$(make $long_target); + # If this command has options, output them as well. + if make --no-print-directory $options_target >/dev/null 2>&1; then + # The REFORMAT_OPTIONS flag turns makefile options like DO_THE_THING into + # CLI options like --do-the-thing. + if [ -n "$REFORMAT_OPTIONS" ]; then + options_text=$(paste -s -d '\t\n' <(make $options_target | awk 'NR % 2 == 1 { option = $0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $0 }') | column -t -s $'\t'); + else + options_text=$(paste -s -d '\t\n' <(make $options_target) | column -t -s $'\t'); + fi; + fi; + # We're done loading, so erase the loading message. + echo -ne "\r\033[K"; + # Output whatever help we hot. + echo "NAME:"; + echo " $SPECIFIC_CMD - $short_desc"; + if [ -n "$long_desc" ]; then + echo; + echo "DESCRIPTION:"; + echo " $long_desc" | fmt -w 80; + fi; + if [ -n "$options_text" ]; then + echo; + echo "OPTIONS:"; + echo "$options_text"; + fi; + # If there's no long help target, there's no additional help for the command. + else + echo "No help found for $SPECIFIC_CMD command."; + fi; +# If no specific help was requested, output all the available commands. +else + targets=$(awk '/^[^#[:space:]].*:/ {print $1}' Makefile | grep '^\.help-short--' | sed 's/:$//' | sort); + if [ -n "$targets" ]; then + output=$(make --no-print-directory $targets 2>/dev/null); + paste <(echo "$targets" | sed "s/^\.help-short--/ $HELP_CMD_PREFIX /") <(echo "$output") | column -t -s $'\t'; echo; + else + echo "No help targets found."; + fi +fi + + From d5e4c6edce33151005beab531039b0d63c436a44 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 11:00:46 -0600 Subject: [PATCH 08/25] make fdm output help with fdm command prefix --- tools/fdm/main.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 5320edaf02f2..a8b9f0ddc3a9 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -51,10 +51,11 @@ func main() { } // Transform options into Makefile-compatible environment variables - envVars := transformToMakeVars(options) + makeVars := transformToMakeVars(options) + makeArgs = append(makeVars, "TOOL_CMD=fdm") // Call the Makefile with the specified target, environment variables, and additional arguments - err = callMake(makeTarget, envVars, makeArgs) + err = callMake(makeTarget, makeVars, makeArgs) if err != nil { fmt.Printf("Error: %v\n", err) os.Exit(1) From cb316d6ff14efb770c4114abe655a7c0d6ffa5fd Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 12:20:04 -0600 Subject: [PATCH 09/25] speed up --- Makefile | 12 +++++++++--- tools/makehelp.sh | 26 ++++++++++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 6061d929b84d..b9010feb3923 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build clean clean-assets e2e-reset-db e2e-serve e2e-setup changelog db-reset db-backup db-restore check-go-cloner update-go-cloner help .help-short--build .help-long--build .help-options--build +.PHONY: build clean clean-assets e2e-reset-db e2e-serve e2e-setup changelog db-reset db-backup db-restore check-go-cloner update-go-cloner help .help-sep-1 .help-sep-2 .help-sep-3 export GO111MODULE=on @@ -84,7 +84,7 @@ endif .help-short--build: @echo "Build binaries" .help-long--build: - @echo " Builds the specified binaries (defaults to building fleet and fleetctl)" + @echo "Builds the specified binaries (defaults to building fleet and fleetctl)" .help-options--build: @echo "FLEET" @echo "Build the fleet binary only" @@ -617,4 +617,10 @@ db-replica-run: fleet HELP_CMD_PREFIX ?= make help: - @SPECIFIC_CMD=$(SPECIFIC_CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makehelp.sh \ No newline at end of file + @SPECIFIC_CMD=$(SPECIFIC_CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makehelp.sh +.help-sep-1: + @echo -n "######" +.help-sep-2: + @echo -n "######" +.help-sep-3: + @echo -n "######" diff --git a/tools/makehelp.sh b/tools/makehelp.sh index 497eb8b7c346..fe5d40e38c53 100755 --- a/tools/makehelp.sh +++ b/tools/makehelp.sh @@ -8,19 +8,33 @@ if [ -n "$SPECIFIC_CMD" ]; then long_target=".help-long--$SPECIFIC_CMD"; options_target=".help-options--$SPECIFIC_CMD"; # Try and get the additional "long" help for the command. - if make --no-print-directory $long_target >/dev/null 2>&1; then + output=$(make $short_target .help-sep-1 $long_target .help-sep-2 $options_target .help-sep-3 2>/dev/null) + + # Replace the multi-character delimiter (#####) with a single character (e.g., ASCII 30, the "record separator") + delim=$'\036' # ASCII 30 + cleaned_output=$(echo "$output" | sed "s/######/$delim/g" | tr '\n' '\037' ) + + # Read the cleaned output into variables + # IFS="$delim" read -r short_desc long_desc options_text <<<"$cleaned_output" + sections=() + IFS="$delim" read -r -a sections <<<"$cleaned_output" + + short_desc="${sections[0]}" + long_desc=$(echo "${sections[1]}" | tr '\037' '\n') + options_text=$(echo "${sections[2]}" | tr '\037' '\n') + + + if [ -n "$long_desc" ]; then # Print a loading message since make takes a second to run. echo -n "Gathering help for $SPECIFIC_CMD command..."; - short_desc=$(make $short_target); - long_desc=$(make $long_target); # If this command has options, output them as well. - if make --no-print-directory $options_target >/dev/null 2>&1; then + if [ -n "$options_text" ]; then # The REFORMAT_OPTIONS flag turns makefile options like DO_THE_THING into # CLI options like --do-the-thing. if [ -n "$REFORMAT_OPTIONS" ]; then - options_text=$(paste -s -d '\t\n' <(make $options_target | awk 'NR % 2 == 1 { option = $0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $0 }') | column -t -s $'\t'); + options_text=$(paste -s -d '\t\n' <(echo "$options_text" | awk 'NR % 2 == 1 { option = $0; gsub("_", "-", option); printf " --%s\n", tolower(option); next } { print $0 }') | column -t -s $'\t'); else - options_text=$(paste -s -d '\t\n' <(make $options_target) | column -t -s $'\t'); + options_text=$(paste -s -d '\t\n' <(echo "$options_text") | column -t -s $'\t'); fi; fi; # We're done loading, so erase the loading message. From e5f6d03f435e8b01e6b6ff9fc745d8e39fa94327 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 12:37:48 -0600 Subject: [PATCH 10/25] more cleanup --- Makefile | 6 +++--- tools/makehelp.sh | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index b9010feb3923..e5e35d648a48 100644 --- a/Makefile +++ b/Makefile @@ -619,8 +619,8 @@ HELP_CMD_PREFIX ?= make help: @SPECIFIC_CMD=$(SPECIFIC_CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makehelp.sh .help-sep-1: - @echo -n "######" + @printf "\036" .help-sep-2: - @echo -n "######" + @printf "\036" .help-sep-3: - @echo -n "######" + @printf "\036" diff --git a/tools/makehelp.sh b/tools/makehelp.sh index fe5d40e38c53..8118ff6b03bd 100755 --- a/tools/makehelp.sh +++ b/tools/makehelp.sh @@ -7,23 +7,22 @@ if [ -n "$SPECIFIC_CMD" ]; then short_target=".help-short--$SPECIFIC_CMD"; long_target=".help-long--$SPECIFIC_CMD"; options_target=".help-options--$SPECIFIC_CMD"; - # Try and get the additional "long" help for the command. - output=$(make $short_target .help-sep-1 $long_target .help-sep-2 $options_target .help-sep-3 2>/dev/null) - - # Replace the multi-character delimiter (#####) with a single character (e.g., ASCII 30, the "record separator") + delim=$'\036' # ASCII 30 - cleaned_output=$(echo "$output" | sed "s/######/$delim/g" | tr '\n' '\037' ) + nl=$'\037' - # Read the cleaned output into variables - # IFS="$delim" read -r short_desc long_desc options_text <<<"$cleaned_output" - sections=() + # Try and get the help for the command. Sections of the output will be delimited bv ASCII 30 (arbirary non-printing char) + output=$(make $short_target .help-sep-1 $long_target .help-sep-2 $options_target .help-sep-3 2>/dev/null) + # Clean the output for "read" by replacing newlines with ASCII 31 (also arbitrary) + cleaned_output=$(echo "$output" | tr '\n' $nl ) + # Read the output into an array IFS="$delim" read -r -a sections <<<"$cleaned_output" - + # Get the newlines back short_desc="${sections[0]}" - long_desc=$(echo "${sections[1]}" | tr '\037' '\n') - options_text=$(echo "${sections[2]}" | tr '\037' '\n') + long_desc=$(echo "${sections[1]}" | tr $nl '\n') + options_text=$(echo "${sections[2]}" | tr $nl '\n') - + # If we found a long help description, then continue printing help. if [ -n "$long_desc" ]; then # Print a loading message since make takes a second to run. echo -n "Gathering help for $SPECIFIC_CMD command..."; @@ -52,10 +51,11 @@ if [ -n "$SPECIFIC_CMD" ]; then echo "OPTIONS:"; echo "$options_text"; fi; - # If there's no long help target, there's no additional help for the command. + # If there's no long help description, there's no additional help for the command. else echo "No help found for $SPECIFIC_CMD command."; fi; + # If no specific help was requested, output all the available commands. else targets=$(awk '/^[^#[:space:]].*:/ {print $1}' Makefile | grep '^\.help-short--' | sed 's/:$//' | sort); From af044e16e1db74fc71448a7c263dfb538205db92 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 12:43:08 -0600 Subject: [PATCH 11/25] reorg --- Makefile | 12 ++---------- tools/makefile-support/helpsystem-targets | 15 +++++++++++++++ tools/{ => makefile-support}/makehelp.sh | 0 3 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 tools/makefile-support/helpsystem-targets rename tools/{ => makefile-support}/makehelp.sh (100%) diff --git a/Makefile b/Makefile index e5e35d648a48..986ce8bbe495 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build clean clean-assets e2e-reset-db e2e-serve e2e-setup changelog db-reset db-backup db-restore check-go-cloner update-go-cloner help .help-sep-1 .help-sep-2 .help-sep-3 +.PHONY: build clean clean-assets e2e-reset-db e2e-serve e2e-setup changelog db-reset db-backup db-restore check-go-cloner update-go-cloner help export GO111MODULE=on @@ -615,12 +615,4 @@ db-replica-reset: fleet db-replica-run: fleet FLEET_MYSQL_ADDRESS=127.0.0.1:3308 FLEET_MYSQL_READ_REPLICA_ADDRESS=127.0.0.1:3309 FLEET_MYSQL_READ_REPLICA_USERNAME=fleet FLEET_MYSQL_READ_REPLICA_DATABASE=fleet FLEET_MYSQL_READ_REPLICA_PASSWORD=insecure ./build/fleet serve --dev --dev_license -HELP_CMD_PREFIX ?= make -help: - @SPECIFIC_CMD=$(SPECIFIC_CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makehelp.sh -.help-sep-1: - @printf "\036" -.help-sep-2: - @printf "\036" -.help-sep-3: - @printf "\036" +include ./tools/makefile-support/helpsystem-targets \ No newline at end of file diff --git a/tools/makefile-support/helpsystem-targets b/tools/makefile-support/helpsystem-targets new file mode 100644 index 000000000000..dffa1d0e5f31 --- /dev/null +++ b/tools/makefile-support/helpsystem-targets @@ -0,0 +1,15 @@ +# Default prefix for commands in the main help command, e.g. "make build". +# The FDM utility may change this to "fdm". +HELP_CMD_PREFIX ?= make + +# Run the main help command. +help: + @SPECIFIC_CMD=$(SPECIFIC_CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makefile-support/makehelp.sh + +# Print separators between help sections. +.help-sep-1: + @printf "\036" +.help-sep-2: + @printf "\036" +.help-sep-3: + @printf "\036" diff --git a/tools/makehelp.sh b/tools/makefile-support/makehelp.sh similarity index 100% rename from tools/makehelp.sh rename to tools/makefile-support/makehelp.sh From 0cdce2368e8c508623bbc3b76d709461609e618d Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 13:19:07 -0600 Subject: [PATCH 12/25] add symlink --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 986ce8bbe495..9eea3ab00045 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,7 @@ build: $(BINS_TO_BUILD) fdm: go build -o build/fdm ./tools/fdm + ln -s "$$(pwd)/build/fdm" /usr/local/bin/fdm fleet: .prefix .pre-build .pre-fleet CGO_ENABLED=1 go build -race=${GO_BUILD_RACE_ENABLED_VAR} -tags full,fts5,netgo -o build/${OUTPUT} -ldflags ${LDFLAGS_VERSION} ./cmd/fleet From a4c7a319881404a12477e2611ddb610ae31150c1 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 13:29:24 -0600 Subject: [PATCH 13/25] update executable directory determination --- Makefile | 4 ++-- tools/fdm/main.go | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 9eea3ab00045..437df5db1d54 100644 --- a/Makefile +++ b/Makefile @@ -90,7 +90,7 @@ endif @echo "Build the fleet binary only" @echo "FLEETCTL" @echo "Build the fleetctl binary only" - @echo "GO_BUILD_RACE_ENABLED_VAR" + @echo "GO_BUILD_RACE_ENABLED" @echo "Turn on data race detection when building" @echo "EXTRA_FLEETCTL_LDFLAGS=\"--flag1 --flag2...\"" @echo "Flags to provide to the Go linker when building fleetctl" @@ -99,7 +99,7 @@ build: $(BINS_TO_BUILD) fdm: go build -o build/fdm ./tools/fdm - ln -s "$$(pwd)/build/fdm" /usr/local/bin/fdm + ln -sf "$$(pwd)/build/fdm" /usr/local/bin/fdm fleet: .prefix .pre-build .pre-fleet CGO_ENABLED=1 go build -race=${GO_BUILD_RACE_ENABLED_VAR} -tags full,fts5,netgo -o build/${OUTPUT} -ldflags ${LDFLAGS_VERSION} ./cmd/fleet diff --git a/tools/fdm/main.go b/tools/fdm/main.go index a8b9f0ddc3a9..2c8bd9315031 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -138,7 +138,12 @@ func getRepoRoot() (string, error) { } // Get the directory of the binary - execDir := filepath.Dir(executable) + execDir, err := filepath.EvalSymlinks(executable) + if err != nil { + return "", err + } + execDir = filepath.Dir(execDir) + fmt.Println(execDir) // Compute the repo root relative to the binary's location repoRoot := filepath.Join(execDir, "../") // Adjust based on your repo structure From 140fe56a0bdfce048889d4349461baa10ecfd8f3 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 13:34:14 -0600 Subject: [PATCH 14/25] remove test log --- tools/fdm/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 2c8bd9315031..219c2ef52f2d 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -143,7 +143,6 @@ func getRepoRoot() (string, error) { return "", err } execDir = filepath.Dir(execDir) - fmt.Println(execDir) // Compute the repo root relative to the binary's location repoRoot := filepath.Join(execDir, "../") // Adjust based on your repo structure From 65fe1199bd881d1416c96d2edb569b26203cbc78 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 13:50:23 -0600 Subject: [PATCH 15/25] fix makeargs assignment --- tools/fdm/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 219c2ef52f2d..3eece4dce735 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -52,7 +52,7 @@ func main() { // Transform options into Makefile-compatible environment variables makeVars := transformToMakeVars(options) - makeArgs = append(makeVars, "TOOL_CMD=fdm") + makeVars = append(makeVars, "TOOL_CMD=fdm") // Call the Makefile with the specified target, environment variables, and additional arguments err = callMake(makeTarget, makeVars, makeArgs) From a037a85fd257b51c46d4395cd90b397649d854c0 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Fri, 27 Dec 2024 13:53:28 -0600 Subject: [PATCH 16/25] update comments --- tools/fdm/main.go | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 3eece4dce735..7d3c9c0f8602 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -9,32 +9,32 @@ import ( ) func main() { - // Ensure there's a make target specified + // Ensure there's a make target specified. if len(os.Args) < 2 { fmt.Println("Usage: fdm [--option=value ...] -- [make-options]") os.Exit(1) } - // Determine the path to the top-level directory (where the Makefile resides) + // Determine the path to the top-level directory (where the Makefile resides). repoRoot, err := getRepoRoot() if err != nil { fmt.Printf("Error determining repo root: %v\n", err) os.Exit(1) } - // Change the working directory to the repo root + // Change the working directory to the repo root. if err := os.Chdir(repoRoot); err != nil { fmt.Printf("Error changing directory to repo root: %v\n", err) os.Exit(1) } - // Extract the make target + // Extract the make target. makeTarget := os.Args[1] - // Split arguments into options and make arguments + // Split arguments into options and make arguments. options, makeArgs := splitArgs(os.Args[2:]) - // Special logic for the help command + // Special logic for the help command. if makeTarget == "help" { if len(os.Args) > 2 && !strings.HasPrefix(os.Args[2], "--") { options["SPECIFIC_CMD"] = os.Args[2] @@ -50,11 +50,11 @@ func main() { } } - // Transform options into Makefile-compatible environment variables + // Transform options into Makefile-compatible environment variables. makeVars := transformToMakeVars(options) makeVars = append(makeVars, "TOOL_CMD=fdm") - // Call the Makefile with the specified target, environment variables, and additional arguments + // Call the Makefile with the specified target, environment variables, and additional arguments. err = callMake(makeTarget, makeVars, makeArgs) if err != nil { fmt.Printf("Error: %v\n", err) @@ -62,7 +62,7 @@ func main() { } } -// splitArgs splits the arguments into options and make arguments based on the `--` delimiter +// splitArgs splits the arguments into options and make arguments based on the `--` delimiter. func splitArgs(args []string) (map[string]string, []string) { options := make(map[string]string) var makeArgs []string @@ -83,14 +83,15 @@ func splitArgs(args []string) (map[string]string, []string) { if isMakeArgs { makeArgs = append(makeArgs, arg) } else if strings.HasPrefix(arg, "--") { - parts := strings.SplitN(arg[2:], "=", 2) // Remove "--" and split by "=" + // Remove "--" and split by "=". + parts := strings.SplitN(arg[2:], "=", 2) if len(parts) == 2 { options[parts[0]] = parts[1] } else if idx+1 < len(args) && !strings.HasPrefix(args[idx+1], "--") { options[arg[2:]] = args[idx+1] skipNext = true } else { - // Flags without values default to "true" + // Flags without values default to "true". options[parts[0]] = "true" } } @@ -99,12 +100,12 @@ func splitArgs(args []string) (map[string]string, []string) { return options, makeArgs } -// transformToMakeVars converts kebab-cased options to snake-cased Makefile env variables +// transformToMakeVars converts kebab-cased options to snake-cased Makefile env variables. func transformToMakeVars(options map[string]string) []string { var makeVars []string for key, value := range options { - // Convert kebab-case to snake_case and uppercase + // Convert kebab-case to snake_case and uppercase. envKey := strings.ToUpper(strings.ReplaceAll(key, "-", "_")) makeVars = append(makeVars, fmt.Sprintf("%s=%s", envKey, value)) } @@ -112,24 +113,24 @@ func transformToMakeVars(options map[string]string) []string { return makeVars } -// callMake invokes the `make` command with the given target, environment variables, and additional arguments +// callMake invokes the `make` command with the given target, environment variables, and additional arguments. func callMake(target string, makeVars []string, makeArgs []string) error { - // Construct the command with target and makeArgs + // Construct the command with target and makeArgs. finalArgs := []string{target} finalArgs = append(finalArgs, makeVars...) finalArgs = append(finalArgs, makeArgs...) cmd := exec.Command("make", finalArgs...) - // Use the same stdin, stdout, and stderr as the parent process + // Use the same stdin, stdout, and stderr as the parent process. cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - // Run the command + // Run the command. return cmd.Run() } -// getRepoRoot determines the repo root (top-level directory) relative to this binary +// getRepoRoot determines the repo root (top-level directory) relative to this binary. func getRepoRoot() (string, error) { // Get the path of the currently executing binary executable, err := os.Executable() @@ -137,15 +138,15 @@ func getRepoRoot() (string, error) { return "", err } - // Get the directory of the binary + // Get the path of the binary, following symlinks. execDir, err := filepath.EvalSymlinks(executable) if err != nil { return "", err } + // Get the directory. execDir = filepath.Dir(execDir) - // Compute the repo root relative to the binary's location - repoRoot := filepath.Join(execDir, "../") // Adjust based on your repo structure - - return filepath.Abs(repoRoot) // Return the absolute path + // Compute the repo root relative to the binary's location. + repoRoot := filepath.Join(execDir, "../") + return filepath.Abs(repoRoot) } From 100eef0c651d5cbd6fc9620bbaec6579b67ca986 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 9 Jan 2025 15:31:53 -0600 Subject: [PATCH 17/25] use positional arguments --- Makefile | 12 ++++++++++-- tools/fdm/main.go | 6 +++++- tools/makefile-support/helpsystem-targets | 3 ++- tools/makefile-support/makehelp.sh | 16 ++++++++-------- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index df974cabd0e0..56e19bdc24a1 100644 --- a/Makefile +++ b/Makefile @@ -76,9 +76,9 @@ all: build $(eval APP_NAME = fleetctl) BINS_TO_BUILD = fleet fleetctl -ifdef FLEET +ifeq ($(ARG1), fleet) BINS_TO_BUILD = fleet -else ifdef FLEETCTL +else ifeq ($(ARG1), fleetctl) BINS_TO_BUILD = fleetctl endif .help-short--build: @@ -97,6 +97,8 @@ endif build: $(BINS_TO_BUILD) +.help-short--fdm: + @echo "Builds the fdm command" fdm: go build -o build/fdm ./tools/fdm @if [ ! -f /usr/local/bin/fdm ]; then \ @@ -130,7 +132,13 @@ lint-go: .help-short--lint: @echo "Run all linters" +ifeq ($(ARG1), go) +lint: lint-go +else ifeq ($(ARG1), js) +lint: lint-js +else lint: lint-go lint-js +endif .help-short--test-schema: @echo "Update schema.sql from current migrations" diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 7d3c9c0f8602..2b3a7bee31cb 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -5,6 +5,7 @@ import ( "os" "os/exec" "path/filepath" + "strconv" "strings" ) @@ -37,7 +38,6 @@ func main() { // Special logic for the help command. if makeTarget == "help" { if len(os.Args) > 2 && !strings.HasPrefix(os.Args[2], "--") { - options["SPECIFIC_CMD"] = os.Args[2] options["REFORMAT_OPTIONS"] = "true" } else { fmt.Println("fdm - developer tools for fleet device management") @@ -66,6 +66,7 @@ func main() { func splitArgs(args []string) (map[string]string, []string) { options := make(map[string]string) var makeArgs []string + positionalArgsIndex := 1 isMakeArgs := false skipNext := false @@ -94,6 +95,9 @@ func splitArgs(args []string) (map[string]string, []string) { // Flags without values default to "true". options[parts[0]] = "true" } + } else { + options["arg"+strconv.Itoa(positionalArgsIndex)] = arg + positionalArgsIndex++ } } diff --git a/tools/makefile-support/helpsystem-targets b/tools/makefile-support/helpsystem-targets index dffa1d0e5f31..c20a31f641be 100644 --- a/tools/makefile-support/helpsystem-targets +++ b/tools/makefile-support/helpsystem-targets @@ -1,10 +1,11 @@ # Default prefix for commands in the main help command, e.g. "make build". # The FDM utility may change this to "fdm". HELP_CMD_PREFIX ?= make +CMD = $(ARG1) # Run the main help command. help: - @SPECIFIC_CMD=$(SPECIFIC_CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makefile-support/makehelp.sh + @CMD=$(CMD) REFORMAT_OPTIONS=$(REFORMAT_OPTIONS) HELP_CMD_PREFIX=$(HELP_CMD_PREFIX) ./tools/makefile-support/makehelp.sh # Print separators between help sections. .help-sep-1: diff --git a/tools/makefile-support/makehelp.sh b/tools/makefile-support/makehelp.sh index 8118ff6b03bd..48aa4ddad8b2 100755 --- a/tools/makefile-support/makehelp.sh +++ b/tools/makefile-support/makehelp.sh @@ -1,12 +1,12 @@ #!/bin/bash -# If a command was specified like `make help SPECIFIC_CMD=build` then try to +# If a command was specified like `make help CMD=build` then try to # gather help for that command. -if [ -n "$SPECIFIC_CMD" ]; then +if [ -n "$CMD" ]; then # Get the make targets for generating different help sections - short_target=".help-short--$SPECIFIC_CMD"; - long_target=".help-long--$SPECIFIC_CMD"; - options_target=".help-options--$SPECIFIC_CMD"; + short_target=".help-short--$CMD"; + long_target=".help-long--$CMD"; + options_target=".help-options--$CMD"; delim=$'\036' # ASCII 30 nl=$'\037' @@ -25,7 +25,7 @@ if [ -n "$SPECIFIC_CMD" ]; then # If we found a long help description, then continue printing help. if [ -n "$long_desc" ]; then # Print a loading message since make takes a second to run. - echo -n "Gathering help for $SPECIFIC_CMD command..."; + echo -n "Gathering help for $CMD command..."; # If this command has options, output them as well. if [ -n "$options_text" ]; then # The REFORMAT_OPTIONS flag turns makefile options like DO_THE_THING into @@ -40,7 +40,7 @@ if [ -n "$SPECIFIC_CMD" ]; then echo -ne "\r\033[K"; # Output whatever help we hot. echo "NAME:"; - echo " $SPECIFIC_CMD - $short_desc"; + echo " $CMD - $short_desc"; if [ -n "$long_desc" ]; then echo; echo "DESCRIPTION:"; @@ -53,7 +53,7 @@ if [ -n "$SPECIFIC_CMD" ]; then fi; # If there's no long help description, there's no additional help for the command. else - echo "No help found for $SPECIFIC_CMD command."; + echo "No help found for $CMD command."; fi; # If no specific help was requested, output all the available commands. From 3061f97fa1cb6a1a6726baaf812541a679106e7e Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 9 Jan 2025 21:23:00 -0600 Subject: [PATCH 18/25] add usage text --- Makefile | 13 ++++++++----- tools/makefile-support/helpsystem-targets | 2 ++ tools/makefile-support/makehelp.sh | 9 ++++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 56e19bdc24a1..70bd77681aae 100644 --- a/Makefile +++ b/Makefile @@ -131,11 +131,14 @@ lint-go: golangci-lint run --exclude-dirs ./node_modules --timeout 15m .help-short--lint: - @echo "Run all linters" -ifeq ($(ARG1), go) -lint: lint-go -else ifeq ($(ARG1), js) -lint: lint-js + @echo "Run linters" +.help-long--lint: + @echo "Runs the linters for Go and Javascript code. Specify 'go' or 'js' to run only that linter, or else both will be run." +.help-usage--lint: + @echo "$(TOOL_CMD) lint [linter-type]" + +ifdef ARG1 +lint: lint-$(ARG1) else lint: lint-go lint-js endif diff --git a/tools/makefile-support/helpsystem-targets b/tools/makefile-support/helpsystem-targets index c20a31f641be..114d24e067fe 100644 --- a/tools/makefile-support/helpsystem-targets +++ b/tools/makefile-support/helpsystem-targets @@ -14,3 +14,5 @@ help: @printf "\036" .help-sep-3: @printf "\036" +.help-sep-4: + @printf "\036" diff --git a/tools/makefile-support/makehelp.sh b/tools/makefile-support/makehelp.sh index 48aa4ddad8b2..4bce15e2fee9 100755 --- a/tools/makefile-support/makehelp.sh +++ b/tools/makefile-support/makehelp.sh @@ -7,12 +7,13 @@ if [ -n "$CMD" ]; then short_target=".help-short--$CMD"; long_target=".help-long--$CMD"; options_target=".help-options--$CMD"; + usage_target=".help-usage--$CMD"; delim=$'\036' # ASCII 30 nl=$'\037' # Try and get the help for the command. Sections of the output will be delimited bv ASCII 30 (arbirary non-printing char) - output=$(make $short_target .help-sep-1 $long_target .help-sep-2 $options_target .help-sep-3 2>/dev/null) + output=$(make $short_target .help-sep-1 $long_target .help-sep-2 $options_target .help-sep-3 $usage_target .help-sep-4 2>/dev/null) # Clean the output for "read" by replacing newlines with ASCII 31 (also arbitrary) cleaned_output=$(echo "$output" | tr '\n' $nl ) # Read the output into an array @@ -21,6 +22,7 @@ if [ -n "$CMD" ]; then short_desc="${sections[0]}" long_desc=$(echo "${sections[1]}" | tr $nl '\n') options_text=$(echo "${sections[2]}" | tr $nl '\n') + usage_text=$(echo "${sections[3]}" | tr $nl '\n') # If we found a long help description, then continue printing help. if [ -n "$long_desc" ]; then @@ -41,6 +43,11 @@ if [ -n "$CMD" ]; then # Output whatever help we hot. echo "NAME:"; echo " $CMD - $short_desc"; + if [ -n "$usage_text" ]; then + echo; + echo "USAGE:"; + echo " $usage_text"; + fi; if [ -n "$long_desc" ]; then echo; echo "DESCRIPTION:"; From deba1bc563e326ed569effdf5e9a090be6ec07d0 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Wed, 15 Jan 2025 23:44:26 -0600 Subject: [PATCH 19/25] styling, allow extra help --- Makefile | 18 ++++++++++++------ tools/fdm/main.go | 7 ++++--- tools/makefile-support/helpsystem-targets | 2 ++ tools/makefile-support/makehelp.sh | 19 ++++++++++++++----- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 98dd6259d7f2..4071c6190a9c 100644 --- a/Makefile +++ b/Makefile @@ -85,16 +85,17 @@ endif @echo "Build binaries" .help-long--build: @echo "Builds the specified binaries (defaults to building fleet and fleetctl)" +.help-usage--build: + @echo "$(TOOL_CMD) build [binaries] [options]" .help-options--build: - @echo "FLEET" - @echo "Build the fleet binary only" - @echo "FLEETCTL" - @echo "Build the fleetctl binary only" @echo "GO_BUILD_RACE_ENABLED" @echo "Turn on data race detection when building" @echo "EXTRA_FLEETCTL_LDFLAGS=\"--flag1 --flag2...\"" @echo "Flags to provide to the Go linker when building fleetctl" - +.help-extra--build: + @echo "AVAILABLE BINARIES:" + @echo " fleet Build the fleet binary" + @echo " fleetctl Build the fleetctl binary" build: $(BINS_TO_BUILD) .help-short--fdm: @@ -102,6 +103,7 @@ build: $(BINS_TO_BUILD) fdm: go build -o build/fdm ./tools/fdm @if [ ! -f /usr/local/bin/fdm ]; then \ + echo "Linking to /usr/local/bin/fdm..."; \ sudo ln -sf "$$(pwd)/build/fdm" /usr/local/bin/fdm; \ fi @@ -133,9 +135,13 @@ lint-go: .help-short--lint: @echo "Run linters" .help-long--lint: - @echo "Runs the linters for Go and Javascript code. Specify 'go' or 'js' to run only that linter, or else both will be run." + @echo "Runs the linters for Go and Javascript code. If not linter type is specified, all linters will be run." .help-usage--lint: @echo "$(TOOL_CMD) lint [linter-type]" +.help-extra--lint: + @echo "AVAILABLE LINTERS:" + @echo " go Lint Go files with golangci-lint" + @echo " js Lint .js, .jsx, .ts and .tsx files with eslint" ifdef ARG1 lint: lint-$(ARG1) diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 2b3a7bee31cb..175052889bb8 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -40,12 +40,13 @@ func main() { if len(os.Args) > 2 && !strings.HasPrefix(os.Args[2], "--") { options["REFORMAT_OPTIONS"] = "true" } else { - fmt.Println("fdm - developer tools for fleet device management") + fmt.Println("\033[1mNAME\033[0m") + fmt.Println(" fdm - developer tools for fleet device management") fmt.Println() - fmt.Println("USAGE:") + fmt.Println("\033[1mUSAGE:\033[0m") fmt.Println(" fdm [--option=value ...] -- [make-options]") fmt.Println() - fmt.Println("COMMANDS:") + fmt.Println("\033[1mCOMMANDS:\033[0m") options["HELP_CMD_PREFIX"] = "fdm" } } diff --git a/tools/makefile-support/helpsystem-targets b/tools/makefile-support/helpsystem-targets index 114d24e067fe..c235ced6e944 100644 --- a/tools/makefile-support/helpsystem-targets +++ b/tools/makefile-support/helpsystem-targets @@ -16,3 +16,5 @@ help: @printf "\036" .help-sep-4: @printf "\036" +.help-sep-5: + @printf "\036" diff --git a/tools/makefile-support/makehelp.sh b/tools/makefile-support/makehelp.sh index 4bce15e2fee9..2b3743090958 100755 --- a/tools/makefile-support/makehelp.sh +++ b/tools/makefile-support/makehelp.sh @@ -8,12 +8,13 @@ if [ -n "$CMD" ]; then long_target=".help-long--$CMD"; options_target=".help-options--$CMD"; usage_target=".help-usage--$CMD"; + extra_target=".help-extra--$CMD"; delim=$'\036' # ASCII 30 nl=$'\037' # Try and get the help for the command. Sections of the output will be delimited bv ASCII 30 (arbirary non-printing char) - output=$(make $short_target .help-sep-1 $long_target .help-sep-2 $options_target .help-sep-3 $usage_target .help-sep-4 2>/dev/null) + output=$(make -k $short_target .help-sep-1 $long_target .help-sep-2 $options_target .help-sep-3 $usage_target .help-sep-4 $extra_target .help-sep-5 2>/dev/null) # Clean the output for "read" by replacing newlines with ASCII 31 (also arbitrary) cleaned_output=$(echo "$output" | tr '\n' $nl ) # Read the output into an array @@ -23,6 +24,7 @@ if [ -n "$CMD" ]; then long_desc=$(echo "${sections[1]}" | tr $nl '\n') options_text=$(echo "${sections[2]}" | tr $nl '\n') usage_text=$(echo "${sections[3]}" | tr $nl '\n') + extra_text=$(echo "${sections[4]}" | tr $nl '\n') # If we found a long help description, then continue printing help. if [ -n "$long_desc" ]; then @@ -41,23 +43,30 @@ if [ -n "$CMD" ]; then # We're done loading, so erase the loading message. echo -ne "\r\033[K"; # Output whatever help we hot. - echo "NAME:"; + echo -e "\033[1mNAME:\033[0m"; echo " $CMD - $short_desc"; if [ -n "$usage_text" ]; then echo; - echo "USAGE:"; + echo -e "\033[1mUSAGE:\033[0m"; echo " $usage_text"; fi; if [ -n "$long_desc" ]; then echo; - echo "DESCRIPTION:"; + echo -e "\033[1mDESCRIPTION:\033[0m"; echo " $long_desc" | fmt -w 80; fi; if [ -n "$options_text" ]; then echo; - echo "OPTIONS:"; + echo -e "\033[1mOPTIONS:\033[0m"; echo "$options_text"; fi; + if [ -n "$extra_text" ]; then + IFS= read -r first_line <<< "$extra_text" + rest_of_text="$(echo "$extra_text" | tail -n +2)" + echo; + echo -e "\033[1m$first_line\033[0m" + echo "$rest_of_text"; + fi; # If there's no long help description, there's no additional help for the command. else echo "No help found for $CMD command."; From cb65b95e96cd6ce3e93f3b83598fe985cd348e28 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 16 Jan 2025 11:24:16 -0600 Subject: [PATCH 20/25] fix copy --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4071c6190a9c..b0390f958766 100644 --- a/Makefile +++ b/Makefile @@ -135,7 +135,7 @@ lint-go: .help-short--lint: @echo "Run linters" .help-long--lint: - @echo "Runs the linters for Go and Javascript code. If not linter type is specified, all linters will be run." + @echo "Runs the linters for Go and Javascript code. If linter type is not specified, all linters will be run." .help-usage--lint: @echo "$(TOOL_CMD) lint [linter-type]" .help-extra--lint: From 17048abab1e0371321a192e7fc1781cad429cb34 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 16 Jan 2025 14:45:31 -0600 Subject: [PATCH 21/25] update workflows --- .github/workflows/check-automated-doc.yml | 4 ++-- .github/workflows/test-db-changes.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check-automated-doc.yml b/.github/workflows/check-automated-doc.yml index ae07734cbc26..c3126789d533 100644 --- a/.github/workflows/check-automated-doc.yml +++ b/.github/workflows/check-automated-doc.yml @@ -46,10 +46,10 @@ jobs: - name: Verify golang generated documentation is up-to-date run: | - make generate-doc + make doc if [[ $(git diff) ]]; then echo "❌ fail: uncommited changes" - echo "please run 'make generate-doc' and commit the changes" + echo "please run 'make doc' and commit the changes" git --no-pager diff exit 1 fi diff --git a/.github/workflows/test-db-changes.yml b/.github/workflows/test-db-changes.yml index 10d1ec4ddea2..2a3ce5f6463d 100644 --- a/.github/workflows/test-db-changes.yml +++ b/.github/workflows/test-db-changes.yml @@ -105,9 +105,9 @@ jobs: - name: Verify test schema changes run: | - make dump-test-schema + make test-schema if [[ $(git diff server/datastore/mysql/schema.sql) ]]; then echo "❌ fail: uncommited changes in schema.sql" - echo "please run `make dump-test-schema` and commit the changes" + echo "please run `make test-schema` and commit the changes" exit 1 fi \ No newline at end of file From d67fdabf84579694822c26c5d645f47f85d935c4 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 16 Jan 2025 15:10:05 -0600 Subject: [PATCH 22/25] lint + cleanup --- tools/fdm/main.go | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/tools/fdm/main.go b/tools/fdm/main.go index 175052889bb8..ce24717f8647 100644 --- a/tools/fdm/main.go +++ b/tools/fdm/main.go @@ -51,11 +51,11 @@ func main() { } } - // Transform options into Makefile-compatible environment variables. + // Transform options into Makefile-compatible variables. makeVars := transformToMakeVars(options) makeVars = append(makeVars, "TOOL_CMD=fdm") - // Call the Makefile with the specified target, environment variables, and additional arguments. + // Call the Makefile with the specified target, Make variables, and additional arguments. err = callMake(makeTarget, makeVars, makeArgs) if err != nil { fmt.Printf("Error: %v\n", err) @@ -72,7 +72,7 @@ func splitArgs(args []string) (map[string]string, []string) { skipNext := false for idx, arg := range args { - if skipNext == true { + if skipNext { skipNext = false continue } @@ -82,21 +82,30 @@ func splitArgs(args []string) (map[string]string, []string) { continue } - if isMakeArgs { + switch { + // If we're processing make args (anything after a bare -- ) + // then add the current arg to the list. + case isMakeArgs: makeArgs = append(makeArgs, arg) - } else if strings.HasPrefix(arg, "--") { + // Otherwise if the arg has a -- prefix, treat it like an option + // for the command. + case strings.HasPrefix(arg, "--"): // Remove "--" and split by "=". parts := strings.SplitN(arg[2:], "=", 2) - if len(parts) == 2 { + switch { + // Handle options like --name=foo + case len(parts) == 2: options[parts[0]] = parts[1] - } else if idx+1 < len(args) && !strings.HasPrefix(args[idx+1], "--") { + // Handle options like --name foo + case idx+1 < len(args) && !strings.HasPrefix(args[idx+1], "--"): options[arg[2:]] = args[idx+1] skipNext = true - } else { - // Flags without values default to "true". + // Handle options like --useturbocharge by assuming they're booleans. + default: options[parts[0]] = "true" } - } else { + // Otherwise assume we're dealing with a positional argument. + default: options["arg"+strconv.Itoa(positionalArgsIndex)] = arg positionalArgsIndex++ } @@ -105,20 +114,20 @@ func splitArgs(args []string) (map[string]string, []string) { return options, makeArgs } -// transformToMakeVars converts kebab-cased options to snake-cased Makefile env variables. +// transformToMakeVars converts kebab-cased options to snake-cased Makefile variables. func transformToMakeVars(options map[string]string) []string { var makeVars []string for key, value := range options { // Convert kebab-case to snake_case and uppercase. - envKey := strings.ToUpper(strings.ReplaceAll(key, "-", "_")) - makeVars = append(makeVars, fmt.Sprintf("%s=%s", envKey, value)) + varName := strings.ToUpper(strings.ReplaceAll(key, "-", "_")) + makeVars = append(makeVars, fmt.Sprintf("%s=%s", varName, value)) } return makeVars } -// callMake invokes the `make` command with the given target, environment variables, and additional arguments. +// callMake invokes the `make` command with the given target, variables, and additional arguments. func callMake(target string, makeVars []string, makeArgs []string) error { // Construct the command with target and makeArgs. finalArgs := []string{target} From bd096df76b227fe381e555ec5e0c653a03c802d1 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 16 Jan 2025 15:29:49 -0600 Subject: [PATCH 23/25] only run logic when needed --- Makefile | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b0390f958766..20a0b481c74e 100644 --- a/Makefile +++ b/Makefile @@ -75,11 +75,15 @@ all: build .pre-fleetctl: $(eval APP_NAME = fleetctl) -BINS_TO_BUILD = fleet fleetctl -ifeq ($(ARG1), fleet) - BINS_TO_BUILD = fleet -else ifeq ($(ARG1), fleetctl) - BINS_TO_BUILD = fleetctl +# For the build target, decide which binaries to build. +BINS_TO_BUILD = +ifeq (build,$(filter build,$(MAKECMDGOALS))) + BINS_TO_BUILD = fleet fleetctl + ifeq ($(ARG1), fleet) + BINS_TO_BUILD = fleet + else ifeq ($(ARG1), fleetctl) + BINS_TO_BUILD = fleetctl + endif endif .help-short--build: @echo "Build binaries" @@ -653,4 +657,7 @@ db-replica-reset: fleet db-replica-run: fleet FLEET_MYSQL_ADDRESS=127.0.0.1:3308 FLEET_MYSQL_READ_REPLICA_ADDRESS=127.0.0.1:3309 FLEET_MYSQL_READ_REPLICA_USERNAME=fleet FLEET_MYSQL_READ_REPLICA_DATABASE=fleet FLEET_MYSQL_READ_REPLICA_PASSWORD=insecure ./build/fleet serve --dev --dev_license -include ./tools/makefile-support/helpsystem-targets \ No newline at end of file +include ./tools/makefile-support/helpsystem-targets + +foo: + @echo $(MAKECMDGOALS) \ No newline at end of file From d6b711f30bbbf877c63b703c1fa77dddd34b4549 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 16 Jan 2025 21:34:04 -0600 Subject: [PATCH 24/25] put old targets back as aliases --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 20a0b481c74e..51babd73d625 100644 --- a/Makefile +++ b/Makefile @@ -157,7 +157,7 @@ endif @echo "Update schema.sql from current migrations" test-schema: go run ./tools/dbutils ./server/datastore/mysql/schema.sql - +dump-test-schema: test-schema # This is the base command to run Go tests. # Wrap this to run tests with presets (see `run-go-tests` and `test-go` targets). @@ -286,12 +286,14 @@ generate-dev: .prefix @echo "Update mock data store" mock: .prefix go generate github.com/fleetdm/fleet/v4/server/mock github.com/fleetdm/fleet/v4/server/mock/mockresult github.com/fleetdm/fleet/v4/server/service/mock +generate-mock: mock .help-short--doc: @echo "Generate updated API documentation for activities, osquery flags" doc: .prefix go generate github.com/fleetdm/fleet/v4/server/fleet go generate github.com/fleetdm/fleet/v4/server/service/osquery_utils +generate-doc: doc .help-short--deps: @echo "Install dependent programs and libraries" From 120dedf317fa755056c808454977caedb8478ec0 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Thu, 16 Jan 2025 21:50:20 -0600 Subject: [PATCH 25/25] reorganize and add help --- Makefile | 55 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 51babd73d625..e06bdda6eebf 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ REVISION = $(shell git rev-parse HEAD) REVSHORT = $(shell git rev-parse --short HEAD) USER = $(shell whoami) DOCKER_IMAGE_NAME = fleetdm/fleet +# The tool that was called on the command line (probably `make` or `fdm`). TOOL_CMD = "make" ifdef GO_BUILD_RACE_ENABLED @@ -161,30 +162,13 @@ dump-test-schema: test-schema # This is the base command to run Go tests. # Wrap this to run tests with presets (see `run-go-tests` and `test-go` targets). -# GO_TEST_MAKE_FLAGS: Internal var used by other targets to add arguments to `go test`. -# +# PKG_TO_TEST: Go packages to test, e.g. "server/datastore/mysql". Separate multiple packages with spaces. +# TESTS_TO_RUN: Name specific tests to run in the specified packages. Leave blank to run all tests in the specified packages. +# GO_TEST_EXTRA_FLAGS: Used to specify other arguments to `go test`. +# GO_TEST_MAKE_FLAGS: Internal var used by other targets to add arguments to `go test`. PKG_TO_TEST := "" go_test_pkg_to_test := $(addprefix ./,$(PKG_TO_TEST)) # set paths for packages to test dlv_test_pkg_to_test := $(addprefix github.com/fleetdm/fleet/v4/,$(PKG_TO_TEST)) # set URIs for packages to debug - -DEFAULT_PKG_TO_TEST := ./cmd/... ./ee/... ./orbit/pkg/... ./orbit/cmd/orbit ./pkg/... ./server/... ./tools/... -ifeq ($(CI_TEST_PKG), main) - CI_PKG_TO_TEST=$(shell go list ${DEFAULT_PKG_TO_TEST} | grep -v "server/datastore/mysql" | grep -v "cmd/fleetctl" | grep -v "server/vulnerabilities" | sed -e 's|github.com/fleetdm/fleet/v4/||g') -else ifeq ($(CI_TEST_PKG), integration) - CI_PKG_TO_TEST="server/service" -else ifeq ($(CI_TEST_PKG), mysql) - CI_PKG_TO_TEST="server/datastore/mysql/..." -else ifeq ($(CI_TEST_PKG), fleetctl) - CI_PKG_TO_TEST="cmd/fleetctl/..." -else ifeq ($(CI_TEST_PKG), vuln) - CI_PKG_TO_TEST="server/vulnerabilities/..." -else - CI_PKG_TO_TEST=$(DEFAULT_PKG_TO_TEST) -endif - -ci-pkg-list: - @echo $(CI_PKG_TO_TEST) - .run-go-tests: ifeq ($(PKG_TO_TEST), "") @echo "Please specify one or more packages to test. See '$(TOOL_CMD) help run-go-tests' for more info."; @@ -232,9 +216,36 @@ run-go-tests: debug-go-tests: @MYSQL_TEST=1 REDIS_TEST=1 MINIO_STORAGE_TEST=1 SAML_IDP_TEST=1 NETWORK_TEST=1 make .debug-go-tests +# Set up packages for CI testing. +DEFAULT_PKG_TO_TEST := ./cmd/... ./ee/... ./orbit/pkg/... ./orbit/cmd/orbit ./pkg/... ./server/... ./tools/... +ifeq ($(CI_TEST_PKG), main) + CI_PKG_TO_TEST=$(shell go list ${DEFAULT_PKG_TO_TEST} | grep -v "server/datastore/mysql" | grep -v "cmd/fleetctl" | grep -v "server/vulnerabilities" | sed -e 's|github.com/fleetdm/fleet/v4/||g') +else ifeq ($(CI_TEST_PKG), integration) + CI_PKG_TO_TEST="server/service" +else ifeq ($(CI_TEST_PKG), mysql) + CI_PKG_TO_TEST="server/datastore/mysql/..." +else ifeq ($(CI_TEST_PKG), fleetctl) + CI_PKG_TO_TEST="cmd/fleetctl/..." +else ifeq ($(CI_TEST_PKG), vuln) + CI_PKG_TO_TEST="server/vulnerabilities/..." +else + CI_PKG_TO_TEST=$(DEFAULT_PKG_TO_TEST) +endif # Command used in CI to run all tests. .help-short--test-go: - @echo "Run the Go tests (all packages and tests -- used in CI)" + @echo "Run Go tests for CI" +.help-long--test-go: + @echo "Run one or more bundle of Go tests. These are bundled together to try and make CI testing more parallelizable (and thus faster)." +.help-options--test-go: + @echo "CI_TEST_PKG=[test package]" + @echo "The test package bundle to run. If not specified, all Go tests will run." +.help-extra--test-go: + @echo "AVAILABLE TEST BUNDLES:" + @echo " integration" + @echo " mysql" + @echo " fleetctl" + @echo " vuln" + @echo " main (all tests not included in other bundles)" test-go: test-schema mock make .run-go-tests PKG_TO_TEST="$(CI_PKG_TO_TEST)"