Warn users to not have mod.sp files in home directory. Closes #2321

This commit is contained in:
Puskar Basu
2023-09-22 22:37:55 +05:30
committed by GitHub
parent 269a74b945
commit 01097a27e6
16 changed files with 173 additions and 60 deletions

View File

@@ -248,7 +248,7 @@ func initDashboard(ctx context.Context) *initialisation.InitData {
func getInitData(ctx context.Context) *initialisation.InitData {
w, errAndWarnings := workspace.LoadWorkspacePromptingForVariables(ctx)
if errAndWarnings.GetError() != nil {
return initialisation.NewErrorInitData(fmt.Errorf("failed to load workspace: %s", errAndWarnings.GetError().Error()))
return initialisation.NewErrorInitData(fmt.Errorf("failed to load workspace: %s", error_helpers.HandleCancelError(errAndWarnings.GetError()).Error()))
}
i := initialisation.NewInitData()

View File

@@ -335,7 +335,11 @@ func runModInitCmd(cmd *cobra.Command, args []string) {
// helpers
func createWorkspaceMod(ctx context.Context, cmd *cobra.Command, workspacePath string) (*modconfig.Mod, error) {
if !modinstaller.ValidateModLocation(ctx, workspacePath) {
cancel, err := modinstaller.ValidateModLocation(ctx, workspacePath)
if err != nil {
return nil, err
}
if !cancel {
return nil, fmt.Errorf("mod %s cancelled", cmd.Name())
}
@@ -355,7 +359,7 @@ func createWorkspaceMod(ctx context.Context, cmd *cobra.Command, workspacePath s
// load up the written mod file so that we get the updated
// block ranges
mod, err := parse.LoadModfile(workspacePath)
mod, err = parse.LoadModfile(workspacePath)
if err != nil {
return nil, err
}

View File

@@ -136,8 +136,11 @@ func runQueryCmd(cmd *cobra.Command, args []string) {
// set config to indicate whether we are running an interactive query
viper.Set(constants.ConfigKeyInteractive, interactiveMode)
// initialize the cancel handler - for context cancellation
initCtx, cancel := context.WithCancel(ctx)
contexthelpers.StartCancelHandler(cancel)
// start the initializer
initData := query.NewInitData(ctx, args)
initData := query.NewInitData(initCtx, args)
if initData.Result.Error != nil {
exitCode = constants.ExitCodeInitializationFailed
error_helpers.ShowError(ctx, initData.Result.Error)

2
go.mod
View File

@@ -43,7 +43,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.16.0
github.com/stevenle/topsort v0.2.0
github.com/turbot/go-kit v0.8.1
github.com/turbot/go-kit v0.9.0-rc.0
github.com/turbot/steampipe-cloud-sdk-go v0.6.0
github.com/turbot/steampipe-plugin-sdk/v5 v5.6.0-rc.30
github.com/xlab/treeprint v1.2.0

4
go.sum
View File

@@ -1092,8 +1092,8 @@ github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQ
github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tombuildsstuff/giovanni v0.15.1/go.mod h1:0TZugJPEtqzPlMpuJHYfXY6Dq2uLPrXf98D2XQSxNbA=
github.com/turbot/go-kit v0.8.1 h1:Su2RFhwiCAlbVXlG5f3w+t/8vpr1YXwfVfAIXlL+Xbc=
github.com/turbot/go-kit v0.8.1/go.mod h1:AY17SDL/JnVnqUlQIc0Y9mQ2Gbtw0+IwEX4ErywH9bw=
github.com/turbot/go-kit v0.9.0-rc.0 h1:lPVYl2UGC9fzvMSddg4+l17HT6N/CH7tBLxpeCIk53I=
github.com/turbot/go-kit v0.9.0-rc.0/go.mod h1:AY17SDL/JnVnqUlQIc0Y9mQ2Gbtw0+IwEX4ErywH9bw=
github.com/turbot/go-prompt v0.2.6-steampipe.0.0.20221028122246-eb118ec58d50 h1:zs87uA6QZsYLk4RRxDOIxt8ro/B2V6HzoMWm05Lo7ao=
github.com/turbot/go-prompt v0.2.6-steampipe.0.0.20221028122246-eb118ec58d50/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
github.com/turbot/steampipe-cloud-sdk-go v0.6.0 h1:ufAxOpKS1uq7eejuE5sfEu1+d7QAd0RBjl8Bn6+mIs8=

View File

@@ -2,11 +2,12 @@ package constants
// viper config keys
const (
ConfigKeyInteractive = "interactive"
ConfigKeyActiveCommand = "cmd"
ConfigKeyActiveCommandArgs = "cmd_args"
ConfigInteractiveVariables = "interactive_var"
ConfigKeyIsTerminalTTY = "is_terminal"
ConfigKeyServerSearchPath = "server-search-path"
ConfigKeyServerSearchPathPrefix = "server-search-path-prefix"
ConfigKeyInteractive = "interactive"
ConfigKeyActiveCommand = "cmd"
ConfigKeyActiveCommandArgs = "cmd_args"
ConfigInteractiveVariables = "interactive_var"
ConfigKeyIsTerminalTTY = "is_terminal"
ConfigKeyServerSearchPath = "server-search-path"
ConfigKeyServerSearchPathPrefix = "server-search-path-prefix"
ConfigKeyBypassHomeDirModfileWarning = "bypass-home-dir-modfile-warning"
)

View File

@@ -36,7 +36,7 @@ func NewInitData(ctx context.Context) *InitData {
w, errAndWarnings := workspace.LoadWorkspacePromptingForVariables(ctx)
if errAndWarnings.GetError() != nil {
return &InitData{
InitData: *initialisation.NewErrorInitData(fmt.Errorf("failed to load workspace: %s", errAndWarnings.GetError().Error())),
InitData: *initialisation.NewErrorInitData(fmt.Errorf("failed to load workspace: %s", error_helpers.HandleCancelError(errAndWarnings.GetError()).Error())),
}
}
i.Workspace = w

View File

@@ -15,14 +15,18 @@ import (
// ValidateModLocation checks whether you are running from the home directory or if you have
// a lot of non .sql and .sp file in your current directory, and asks for confirmation to continue
func ValidateModLocation(ctx context.Context, workspacePath string) bool {
func ValidateModLocation(ctx context.Context, workspacePath string) (bool, error) {
const MaxResults = 10
cmd := viper.Get(constants.ConfigKeyActiveCommand).(*cobra.Command)
home, _ := os.UserHomeDir()
// check if running in home directory
if workspacePath == home {
return utils.UserConfirmation(fmt.Sprintf("%s: Creating a mod file in the home directory is not recommended.\nBest practice is to create a new directory and run %s from there.\nDo you want to continue? (y/n)", color.YellowString("Warning"), constants.Bold(fmt.Sprintf("steampipe mod %s", cmd.Name()))))
cont, err := utils.UserConfirmation(ctx, fmt.Sprintf("%s: Creating a mod file in the home directory is not recommended.\nBest practice is to create a new directory and run %s from there.\nDo you want to continue? (y/n)", color.YellowString("Warning"), constants.Bold(fmt.Sprintf("steampipe mod %s", cmd.Name()))))
if err != nil {
return false, err
}
return cont, nil
}
// else check if running in a directory containing lot of sql and sp files
fileList, _ := filehelpers.ListFiles(workspacePath, &filehelpers.ListOptions{
@@ -31,8 +35,11 @@ func ValidateModLocation(ctx context.Context, workspacePath string) bool {
MaxResults: MaxResults,
})
if len(fileList) == MaxResults {
return utils.UserConfirmation(fmt.Sprintf("%s: Creating a mod file in a directory with a lot of files or subdirectories is not recommended.\nBest practice is to create a new directory and run %s from there.\nDo you want to continue? (y/n)", color.YellowString("Warning"), constants.Bold(fmt.Sprintf("steampipe mod %s", cmd.Name()))))
cont, err := utils.UserConfirmation(ctx, fmt.Sprintf("%s: Creating a mod file in a directory with a lot of files or subdirectories is not recommended.\nBest practice is to create a new directory and run %s from there.\nDo you want to continue? (y/n)", color.YellowString("Warning"), constants.Bold(fmt.Sprintf("steampipe mod %s", cmd.Name()))))
if err != nil {
return false, err
}
return cont, nil
}
return true
return true, nil
}

View File

@@ -3,11 +3,13 @@ package query
import (
"context"
"fmt"
"path/filepath"
"time"
"github.com/spf13/viper"
"github.com/turbot/steampipe/pkg/constants"
"github.com/turbot/steampipe/pkg/db/db_client"
"github.com/turbot/steampipe/pkg/error_helpers"
"github.com/turbot/steampipe/pkg/export"
"github.com/turbot/steampipe/pkg/initialisation"
"github.com/turbot/steampipe/pkg/statushooks"
@@ -32,6 +34,20 @@ func NewInitData(ctx context.Context, args []string) *InitData {
InitData: *initialisation.NewInitData(),
Loaded: make(chan struct{}),
}
// for interactive mode - do the home directory modfile check before init
if viper.GetBool(constants.ConfigKeyInteractive) {
path := viper.GetString(constants.ArgModLocation)
modFilePath, _ := workspace.FindModFilePath(path)
// if the user cancels - no need to continue init
if err := workspace.HomeDirectoryModfileCheck(ctx, filepath.Dir(modFilePath)); err != nil {
i.Result.Error = err
close(i.Loaded)
return i
}
// home dir modfile already done - set the viper config
viper.Set(constants.ConfigKeyBypassHomeDirModfileWarning, true)
}
go i.init(ctx, args)
return i
@@ -89,7 +105,7 @@ func (i *InitData) init(ctx context.Context, args []string) {
statushooks.SetStatus(ctx, "Loading workspace")
w, errAndWarnings := workspace.LoadWorkspacePromptingForVariables(ctx)
if errAndWarnings.GetError() != nil {
i.Result.Error = fmt.Errorf("failed to load workspace: %s", errAndWarnings.GetError().Error())
i.Result.Error = fmt.Errorf("failed to load workspace: %s", error_helpers.HandleCancelError(errAndWarnings.GetError()).Error())
return
}
i.Result.AddWarnings(errAndWarnings.Warnings...)

View File

@@ -1,6 +1,7 @@
package steampipeconfig
import (
"context"
"fmt"
"log"
"os"
@@ -21,14 +22,14 @@ import (
// if CreatePseudoResources flag is set, construct hcl resources for files with specific extensions
// NOTE: it is an error if there is more than 1 mod defined, however zero mods is acceptable
// - a default mod will be created assuming there are any resource files
func LoadMod(modPath string, parseCtx *parse.ModParseContext) (mod *modconfig.Mod, errorsAndWarnings *error_helpers.ErrorAndWarnings) {
func LoadMod(ctx context.Context, modPath string, parseCtx *parse.ModParseContext) (mod *modconfig.Mod, errorsAndWarnings *error_helpers.ErrorAndWarnings) {
defer func() {
if r := recover(); r != nil {
errorsAndWarnings = error_helpers.NewErrorsAndWarning(helpers.ToError(r))
}
}()
mod, loadModResult := loadModDefinition(modPath, parseCtx)
mod, loadModResult := loadModDefinition(ctx, modPath, parseCtx)
if loadModResult.Error != nil {
return nil, loadModResult
}
@@ -44,21 +45,21 @@ func LoadMod(modPath string, parseCtx *parse.ModParseContext) (mod *modconfig.Mo
}
// load the mod dependencies
if err := loadModDependencies(mod, parseCtx); err != nil {
if err := loadModDependencies(ctx, mod, parseCtx); err != nil {
return nil, error_helpers.NewErrorsAndWarning(err)
}
// populate the resource maps of the current mod using the dependency mods
mod.ResourceMaps = parseCtx.GetResourceMaps()
// now load the mod resource hcl (
mod, errorsAndWarnings = loadModResources(mod, parseCtx)
mod, errorsAndWarnings = loadModResources(ctx, mod, parseCtx)
// add in any warnings from mod load
errorsAndWarnings.AddWarning(loadModResult.Warnings...)
return mod, errorsAndWarnings
}
func loadModDefinition(modPath string, parseCtx *parse.ModParseContext) (mod *modconfig.Mod, errorsAndWarnings *error_helpers.ErrorAndWarnings) {
func loadModDefinition(ctx context.Context, modPath string, parseCtx *parse.ModParseContext) (mod *modconfig.Mod, errorsAndWarnings *error_helpers.ErrorAndWarnings) {
errorsAndWarnings = &error_helpers.ErrorAndWarnings{}
// verify the mod folder exists
_, err := os.Stat(modPath)
@@ -88,7 +89,7 @@ func loadModDefinition(modPath string, parseCtx *parse.ModParseContext) (mod *mo
return mod, errorsAndWarnings
}
func loadModDependencies(parent *modconfig.Mod, parseCtx *parse.ModParseContext) error {
func loadModDependencies(ctx context.Context, parent *modconfig.Mod, parseCtx *parse.ModParseContext) error {
var errors []error
if parent.Require != nil {
// now ensure there is a lock file - if we have any mod dependnecies there MUST be a lock file -
@@ -106,7 +107,7 @@ func loadModDependencies(parent *modconfig.Mod, parseCtx *parse.ModParseContext)
if lockedVersion == nil {
return fmt.Errorf("not all dependencies are installed - run 'steampipe mod install'")
}
if err := loadModDependency(lockedVersion, parseCtx); err != nil {
if err := loadModDependency(ctx, lockedVersion, parseCtx); err != nil {
errors = append(errors, err)
}
}
@@ -115,7 +116,7 @@ func loadModDependencies(parent *modconfig.Mod, parseCtx *parse.ModParseContext)
return error_helpers.CombineErrors(errors...)
}
func loadModDependency(modDependency *versionmap.ResolvedVersionConstraint, parseCtx *parse.ModParseContext) error {
func loadModDependency(ctx context.Context, modDependency *versionmap.ResolvedVersionConstraint, parseCtx *parse.ModParseContext) error {
// dependency mods are installed to <mod path>/<mod nam>@version
// for example workspace_folder/.steampipe/mods/github.com/turbot/steampipe-mod-aws-compliance@v1.0
@@ -135,7 +136,7 @@ func loadModDependency(modDependency *versionmap.ResolvedVersionConstraint, pars
childParseCtx := parse.NewChildModParseContext(parseCtx, modDependency, dependencyDir)
// NOTE: pass in the version and dependency path of the mod - these must be set before it loads its dependencies
dependencyMod, errAndWarnings := LoadMod(dependencyDir, childParseCtx)
dependencyMod, errAndWarnings := LoadMod(ctx, dependencyDir, childParseCtx)
if errAndWarnings.GetError() != nil {
return errAndWarnings.GetError()
}
@@ -151,20 +152,20 @@ func loadModDependency(modDependency *versionmap.ResolvedVersionConstraint, pars
}
func loadModResources(mod *modconfig.Mod, parseCtx *parse.ModParseContext) (*modconfig.Mod, *error_helpers.ErrorAndWarnings) {
func loadModResources(ctx context.Context, mod *modconfig.Mod, parseCtx *parse.ModParseContext) (*modconfig.Mod, *error_helpers.ErrorAndWarnings) {
// if flag is set, create pseudo resources by mapping files
var pseudoResources []modconfig.MappableResource
var err error
if parseCtx.CreatePseudoResources() {
// now execute any pseudo-resource creations based on file mappings
pseudoResources, err = createPseudoResources(mod, parseCtx)
pseudoResources, err = createPseudoResources(ctx, mod, parseCtx)
if err != nil {
return nil, error_helpers.NewErrorsAndWarning(err)
}
}
// get the source files
sourcePaths, err := getSourcePaths(mod.ModPath, parseCtx.ListOptions)
sourcePaths, err := getSourcePaths(ctx, mod.ModPath, parseCtx.ListOptions)
if err != nil {
log.Printf("[WARN] LoadMod: failed to get mod file paths: %v\n", err)
return nil, error_helpers.NewErrorsAndWarning(err)
@@ -177,13 +178,13 @@ func loadModResources(mod *modconfig.Mod, parseCtx *parse.ModParseContext) (*mod
}
// parse all hcl files (NOTE - this reads the CurrentMod out of ParseContext and adds to it)
mod, errAndWarnings := parse.ParseMod(fileData, pseudoResources, parseCtx)
mod, errAndWarnings := parse.ParseMod(ctx, fileData, pseudoResources, parseCtx)
return mod, errAndWarnings
}
// LoadModResourceNames parses all hcl files in modPath and returns the names of all resources
func LoadModResourceNames(mod *modconfig.Mod, parseCtx *parse.ModParseContext) (resources *modconfig.WorkspaceResources, err error) {
func LoadModResourceNames(ctx context.Context, mod *modconfig.Mod, parseCtx *parse.ModParseContext) (resources *modconfig.WorkspaceResources, err error) {
defer func() {
if r := recover(); r != nil {
err = helpers.ToError(r)
@@ -200,7 +201,7 @@ func LoadModResourceNames(mod *modconfig.Mod, parseCtx *parse.ModParseContext) (
}
// now execute any pseudo-resource creations based on file mappings
pseudoResources, err := createPseudoResources(mod, parseCtx)
pseudoResources, err := createPseudoResources(ctx, mod, parseCtx)
if err != nil {
return nil, err
}
@@ -212,7 +213,7 @@ func LoadModResourceNames(mod *modconfig.Mod, parseCtx *parse.ModParseContext) (
}
}
sourcePaths, err := getSourcePaths(mod.ModPath, parseCtx.ListOptions)
sourcePaths, err := getSourcePaths(ctx, mod.ModPath, parseCtx.ListOptions)
if err != nil {
log.Printf("[WARN] LoadModResourceNames: failed to get mod file paths: %v\n", err)
return nil, err
@@ -240,8 +241,8 @@ func GetModFileExtensions() []string {
// this will include hcl files (with .sp extension)
// as well as any other files with extensions that have been registered for pseudo resource creation
// (see steampipeconfig/modconfig/resource_type_map.go)
func getSourcePaths(modPath string, listOpts *filehelpers.ListOptions) ([]string, error) {
sourcePaths, err := filehelpers.ListFiles(modPath, listOpts)
func getSourcePaths(ctx context.Context, modPath string, listOpts *filehelpers.ListOptions) ([]string, error) {
sourcePaths, err := filehelpers.ListFilesWithContext(ctx, modPath, listOpts)
if err != nil {
return nil, err
}
@@ -249,7 +250,7 @@ func getSourcePaths(modPath string, listOpts *filehelpers.ListOptions) ([]string
}
// create pseudo-resources for any files whose extensions are registered
func createPseudoResources(mod *modconfig.Mod, parseCtx *parse.ModParseContext) ([]modconfig.MappableResource, error) {
func createPseudoResources(ctx context.Context, mod *modconfig.Mod, parseCtx *parse.ModParseContext) ([]modconfig.MappableResource, error) {
// create list options to find pseudo resources
listOpts := &filehelpers.ListOptions{
Flags: parseCtx.ListOptions.Flags,
@@ -257,7 +258,7 @@ func createPseudoResources(mod *modconfig.Mod, parseCtx *parse.ModParseContext)
Exclude: parseCtx.ListOptions.Exclude,
}
// list all registered files
sourcePaths, err := getSourcePaths(mod.ModPath, listOpts)
sourcePaths, err := getSourcePaths(ctx, mod.ModPath, listOpts)
if err != nil {
return nil, err
}

View File

@@ -17,10 +17,10 @@ import (
"golang.org/x/exp/maps"
)
func LoadVariableDefinitions(variablePath string, parseCtx *parse.ModParseContext) (*modconfig.ModVariableMap, error) {
func LoadVariableDefinitions(ctx context.Context, variablePath string, parseCtx *parse.ModParseContext) (*modconfig.ModVariableMap, error) {
// only load mod and variables blocks
parseCtx.BlockTypes = []string{modconfig.BlockTypeVariable}
mod, errAndWarnings := LoadMod(variablePath, parseCtx)
mod, errAndWarnings := LoadMod(ctx, variablePath, parseCtx)
if errAndWarnings.GetError() != nil {
return nil, errAndWarnings.GetError()
}

View File

@@ -1,6 +1,7 @@
package parse
import (
"context"
"fmt"
"log"
"os"
@@ -97,7 +98,7 @@ func ParseModDefinition(modPath string, evalCtx *hcl.EvalContext) (*modconfig.Mo
// ParseMod parses all source hcl files for the mod path and associated resources, and returns the mod object
// NOTE: the mod definition has already been parsed (or a default created) and is in opts.RunCtx.RootMod
func ParseMod(fileData map[string][]byte, pseudoResources []modconfig.MappableResource, parseCtx *ModParseContext) (*modconfig.Mod, *error_helpers.ErrorAndWarnings) {
func ParseMod(ctx context.Context, fileData map[string][]byte, pseudoResources []modconfig.MappableResource, parseCtx *ModParseContext) (*modconfig.Mod, *error_helpers.ErrorAndWarnings) {
body, diags := ParseHclFiles(fileData)
if diags.HasErrors() {
return nil, error_helpers.NewErrorsAndWarning(plugin.DiagsToError("Failed to load all mod source files", diags))

View File

@@ -161,7 +161,7 @@ func showNotificationsForCommand(cmd *cobra.Command, cmdArgs []string) bool {
return !(isPluginUpdateCmd(cmd) ||
IsPluginManagerCmd(cmd) ||
isServiceStopCmd(cmd) ||
isBatchQueryCmd(cmd, cmdArgs) ||
IsBatchQueryCmd(cmd, cmdArgs) ||
isCompletionCmd(cmd))
}
@@ -177,6 +177,6 @@ func IsPluginManagerCmd(cmd *cobra.Command) bool {
func isPluginUpdateCmd(cmd *cobra.Command) bool {
return cmd.Name() == "update" && cmd.Parent() != nil && cmd.Parent().Name() == "plugin"
}
func isBatchQueryCmd(cmd *cobra.Command, cmdArgs []string) bool {
func IsBatchQueryCmd(cmd *cobra.Command, cmdArgs []string) bool {
return cmd.Name() == "query" && len(cmdArgs) > 0
}

View File

@@ -1,19 +1,37 @@
package utils
import (
"context"
"fmt"
"log"
"strings"
)
// UserConfirmation displays the warning message and asks the user for input
// regarding whether to continue or not
func UserConfirmation(warning string) bool {
fmt.Println(warning)
var userConfirm string
_, err := fmt.Scanf("%s", &userConfirm)
if err != nil {
log.Fatal(err)
func UserConfirmation(ctx context.Context, warningMsg string) (bool, error) {
fmt.Println(warningMsg)
confirm := make(chan string, 1)
confirmErr := make(chan error, 1)
go func() {
defer func() {
close(confirm)
close(confirmErr)
}()
var userConfirm string
_, err := fmt.Scanf("%s", &userConfirm)
if err != nil {
confirmErr <- err
return
}
confirm <- userConfirm
}()
select {
case err := <-confirmErr:
return false, err
case <-ctx.Done():
return false, ctx.Err()
case c := <-confirm:
return strings.ToUpper(c) == "Y", nil
}
return strings.ToUpper(userConfirm) == "Y"
}

View File

@@ -10,10 +10,14 @@ import (
"strings"
"sync"
"github.com/fatih/color"
"github.com/fsnotify/fsnotify"
"github.com/spf13/cobra"
"github.com/spf13/viper"
filehelpers "github.com/turbot/go-kit/files"
"github.com/turbot/go-kit/filewatcher"
"github.com/turbot/steampipe-plugin-sdk/v5/sperr"
"github.com/turbot/steampipe/pkg/cmdconfig"
"github.com/turbot/steampipe/pkg/constants"
"github.com/turbot/steampipe/pkg/dashboard/dashboardevents"
"github.com/turbot/steampipe/pkg/db/db_common"
@@ -24,6 +28,7 @@ import (
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/turbot/steampipe/pkg/steampipeconfig/parse"
"github.com/turbot/steampipe/pkg/steampipeconfig/versionmap"
"github.com/turbot/steampipe/pkg/task"
"github.com/turbot/steampipe/pkg/utils"
)
@@ -199,7 +204,7 @@ func (w *Workspace) ModfileExists() bool {
// check whether the workspace contains a modfile
// this will determine whether we load files recursively, and create pseudo resources for sql files
func (w *Workspace) setModfileExists() {
modFile, err := w.findModFilePath(w.Path)
modFile, err := FindModFilePath(w.Path)
modFileExists := err != ErrorNoModDefinition
if modFileExists {
@@ -219,7 +224,8 @@ func (w *Workspace) setModfileExists() {
}
}
func (w *Workspace) findModFilePath(folder string) (string, error) {
// TODO comment
func FindModFilePath(folder string) (string, error) {
folder, err := filepath.Abs(folder)
if err != nil {
return "", err
@@ -238,12 +244,57 @@ func (w *Workspace) findModFilePath(folder string) (string, error) {
// this typically means that we are already in the root directory
return "", ErrorNoModDefinition
}
return w.findModFilePath(filepath.Dir(folder))
return FindModFilePath(filepath.Dir(folder))
}
return modFilePath, nil
}
func HomeDirectoryModfileCheck(ctx context.Context, workspacePath string) error {
// bypass all the checks if ConfigKeyBypassHomeDirModfileWarning is set - it means home dir modfile check
// has already happened before
if viper.GetBool(constants.ConfigKeyBypassHomeDirModfileWarning) {
return nil
}
// get the cmd and home dir
cmd := viper.Get(constants.ConfigKeyActiveCommand).(*cobra.Command)
home, _ := os.UserHomeDir()
_, err := os.Stat(filepaths.ModFilePath(workspacePath))
modFileExists := !os.IsNotExist(err)
// check if your workspace path is home dir and if modfile exists
if workspacePath == home && modFileExists {
// for interactive query - ask for confirmation to continue
if cmd.Name() == "query" && viper.GetBool(constants.ConfigKeyInteractive) {
confirm, err := utils.UserConfirmation(ctx, fmt.Sprintf("%s: You have a mod.sp file in your home directory. This is not recommended.\nAs a result, steampipe will try to load all the files in home and its sub-directories, which can cause performance issues.\nBest practice is to put mod.sp files in their own directories.\nDo you still want to continue? (y/n)", color.YellowString("Warning")))
if err != nil {
return err
}
if !confirm {
return sperr.New("failed to load workspace: execution cancelled")
}
return nil
}
// for batch query mode - if output is table, just warn
if task.IsBatchQueryCmd(cmd, viper.GetStringSlice(constants.ConfigKeyActiveCommandArgs)) && cmdconfig.Viper().GetString(constants.ArgOutput) == constants.OutputFormatTable {
error_helpers.ShowWarning("You have a mod.sp file in your home directory. This is not recommended.\nAs a result, steampipe will try to load all the files in home and its sub-directories, which can cause performance issues.\nBest practice is to put mod.sp files in their own directories.\nHit Ctrl+C to stop.\n")
return nil
}
// for other cmds - if home dir has modfile, just warn
error_helpers.ShowWarning("You have a mod.sp file in your home directory. This is not recommended.\nAs a result, steampipe will try to load all the files in home and its sub-directories, which can cause performance issues.\nBest practice is to put mod.sp files in their own directories.\nHit Ctrl+C to stop.\n")
}
return nil
}
func (w *Workspace) loadWorkspaceMod(ctx context.Context) *error_helpers.ErrorAndWarnings {
// check if your workspace path is home dir and if modfile exists - if yes then warn and ask user to continue or not
if err := HomeDirectoryModfileCheck(ctx, w.Path); err != nil {
return error_helpers.NewErrorsAndWarning(err)
}
// resolve values of all input variables
// we WILL validate missing variables when loading
validateMissing := true
@@ -270,7 +321,8 @@ func (w *Workspace) loadWorkspaceMod(ctx context.Context) *error_helpers.ErrorAn
parseCtx.BlockTypeExclusions = []string{modconfig.BlockTypeVariable}
// load the workspace mod
m, otherErrorAndWarning := steampipeconfig.LoadMod(w.Path, parseCtx)
log.Println("[INFO] >> 1. ctx:", &ctx)
m, otherErrorAndWarning := steampipeconfig.LoadMod(ctx, w.Path, parseCtx)
errorsAndWarnings.Merge(otherErrorAndWarning)
if errorsAndWarnings.Error != nil {
return errorsAndWarnings
@@ -293,6 +345,9 @@ func (w *Workspace) loadWorkspaceMod(ctx context.Context) *error_helpers.ErrorAn
}
func (w *Workspace) getInputVariables(ctx context.Context, validateMissing bool) (*modconfig.ModVariableMap, *error_helpers.ErrorAndWarnings) {
log.Println("[INFO] >> start getInputVariables")
defer log.Println("[INFO] >> end getInputVariables")
// build a run context just to use to load variable definitions
variablesParseCtx, err := w.getParseContext(ctx)
if err != nil {
@@ -303,8 +358,12 @@ func (w *Workspace) getInputVariables(ctx context.Context, validateMissing bool)
}
func (w *Workspace) getVariableValues(ctx context.Context, variablesParseCtx *parse.ModParseContext, validateMissing bool) (*modconfig.ModVariableMap, *error_helpers.ErrorAndWarnings) {
log.Println("[INFO] >> start getVariableValues")
defer log.Println("[INFO] >> end getVariableValues")
// load variable definitions
variableMap, err := steampipeconfig.LoadVariableDefinitions(w.Path, variablesParseCtx)
log.Println("[INFO] >> 1. ctx:", &ctx)
variableMap, err := steampipeconfig.LoadVariableDefinitions(ctx, w.Path, variablesParseCtx)
if err != nil {
return nil, error_helpers.NewErrorsAndWarning(err)
}
@@ -315,6 +374,8 @@ func (w *Workspace) getVariableValues(ctx context.Context, variablesParseCtx *pa
// build options used to load workspace
// set flags to create pseudo resources and a default mod if needed
func (w *Workspace) getParseContext(ctx context.Context) (*parse.ModParseContext, error) {
log.Println("[INFO] >> start getParseContext")
defer log.Println("[INFO] >> end getParseContext")
parseFlag := parse.CreateDefaultMod
if w.loadPseudoResources {
parseFlag |= parse.CreatePseudoResources
@@ -401,7 +462,7 @@ func (w *Workspace) loadWorkspaceResourceName(ctx context.Context) (*modconfig.W
return nil, err
}
workspaceResourceNames, err := steampipeconfig.LoadModResourceNames(w.Mod, parseCtx)
workspaceResourceNames, err := steampipeconfig.LoadModResourceNames(ctx, w.Mod, parseCtx)
if err != nil {
return nil, err
}

View File

@@ -429,6 +429,7 @@ load "$LIB_BATS_SUPPORT/load.bash"
}
@test "verify cache ttl works when set in database options" {
skip "re-enable after verifying/fixing the default.spc overwrite issue" # https://github.com/turbot/steampipe/issues/3891
export STEAMPIPE_LOG=info
cp $SRC_DATA_DIR/chaos_no_options.spc $STEAMPIPE_INSTALL_DIR/config/chaos_no_options.spc