Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
11 changes: 10 additions & 1 deletion cli/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"path/filepath"
"runtime"
"runtime/debug"
"slices"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -3280,7 +3281,15 @@ func RobotsPartRemoveFragmentAction(c *cli.Context, args robotsPartRemoveFragmen
}
}
} else {
// No fragment provided, prompt user to select
if !isInteractive() {
names := make([]string, 0, len(fragmentNamesToIDs))
for name, id := range fragmentNamesToIDs {
names = append(names, fmt.Sprintf(" %s (%s)", name, id))
}
slices.Sort(names)
return fmt.Errorf("--fragment flag required in non-interactive mode; available fragments:\n%s",
strings.Join(names, "\n"))
}
whichFragment, whichID, err = client.selectFragment(fragmentNamesToIDs)
if err != nil {
return err
Expand Down
41 changes: 30 additions & 11 deletions cli/module_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ type generateModuleArgs struct {
func GenerateModuleAction(cCtx *cli.Context, args generateModuleArgs) error {
c, err := newViamClient(cCtx)
if err != nil {
if !isInteractive() {
return errors.New("authentication required; run `viam login` before using module generate non-interactively")
}
shouldContinueGeneration := promptUnauthenticated()
if !shouldContinueGeneration {
return err
Expand Down Expand Up @@ -129,6 +132,10 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context, args generateModule
}

if newModule.HasEmptyInput() {
if !isInteractive() {
return errors.New("missing required flags for non-interactive mode; " +
"provide --name, --language, --public-namespace, --resource-subtype, and --model-name")
}
err = promptUser(newModule)
if err != nil {
return err
Expand All @@ -141,7 +148,7 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context, args generateModule
}
populateAdditionalInfo(newModule)

s := spinner.New()
var s *spinner.Spinner
var fatalError error
var registryURL string
nonFatalError := false
Expand All @@ -150,61 +157,73 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context, args generateModule
return err
}
globalArgs := *gArgs

// logTitle updates the spinner in interactive mode, prints a status line
// in non-interactive mode, and is a no-op in debug mode.
Comment on lines +168 to +169
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused, why do we want this to be a no-op in debug mode? I would think that debug mode should have no impact on behavior other than providing additional log messages, at least when we're in interactive mode.

logTitle := func(string) {}
interactive := isInteractive()
if interactive && !globalArgs.Debug {
s = spinner.New()
logTitle = func(msg string) { s.Title(msg) }
} else if !globalArgs.Debug {
logTitle = func(msg string) { printf(cCtx.App.Writer, "%s", msg) }
}

action := func() {
s.Title("Getting latest release...")
logTitle("Getting latest release...")
version, err := getLatestSDKTag(cCtx, newModule.Language, globalArgs)
if err != nil {
fatalError = err
return
}
newModule.SDKVersion = version[1:]

s.Title("Setting up module directory...")
logTitle("Setting up module directory...")
if err = setupDirectories(cCtx, newModule.ModuleName, globalArgs); err != nil {
fatalError = err
return
}

s.Title("Creating module and generating manifest...")
logTitle("Creating module and generating manifest...")
registryURL, err = createModuleAndManifest(cCtx, c, *newModule, globalArgs)
if err != nil {
fatalError = err
return
}

s.Title("Rendering common files...")
logTitle("Rendering common files...")
if err = renderCommonFiles(cCtx, *newModule, globalArgs); err != nil {
fatalError = err
return
}

s.Title(fmt.Sprintf("Copying %s files...", newModule.Language))
logTitle(fmt.Sprintf("Copying %s files...", newModule.Language))
if err = copyLanguageTemplate(cCtx, newModule.Language, newModule.ModuleName, globalArgs); err != nil {
fatalError = err
return
}

s.Title("Rendering template...")
logTitle("Rendering template...")
if err = renderTemplate(cCtx, *newModule, globalArgs); err != nil {
fatalError = err
return
}

s.Title(fmt.Sprintf("Generating %s stubs...", newModule.Language))
logTitle(fmt.Sprintf("Generating %s stubs...", newModule.Language))
if err = generateStubs(cCtx, *newModule, globalArgs); err != nil {
warningf(cCtx.App.ErrWriter, err.Error())
nonFatalError = true
}
}

if globalArgs.Debug {
action()
} else {
if interactive && !globalArgs.Debug {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SImilar question here, why do treat the debug case and the non-interactive case the same?

s.Action(action)
err := s.Run()
if err != nil {
return err
}
} else {
action()
}

if fatalError != nil {
Expand Down
12 changes: 12 additions & 0 deletions cli/tty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package cli

import (
"os"

"golang.org/x/term"
)

// isInteractive reports whether stdin is connected to a terminal.
func isInteractive() bool {
return term.IsTerminal(int(os.Stdin.Fd()))
}
Loading