Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 26 additions & 31 deletions cf_cli_java_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ import (
"github.com/simonleung8/flags"
)

// Assert that JavaPlugin implements plugin.Plugin.
var _ plugin.Plugin = (*JavaPlugin)(nil)

// The JavaPlugin is a cf cli plugin that supports taking heap and thread dumps on demand
type JavaPlugin struct{}
type JavaPlugin struct{
verbose bool
}

// UUIDGenerator is an interface that encapsulates the generation of UUIDs
type UUIDGenerator interface {
Expand Down Expand Up @@ -86,49 +91,39 @@ const (
// 1 should the plugin exit nonzero.
func (c *JavaPlugin) Run(cliConnection plugin.CliConnection, args []string) {
// Check if verbose flag is in args for early logging
verbose := false
for _, arg := range args {
if arg == "-v" || arg == "--verbose" {
verbose = true
c.verbose = true
break
}
}

if verbose {
if c.verbose {
fmt.Printf("[VERBOSE] Run called with args: %v\n", args)
}

_, err := c.DoRun(&commandExecutorImpl{cliConnection: cliConnection}, &uuidGeneratorImpl{}, utils.CfJavaPluginUtilImpl{}, args)
_, err := c.DoRun(&commandExecutorImpl{cliConnection: cliConnection}, &uuidGeneratorImpl{}, args)
if err != nil {
if verbose {
if c.verbose {
fmt.Printf("[VERBOSE] Error occurred: %v\n", err)
}
os.Exit(1)
}
if verbose {
if c.verbose {
fmt.Printf("[VERBOSE] Run completed successfully\n")
}
}

// DoRun is an internal method that we use to wrap the cmd package with CommandExecutor for test purposes
func (c *JavaPlugin) DoRun(commandExecutor cmd.CommandExecutor, uuidGenerator UUIDGenerator, util utils.CfJavaPluginUtil, args []string) (string, error) {
func (c *JavaPlugin) DoRun(commandExecutor cmd.CommandExecutor, uuidGenerator UUIDGenerator, args []string) (string, error) {
traceLogger := trace.NewLogger(os.Stdout, true, os.Getenv("CF_TRACE"), "")
ui := terminal.NewUI(os.Stdin, os.Stdout, terminal.NewTeePrinter(os.Stdout), traceLogger)

// Check if verbose flag is in args for early logging
verbose := false
for _, arg := range args {
if arg == "-v" || arg == "--verbose" {
verbose = true
break
}
}

if verbose {
if c.verbose {
fmt.Printf("[VERBOSE] DoRun called with args: %v\n", args)
}

output, err := c.execute(commandExecutor, uuidGenerator, util, args)
output, err := c.execute(commandExecutor, uuidGenerator, args)
if err != nil {
if err.Error() == "unexpected EOF" {
return output, err
Expand Down Expand Up @@ -491,7 +486,7 @@ func toSentenceCase(input string) string {
return strings.ToUpper(string(input[0])) + strings.ToLower(input[1:])
}

func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator UUIDGenerator, util utils.CfJavaPluginUtil, args []string) (string, error) {
func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator UUIDGenerator, args []string) (string, error) {
if len(args) == 0 {
return "", &InvalidUsageError{message: "No command provided"}
}
Expand Down Expand Up @@ -536,7 +531,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator
verbose := commandFlags.IsSet("verbose")

// Helper function for verbose logging with format strings
logVerbose := func(format string, args ...interface{}) {
logVerbose := func(format string, args ...any) {
if verbose {
fmt.Printf("[VERBOSE] "+format+"\n", args...)
}
Expand Down Expand Up @@ -637,7 +632,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator

logVerbose("CF SSH arguments: %v", cfSSHArguments)

supported, err := util.CheckRequiredTools(applicationName)
supported, err := utils.CheckRequiredTools(applicationName)

if err != nil || !supported {
return "required tools checking failed", err
Expand Down Expand Up @@ -670,7 +665,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator
// Initialize fspath and fileName for commands that need them
if command.GenerateFiles || command.NeedsFileName || command.GenerateArbitraryFiles {
logVerbose("Command requires file generation")
fspath, err = util.GetAvailablePath(applicationName, remoteDir)
fspath, err = utils.GetAvailablePath(applicationName, remoteDir)
if err != nil {
return "", fmt.Errorf("failed to get available path: %w", err)
}
Expand Down Expand Up @@ -745,10 +740,10 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator
switch command.FileExtension {
case ".hprof":
logVerbose("Finding heap dump file")
finalFile, err = util.FindHeapDumpFile(cfSSHArguments, fileName, fspath)
finalFile, err = utils.FindHeapDumpFile(cfSSHArguments, fileName, fspath)
case ".jfr":
logVerbose("Finding JFR file")
finalFile, err = util.FindJFRFile(cfSSHArguments, fileName, fspath)
finalFile, err = utils.FindJFRFile(cfSSHArguments, fileName, fspath)
default:
return "", &InvalidUsageError{message: fmt.Sprintf("Unsupported file extension %q", command.FileExtension)}
}
Expand All @@ -764,7 +759,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator

localFileFullPath := localDir + "/" + applicationName + "-" + command.FileNamePart + "-" + uuidGenerator.Generate() + command.FileExtension
logVerbose("Downloading file to: %s", localFileFullPath)
err = util.CopyOverCat(cfSSHArguments, fileName, localFileFullPath)
err = utils.CopyOverCat(cfSSHArguments, fileName, localFileFullPath)
if err == nil {
logVerbose("File download completed successfully")
fmt.Println(toSentenceCase(command.FileLabel) + " file saved to: " + localFileFullPath)
Expand All @@ -775,7 +770,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator

if !keepAfterDownload {
logVerbose("Deleting remote file")
err = util.DeleteRemoteFile(cfSSHArguments, fileName)
err = utils.DeleteRemoteFile(cfSSHArguments, fileName)
if err != nil {
logVerbose("Failed to delete remote file: %v", err)
return "", err
Expand All @@ -790,7 +785,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator
logVerbose("Processing arbitrary files download: %s", fspath)
logVerbose("cfSSHArguments: %v", cfSSHArguments)
// download all files in the generic folder
files, err := util.ListFiles(cfSSHArguments, fspath)
files, err := utils.ListFiles(cfSSHArguments, fspath)
for i, file := range files {
logVerbose("File %d: %s", i+1, file)
}
Expand All @@ -803,7 +798,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator
for _, file := range files {
logVerbose("Downloading file: %s", file)
localFileFullPath := localDir + "/" + file
err = util.CopyOverCat(cfSSHArguments, fspath+"/"+file, localFileFullPath)
err = utils.CopyOverCat(cfSSHArguments, fspath+"/"+file, localFileFullPath)
if err == nil {
logVerbose("File %s downloaded successfully", file)
fmt.Printf("File %s saved to: %s\n", file, localFileFullPath)
Expand All @@ -815,7 +810,7 @@ func (c *JavaPlugin) execute(commandExecutor cmd.CommandExecutor, uuidGenerator

if !keepAfterDownload {
logVerbose("Deleting remote file folder")
err = util.DeleteRemoteFile(cfSSHArguments, fspath)
err = utils.DeleteRemoteFile(cfSSHArguments, fspath)
if err != nil {
logVerbose("Failed to delete remote folder: %v", err)
return "", err
Expand Down Expand Up @@ -902,7 +897,7 @@ func (c *JavaPlugin) GetMetadata() plugin.PluginMetadata {
}
}

// Unlike most Go programs, the `Main()` function will not be used to run all of the
// Unlike most Go programs, the `main()` function will not be used to run all of the
// commands provided in your plugin. Main will be used to initialize the plugin
// process, as well as any dependencies you might require for your
// plugin.
Expand Down
69 changes: 26 additions & 43 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,62 +1,45 @@
module cf.plugin.ref/requires

go 1.23.0
go 1.24.3

toolchain go1.23.5
toolchain go1.24.4

require (
code.cloudfoundry.org/cli v7.1.0+incompatible
code.cloudfoundry.org/cli v0.0.0-20250623142502-fb19e7a825ee
github.com/lithammer/fuzzysearch v1.1.8
github.com/satori/go.uuid v1.2.0
github.com/simonleung8/flags v0.0.0-20170704170018-8020ed7bcf1a
)

require (
code.cloudfoundry.org/bytefmt v0.0.0-20210608160410-67692ebc98de // indirect
code.cloudfoundry.org/cli-plugin-repo v0.0.0-20250414213145-88c4afe9cd65 // indirect
code.cloudfoundry.org/go-log-cache v1.0.0 // indirect
code.cloudfoundry.org/go-loggregator v7.4.0+incompatible // indirect
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f // indirect
code.cloudfoundry.org/bytefmt v0.42.0 // indirect
code.cloudfoundry.org/jsonry v1.1.4 // indirect
code.cloudfoundry.org/rfc5424 v0.0.0-20201103192249-000122071b78 // indirect
code.cloudfoundry.org/tlsconfig v0.0.0-20210615191307-5d92ef3894a7 // indirect
code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d // indirect
github.com/SermoDigital/jose v0.9.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
code.cloudfoundry.org/tlsconfig v0.29.0 // indirect
github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect
github.com/bmizerany/pat v0.0.0-20210406213842-e4b6760bdd6f // indirect
github.com/charlievieth/fs v0.0.1 // indirect
github.com/charlievieth/fs v0.0.3 // indirect
github.com/cloudfoundry/bosh-cli v6.4.1+incompatible // indirect
github.com/cloudfoundry/bosh-utils v0.0.264 // indirect
github.com/cppforlife/go-patch v0.2.0 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/fatih/color v1.12.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/jessevdk/go-flags v1.5.0 // indirect
github.com/cloudfoundry/bosh-utils v0.0.397 // indirect
github.com/cppforlife/go-patch v0.1.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jessevdk/go-flags v1.6.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/lunixbochs/vtclean v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/onsi/gomega v1.36.2 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/tedsuo/rata v1.0.0 // indirect
github.com/vito/go-interact v1.0.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto v0.0.0-20250414145226-207652e42e2e // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a // indirect
google.golang.org/grpc v1.71.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
Loading