github.com/swaros/contxt/module/runner@v0.0.0-20240305083542-3dbd4436ac40/functions.go (about) 1 // Copyright (c) 2023 Thomas Ziegler <thomas.zglr@googlemail.com>. All rights reserved. 2 // 3 // # Licensed under the MIT License 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 // SOFTWARE. 22 package runner 23 24 import ( 25 "errors" 26 "fmt" 27 "os" 28 "runtime" 29 "sort" 30 "strconv" 31 "strings" 32 "time" 33 34 "github.com/sirupsen/logrus" 35 "github.com/swaros/contxt/module/configure" 36 "github.com/swaros/contxt/module/ctxout" 37 "github.com/swaros/contxt/module/dirhandle" 38 "github.com/swaros/contxt/module/mimiclog" 39 "github.com/swaros/contxt/module/systools" 40 "github.com/swaros/contxt/module/tasks" 41 "github.com/swaros/contxt/module/yaclint" 42 "gopkg.in/yaml.v2" 43 ) 44 45 type CmdExecutorImpl struct { 46 session *CmdSession 47 } 48 49 func NewCmd(session *CmdSession) *CmdExecutorImpl { 50 return &CmdExecutorImpl{ 51 session: session, 52 } 53 } 54 55 func (c *CmdExecutorImpl) Combine4Print(msg ...interface{}) []interface{} { 56 var outInterfaces []interface{} 57 outInterfaces = append(outInterfaces, c.session.OutPutHdnl) 58 outInterfaces = append(outInterfaces, c.session.Printer) 59 outInterfaces = append(outInterfaces, msg...) 60 return outInterfaces 61 } 62 63 func (c *CmdExecutorImpl) MessageToString(msg ...interface{}) string { 64 msg = c.Combine4Print(msg...) 65 return ctxout.ToString(msg...) 66 } 67 68 func (c *CmdExecutorImpl) Print(msg ...interface{}) { 69 ctxout.Print(c.Combine4Print(msg...)...) 70 } 71 72 func (c *CmdExecutorImpl) Println(msg ...interface{}) { 73 ctxout.PrintLn(c.Combine4Print(msg...)...) 74 } 75 76 func (c *CmdExecutorImpl) doMagicParamOne(args string) { 77 } 78 79 func (c *CmdExecutorImpl) CallBackOldWs(oldws string) bool { 80 c.session.Log.Logger.Info("OLD workspace: ", oldws) 81 // get all paths first 82 configure.GetGlobalConfig().PathWorkerNoCd(func(_ string, path string) { 83 84 current := dirhandle.Pushd() 85 template, exists, _ := c.session.TemplateHndl.Load() 86 Fields := logrus.Fields{ 87 "template: ": template, 88 "exists": exists, 89 "path": path, 90 } 91 c.session.Log.Logger.Debug("path parsing ", Fields) 92 93 if exists && template.Config.Autorun.Onleave != "" { 94 onleaveTarget := template.Config.Autorun.Onleave 95 Fields := logrus.Fields{ 96 "target": onleaveTarget, 97 } 98 c.session.Log.Logger.Info("execute leave-action", Fields) 99 c.RunTargets(onleaveTarget, true) 100 101 } 102 current.Popd() 103 104 }) 105 return true 106 } 107 108 func (c *CmdExecutorImpl) CallBackNewWs(newWs string) { 109 c.ResetVariables() // reset old variables while change the workspace. (req for shell mode) 110 c.session.Log.Logger.Info("NEW workspace: ", newWs) 111 configure.GetGlobalConfig().PathWorker(func(_ string, path string) { // iterate any path 112 template, exists, _ := c.session.TemplateHndl.Load() 113 Fields := logrus.Fields{ 114 "template: ": template, 115 "exists": exists, 116 "path": path, 117 } 118 c.session.Log.Logger.Debug("path parsing", Fields) 119 120 // try to run onEnter func at any possible target in the workspace 121 if exists && template.Config.Autorun.Onenter != "" { 122 Fields := logrus.Fields{ 123 "target": template.Config.Autorun.Onenter, 124 } 125 onEnterTarget := template.Config.Autorun.Onenter 126 c.session.Log.Logger.Info("execute enter-action", Fields) 127 c.RunTargets(onEnterTarget, true) 128 } 129 130 }, func(origin string) { 131 Fields := logrus.Fields{ 132 "current-dir": origin, 133 } 134 c.session.Log.Logger.Debug("done calling autoruns on sub-dirs", Fields) 135 }) 136 } 137 138 // set the default runtime variables depeding the predefined variables from 139 // the main init, and the given variables depending the task and environment 140 func (c *CmdExecutorImpl) SetStartupVariables(dataHndl *tasks.CombinedDh, template *configure.RunConfig) { 141 // first apply logger if poosible 142 mimiclog.ApplyLogger(c.session.Log.Logger, dataHndl) 143 144 c.session.Log.Logger.Debug("set startup variables") 145 // get the predifined variables from the MainInit function 146 // and set them to the datahandler 147 for k, v := range c.session.DefaultVariables { 148 dataHndl.SetPH(k, v) 149 } 150 151 currentDir, err := os.Getwd() 152 if err != nil { 153 c.session.Log.Logger.Error("error while getting current dir", err) 154 } else { 155 // we will override the current dir from the predefined ones, with the current dir 156 dataHndl.SetPH("CTX_PWD", currentDir) 157 dataHndl.SetPH("BASEPATH", currentDir) 158 } 159 160 // template depending variables 161 dataHndl.SetPH("CTX_PROJECT", template.Workspace.Project) 162 dataHndl.SetPH("CTX_ROLE", template.Workspace.Role) 163 dataHndl.SetPH("CTX_VERSION", template.Workspace.Version) 164 165 dataHndl.SetPH("CTX_WS", configure.GetGlobalConfig().UsedV2Config.CurrentSet) 166 keys := "" 167 configure.GetGlobalConfig().ExecOnWorkSpaces(func(index string, cfg configure.ConfigurationV2) { 168 for _, ws2 := range cfg.Paths { 169 keys += setConfigVaribales(dataHndl, ws2, "WS") // there a space is added at the end already 170 } 171 }) 172 c.session.Log.Logger.Debug("set startup variables for ws2", keys) 173 dataHndl.SetPH("CTX_WS_KEYS", keys) 174 // read the imports from the template and set them to the datahandler 175 c.handleImports(dataHndl, template) 176 } 177 178 // taking care about the imports. 179 // these are the imports from the template, defined in config.imports and they are 180 // used as variables map for the current run. 181 // these imports will be set as map[string]string to the datahandler as long the are json or yaml files. 182 // and can be used as placeholder in the tasks. 183 // for example: 184 // 185 // imports: 186 // - imports.json 187 // - imports.yaml 188 // 189 // this can be used in the tasks as ${imports.json:key1} or ${imports.yaml:key1} 190 // but if an string is given, sperated by a space, the string will be used as key. 191 // for example: 192 // 193 // imports: 194 // - imports.json jmap 195 // - imports.yaml ymap 196 // 197 // this can be used in the tasks as ${jmap:key1} or ${ymap:key1} 198 // any other file type will be loaded as string and assigned to the key with the whole content of the file. 199 // for example: 200 // 201 // imports: 202 // - imports.txt 203 // 204 // this can be used in the tasks as ${imports.txt} 205 // or by using the key by the import 206 // for example: 207 // 208 // imports: 209 // - imports.txt txt 210 // 211 // this can be used in the tasks as ${txt} 212 func (c *CmdExecutorImpl) handleImports(dataHndl *tasks.CombinedDh, template *configure.RunConfig) { 213 importHndlr := NewImportHandler(c.session.Log.Logger, dataHndl, c.session.TemplateHndl) 214 importHndlr.SetImports(template.Config.Imports) 215 if err := importHndlr.HandleImports(); err != nil { 216 c.Println(ctxout.ForeRed, "error while handling imports", ctxout.ForeYellow, err) 217 c.session.Log.Logger.Error("error while handling imports", err) 218 systools.Exit(systools.ErrorBySystem) 219 } 220 } 221 222 func setConfigVaribales(dataHndl *tasks.CombinedDh, wsInfo configure.WorkspaceInfoV2, varPrefix string) string { 223 pathStrInfo := "" 224 if wsInfo.Project != "" && wsInfo.Role != "" { 225 prefix := wsInfo.Project + "_" + wsInfo.Role 226 pathkey := varPrefix + "0_" + prefix 227 dataHndl.SetPH(pathkey, wsInfo.Path) // at least XXX0 without any version. this could be overwritten by other checkouts 228 pathStrInfo += pathkey + " " 229 if wsInfo.Version != "" { 230 // if version is set, we use them for avoid conflicts with different checkouts 231 if versionSan, err := systools.CheckForCleanString(wsInfo.Version); err == nil { 232 prefix += "_" + versionSan 233 // add it to ws1 as prefix for versionized keys 234 dataHndl.SetPH(varPrefix+"1_"+prefix, wsInfo.Path) 235 } 236 } 237 } 238 return pathStrInfo 239 } 240 241 // RunTargets run the given targets 242 // force is used as flag for the first level targets, and is used 243 // to runs shared targets once in front of the regular assigned targets 244 func (c *CmdExecutorImpl) RunTargets(target string, force bool) error { 245 if template, exists, err := c.session.TemplateHndl.Load(); err != nil { 246 c.session.Log.Logger.Error("error while loading template", err) 247 return err 248 } else if !exists { 249 c.session.Log.Logger.Error("template not exists") 250 return errors.New("no contxt template found in current directory") 251 } else { 252 253 datahndl := tasks.NewCombinedDataHandler() 254 c.SetStartupVariables(datahndl, &template) 255 datahndl.SetPH("CTX_TARGET", target) 256 datahndl.SetPH("CTX_FORCE", strconv.FormatBool(force)) 257 258 requireHndl := tasks.NewDefaultRequires(datahndl, c.session.Log.Logger) 259 executer := tasks.NewTaskListExec( 260 template, 261 datahndl, 262 requireHndl, 263 c.getOutHandler(), 264 tasks.ShellCmd, 265 ) 266 executer.SetLogger(c.session.Log.Logger) 267 code := executer.RunTarget(target, force) 268 switch code { 269 case systools.ExitByNoTargetExists: 270 c.session.Log.Logger.Error("target not exists:", target) 271 return errors.New("target " + target + " not exists") 272 case systools.ExitAlreadyRunning: 273 c.session.Log.Logger.Info("target already running") 274 return nil 275 case systools.ExitCmdError: 276 c.session.Log.Logger.Error("error while running target ", target) 277 return errors.New("error while running target:" + target) 278 case systools.ExitByNothingToDo: 279 c.session.Log.Logger.Info("nothing to do ", target) 280 return nil 281 case systools.ExitOk: 282 c.session.Log.Logger.Info("target executed successfully") 283 return nil 284 default: 285 c.session.Log.Logger.Error("unexpected exit code:", code) 286 return errors.New("unexpected exit code:" + fmt.Sprintf("%d", code)) 287 } 288 } 289 290 } 291 292 func (c *CmdExecutorImpl) GetTargets(incInvisible bool) []string { 293 if template, exists, err := c.session.TemplateHndl.Load(); err != nil { 294 c.session.Log.Logger.Error("error while loading template", err) 295 } else if !exists { 296 c.session.Log.Logger.Error("template not exists", err) 297 } else { 298 if res, have := TemplateTargetsAsMap(template, incInvisible); have { 299 return res 300 } 301 } 302 return nil 303 } 304 305 func (c *CmdExecutorImpl) ResetVariables() { 306 } 307 308 func (c *CmdExecutorImpl) MainInit() { 309 c.initDefaultVariables() 310 } 311 312 // initDefaultVariables init the default variables for the current session. 313 // these are the varibales they should not change during the session. 314 func (c *CmdExecutorImpl) initDefaultVariables() { 315 if currentPath, err := os.Getwd(); err != nil { 316 ctxout.CtxOut("Error while reading current directory", err) 317 systools.Exit(systools.ErrorBySystem) 318 } else { 319 c.setVariable("CTX_PWD", currentPath) 320 c.setVariable("CTX_PATH", currentPath) 321 c.setVariable("BASEPATH", currentPath) 322 } 323 c.setVariable("CTX_OS", runtime.GOOS) 324 c.setVariable("CTX_ARCH", runtime.GOARCH) 325 c.setVariable("CTX_USER", os.Getenv("USER")) 326 c.setVariable("CTX_HOST", getHostname()) 327 c.setVariable("CTX_HOME", os.Getenv("HOME")) 328 c.setVariable("CTX_DATE", time.Now().Format("2006-01-02")) 329 c.setVariable("CTX_TIME", time.Now().Format("15:04:05")) 330 c.setVariable("CTX_DATETIME", time.Now().Format("2006-01-02 15:04:05")) 331 332 c.setVariable("CTX_VERSION", configure.GetVersion()) 333 c.setVariable("CTX_BUILD_NO", configure.GetBuild()) 334 335 c.handleWindowsInit() // it self is testing if we are on windows 336 } 337 338 func getHostname() string { 339 if hostname, err := os.Hostname(); err != nil { 340 return "" 341 } else { 342 return hostname 343 } 344 } 345 346 func (c *CmdExecutorImpl) handleWindowsInit() { 347 if runtime.GOOS == "windows" { 348 // we need to set the console to utf8, to be able to print utf8 chars 349 // in the console 350 if os.Getenv("CTX_COLOR") == "ON" { // then lets see if this should forced for beeing enabled by env-var 351 c.SetColor(true) 352 } else { 353 // if not forced already we try to figure out, by oure own, if the powershell is able to support ANSII 354 // this is since version 7 the case 355 pwrShellRunner := tasks.GetShellRunnerForOs("windows") 356 version, _ := pwrShellRunner.ExecSilentAndReturnLast(PWRSHELL_CMD_VERSION) 357 c.setVariable("CTX_PS_VERSION", version) // also setup varibale to have the PS version in place 358 if version >= "7" { 359 c.SetColor(true) 360 } 361 } 362 } 363 } 364 365 // updates the given variable in the current session. 366 // this is just for keeping the variable in the session. but this 367 // is not used as variables for the template. 368 // this is just ment, to define already variables while setting up 369 // the session and keep them in the session, until they get used by the template later. 370 // see RunTargets for the usage of the variables. 371 func (c *CmdExecutorImpl) setVariable(name string, value string) { 372 c.session.DefaultVariables[name] = value 373 } 374 375 func (c *CmdExecutorImpl) GetVariable(name string) string { 376 if val, have := c.session.DefaultVariables[name]; have { 377 return val 378 } 379 return "" 380 } 381 382 func (c *CmdExecutorImpl) GetVariables() map[string]string { 383 return c.session.DefaultVariables 384 } 385 386 func (c *CmdExecutorImpl) SetColor(onoff bool) { 387 behave := ctxout.GetBehavior() 388 behave.NoColored = onoff 389 ctxout.SetBehavior(behave) 390 } 391 392 func (c *CmdExecutorImpl) GetOuputHandler() (ctxout.StreamInterface, ctxout.PrintInterface) { 393 return c.session.OutPutHdnl, c.session.Printer 394 } 395 396 func (c *CmdExecutorImpl) GetWorkspaces() []string { 397 ws := configure.GetGlobalConfig().ListWorkSpaces() 398 sort.Strings(ws) 399 return ws 400 } 401 402 func (c *CmdExecutorImpl) FindWorkspaceInfoByTemplate(updateFn func(workspace string, cnt int, update bool, info configure.WorkspaceInfoV2)) (allCount int, updatedCount int) { 403 wsCount := 0 404 wsUpdated := 0 405 c.session.Log.Logger.Info("Start to find workspace info by template") 406 407 if currentPath, err := os.Getwd(); err != nil { 408 ctxout.CtxOut("Error while reading current directory", err) 409 systools.Exit(systools.ErrorBySystem) 410 } else { 411 haveUpdate := false 412 configure.GetGlobalConfig().ExecOnWorkSpaces(func(index string, cfg configure.ConfigurationV2) { 413 wsCount++ 414 for pathIndex, savedWorkspace := range cfg.Paths { 415 logFields := mimiclog.Fields{"path": savedWorkspace.Path, "project": savedWorkspace.Project, "role": savedWorkspace.Role} 416 c.session.Log.Logger.Debug("parsing workspace", logFields) 417 if err := os.Chdir(savedWorkspace.Path); err == nil && savedWorkspace.Project == "" && savedWorkspace.Role == "" { 418 template, found, err := c.session.TemplateHndl.Load() 419 if found && err == nil { 420 if template.Workspace.Project != "" && template.Workspace.Role != "" { 421 savedWorkspace.Project = template.Workspace.Project 422 savedWorkspace.Role = template.Workspace.Role 423 if template.Workspace.Version != "" { 424 savedWorkspace.Version = template.Workspace.Version 425 } 426 cfg.Paths[pathIndex] = savedWorkspace 427 logFields := mimiclog.Fields{"path": savedWorkspace.Path, "project": savedWorkspace.Project, "role": savedWorkspace.Role} 428 c.session.Log.Logger.Info("found template for workspace", logFields) 429 configure.GetGlobalConfig().UpdateCurrentConfig(cfg) 430 haveUpdate = true 431 wsUpdated++ 432 if updateFn != nil { 433 c.session.Log.Logger.Debug("exeute update function") 434 updateFn(index, wsCount, true, savedWorkspace) 435 } 436 } 437 } else { 438 if updateFn != nil { 439 updateFn(index, wsCount, false, savedWorkspace) 440 } 441 } 442 } 443 } 444 445 }) 446 if haveUpdate { 447 c.session.Log.Logger.Info("Update configuration") 448 if err := configure.GetGlobalConfig().SaveConfiguration(); err != nil { 449 c.session.Log.Logger.Error("Error while saving configuration", err) 450 ctxout.CtxOut("Error while saving configuration", err) 451 systools.Exit(systools.ErrorBySystem) 452 } 453 } 454 os.Chdir(currentPath) 455 } 456 ctxout.PrintLn("") 457 return wsCount, wsUpdated 458 } 459 460 func (c *CmdExecutorImpl) SetLogLevel(level string) error { 461 if level != "" { 462 lvl, err := logrus.ParseLevel(level) 463 if err != nil { 464 return err 465 } 466 c.session.Log.Logger.SetLevel(lvl) 467 468 } 469 return nil 470 } 471 472 func (c *CmdExecutorImpl) GetLogger() mimiclog.Logger { 473 return c.session.Log.Logger 474 } 475 476 func (c *CmdExecutorImpl) PrintPaths(plain bool, showFulltask bool) { 477 dir, err := os.Getwd() 478 logFields := mimiclog.Fields{"dir": dir, "err": err} 479 c.session.Log.Logger.Debug("print paths in workspace", logFields) 480 481 if err == nil { 482 if !plain { 483 c.Println(ctxout.ForeWhite, " current directory: ", ctxout.BoldTag, dir, ctxout.CleanTag) 484 c.Println(ctxout.ForeWhite, " current workspace: ", ctxout.BoldTag, configure.GetGlobalConfig().UsedV2Config.CurrentSet, ctxout.CleanTag) 485 } 486 pathColor := ctxout.ForeLightBlue 487 if !configure.GetGlobalConfig().PathMeightPartOfWs(dir) { 488 pathColor = ctxout.ForeLightMagenta 489 } 490 if !plain { 491 c.Println(" contains paths:") 492 } 493 //ctxout.Print(c.session.OutPutHdnl, "<table>") 494 walkErr := configure.GetGlobalConfig().PathWorker(func(index string, path string) { 495 template, exists, err := c.session.TemplateHndl.Load() 496 if err == nil { 497 add := ctxout.Dim + ctxout.ForeLightGrey 498 taskDrawMode := "ignore" 499 if showFulltask { 500 taskDrawMode = "wordwrap" 501 } 502 indexColor := ctxout.ForeLightBlue 503 indexStr := index 504 if path == configure.GetGlobalConfig().GetActivePath("") { 505 indexColor = ctxout.ForeLightCyan 506 indexStr = "> " + index 507 add = ctxout.ResetDim + ctxout.ForeLightGrey 508 } 509 510 if strings.Contains(dir, path) { 511 add = ctxout.ResetDim + ctxout.ForeCyan 512 } 513 if dir == path { 514 add = ctxout.ResetDim + ctxout.ForeGreen 515 } 516 outTasks := "" 517 if exists { 518 targets, _ := TemplateTargetsAsMap(template, true) 519 outTasks = strings.Join(targets, " ") 520 } else { 521 outTasks = ctxout.ForeDarkGrey + "no tasks" 522 } 523 c.Print( 524 "<row>", 525 indexColor, 526 "<tab size='5' fill=' ' draw='fixed' origin='2'>", 527 indexStr+" ", 528 "</tab>", 529 add, 530 "<tab size='65' draw='content' fill=' ' cut-add='///..' origin='1'>", 531 path, " ", 532 "</tab>", 533 ctxout.CleanTag, 534 "<tab size='29' fill=' ' prefix='<f:yellow>' suffix='</>' overflow='"+taskDrawMode+"' draw='extend' cut-add='<f:light-blue> ..<f:yellow>.' origin='2'>", 535 outTasks, 536 "</tab>", 537 "</row>", 538 ) 539 540 } else { 541 c.Print(ctxout.Message(" path: ", ctxout.Dim, " no ", ctxout.ForeYellow, index, " ", pathColor, path, ctxout.ForeRed, " error while loading template: ", err.Error())) 542 } 543 }, func(origin string) {}) 544 545 if walkErr != nil { 546 c.session.Log.Logger.Error("Error while walking through paths", err) 547 c.Println(ctxout.ForeRed, "Error while walking through paths: ", ctxout.CleanTag, walkErr.Error(), ctxout.CleanTag) 548 } 549 //c.Println("") 550 } 551 } 552 553 func (c *CmdExecutorImpl) GetCurrentWorkSpace() string { 554 return configure.GetGlobalConfig().UsedV2Config.CurrentSet 555 } 556 557 func (c *CmdExecutorImpl) PrintWorkspaces() { 558 configure.GetGlobalConfig().ExecOnWorkSpaces(func(index string, cfg configure.ConfigurationV2) { 559 if index == configure.GetGlobalConfig().UsedV2Config.CurrentSet { 560 c.Println("\t[ ", ctxout.BoldTag, index, ctxout.CleanTag, " ]") 561 } else { 562 c.Println("\t ", ctxout.ForeDarkGrey, index, ctxout.CleanTag) 563 } 564 }) 565 } 566 567 func TemplateTargetsAsMap(template configure.RunConfig, showInvTarget bool) ([]string, bool) { 568 var targets []string 569 found := false 570 571 if len(template.Task) > 0 { 572 for _, tasks := range template.Task { 573 if !systools.SliceContains(targets, tasks.ID) && (!tasks.Options.Invisible || showInvTarget) { 574 found = true 575 targets = append(targets, strings.TrimSpace(tasks.ID)) 576 } 577 } 578 } 579 sort.Strings(targets) 580 return targets, found 581 } 582 583 func (c *CmdExecutorImpl) Lint(showAll bool) error { 584 c.Println("linting...") 585 c.session.TemplateHndl.SetLinting(true) 586 if _, exists, err := c.session.TemplateHndl.Load(); err != nil { 587 c.Println(ctxout.ForeRed, "linting failed: ", ctxout.CleanTag, err.Error()) 588 return err 589 } else { 590 if exists { 591 c.Println("...loading config ", ctxout.ForeGreen, "ok", ctxout.CleanTag) 592 linter, lErr := c.session.TemplateHndl.GetLinter() 593 if lErr != nil { 594 return lErr 595 } 596 if linter.HasWarning() { 597 if showAll { 598 c.Println(" ") 599 c.Println(" you see all the unset fields, which are not set in the config") 600 c.Println(" these are shown as", ctxout.ForeDarkGrey, " MissingEntry: level[5]", ctxout.CleanTag) 601 c.Println(" this do not mean, that you have to set them, but it is a hint, that you can set them") 602 c.Println(" and how they are named") 603 c.Println(" ") 604 c.Println(" ") 605 // we just print all warnings once per keypath 606 alreadyPrinted := make(map[string]bool) 607 608 linter.GetIssue(yaclint.IssueLevelWarn, func(token *yaclint.MatchToken) { 609 //c.Println(ctxout.ForeYellow, "linting warning: ", ctxout.CleanTag, token.ToIssueString()) 610 propColor := ctxout.ForeYellow 611 if token.Added { 612 propColor = ctxout.ForeGreen 613 } 614 615 canPrint := true 616 if _, ok := alreadyPrinted[token.KeyPath]; ok { 617 canPrint = false 618 } 619 if canPrint { 620 valueStr := fmt.Sprintf(" %v ", token.Value) 621 c.Println( 622 ctxout.Row( 623 ctxout.TD(token.KeyPath, ctxout.Size(20), ctxout.Prop(ctxout.AttrPrefix, propColor)), 624 ctxout.TD(valueStr, ctxout.Size(20), ctxout.Prop(ctxout.AttrPrefix, ctxout.ForeYellow)), 625 ctxout.TD(token.ToIssueString(), ctxout.Size(40), ctxout.Prop(ctxout.AttrPrefix, ctxout.ForeDarkGrey)), 626 ctxout.TD(token.Type, ctxout.Size(20), ctxout.Prop(ctxout.AttrPrefix, ctxout.ForeLightCyan)), 627 ), 628 ) 629 alreadyPrinted[token.KeyPath] = true 630 } 631 632 }) 633 } else { 634 if linter.HasError() { 635 c.Println(ctxout.ForeRed, "...linting errors: ", ctxout.CleanTag, len(linter.Errors())) 636 c.Println(" ") 637 linter.GetIssue(yaclint.IssueLevelError, func(token *yaclint.MatchToken) { 638 c.Println( 639 ctxout.ForeRed, 640 "linting error: ", ctxout.ForeYellow, token.ToIssueString(), 641 ctxout.CleanTag, " check entry: ", 642 ctxout.ForeBlue, token.KeyPath, ctxout.CleanTag, ":", ctxout.ForeLightBlue, token.Value, ctxout.CleanTag) 643 }) 644 c.Println(" ") 645 } else { 646 c.Println(ctxout.ForeLightGreen, "...linter findings : ", ctxout.CleanTag, len(linter.Warnings())) 647 c.Println(" ") 648 c.Println(ctxout.ForeLightBlue, 649 "linter findings are usual and expected, because there are fields not set, the ", 650 ctxout.BoldTag, "could", ctxout.CleanTag, ctxout.ForeLightBlue, " be set, but it is not necessary.") 651 c.Println(ctxout.ForeLightBlue, "if you like to see all of this findings, use the flag show-issues") 652 c.Println(" ") 653 } 654 } 655 } 656 } else { 657 c.Println(ctxout.ForeRed, "linting failed: ", ctxout.CleanTag, "no template found") 658 return errors.New("no template found") 659 } 660 } 661 return nil 662 663 } 664 665 func (c *CmdExecutorImpl) InteractiveScreen() { 666 667 if !systools.IsStdOutTerminal() { 668 c.Print("no terminal detected") 669 systools.Exit(systools.ErrorInitApp) 670 return 671 } 672 shellRunner(c).runAsShell() 673 } 674 func (c *CmdExecutorImpl) ShellWithComands(cmds []string, timeout int) { 675 if err := shellRunner(c).runWithCmds(cmds, timeout); err != nil { 676 c.Println(ctxout.ForeRed, "error while running shell", ctxout.CleanTag, err.Error()) 677 } 678 } 679 680 // PrintShared print all shared paths in a simple list 681 func (c *CmdExecutorImpl) PrintShared() { 682 sharedRun := NewSharedHelper() 683 sharedDirs, _ := sharedRun.ListUseCases(false) 684 for _, sharedPath := range sharedDirs { 685 c.Println(sharedPath) 686 } 687 } 688 689 // displays the current version of contxt template as a yaml string 690 func (c *CmdExecutorImpl) PrintTemplate() { 691 if template, exists, err := c.session.TemplateHndl.Load(); err != nil { 692 c.Println(ctxout.ForeRed, "yaml export failed: ", ctxout.CleanTag, err.Error()) 693 c.Print(ctxout.ForeRed, "error while loading template: ", ctxout.CleanTag, err.Error()) 694 } else { 695 if exists { 696 c.Println("...loading config ", ctxout.ForeGreen, "ok", ctxout.CleanTag) 697 // map the template to a yaml string 698 if yamlStr, err := yaml.Marshal(template); err != nil { 699 c.Println(ctxout.ForeRed, "yaml export failed: ", ctxout.CleanTag, err.Error()) 700 } else { 701 c.Println(string(yamlStr)) 702 } 703 } else { 704 c.Println(ctxout.ForeRed, "yaml export failed: ", ctxout.CleanTag, "no template found") 705 } 706 } 707 } 708 709 // Set the given variable to the current session Default Variables. 710 // this will end up by using them as variables for the template, and are reset for any run. 711 // this is also an different Behavior to V1 where the variables are set for the wohle runtime, and if 712 // they changed by a task, they are changed for the whole runtime. 713 // this is not happen anymore, and the variables are just set for the current run. 714 func (c *CmdExecutorImpl) SetPreValue(name string, value string) { 715 c.session.DefaultVariables[name] = value 716 }