github.com/swaros/contxt/module/runner@v0.0.0-20240305083542-3dbd4436ac40/execouthndl.go (about) 1 // MIT License 2 // 3 // Copyright (c) 2020 Thomas Ziegler <thomas.zglr@googlemail.com>. All rights reserved. 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 23 // AINC-NOTE-0815 24 25 package runner 26 27 import ( 28 "fmt" 29 "strings" 30 "sync" 31 32 "github.com/swaros/contxt/module/ctxout" 33 "github.com/swaros/contxt/module/systools" 34 "github.com/swaros/contxt/module/tasks" 35 ) 36 37 var ( 38 // random color helper 39 randColors = NewRandColorStore() 40 // color for the state label 41 stateColorPreDef = ctxout.ToString(ctxout.NewMOWrap(), ctxout.ForeLightCyan+ctxout.BoldTag+ctxout.BackBlue) 42 processPreDef = ctxout.ToString(ctxout.NewMOWrap(), ctxout.ForeLightCyan+ctxout.BackBlack) 43 pidPreDef = ctxout.ToString(ctxout.NewMOWrap(), ctxout.ForeLightYellow+ctxout.BackBlack) 44 commentPreDef = ctxout.ToString(ctxout.NewMOWrap(), ctxout.ForeLightBlue+ctxout.BackBlack) 45 ) 46 47 // short for drawRowWithLabels("", "", label, labelColor, content, contentColor, info, infoColor) 48 func (c *CmdExecutorImpl) drawRow(label, labelColor, content, contentColor, info, infoColor string) { 49 c.drawRowWithLabels("", "", label, labelColor, content, contentColor, info, infoColor) 50 } 51 52 // draws a row with labels and colors 53 // leftLabel and rightLabel are optional 54 // labelColor is the color markup for the label 55 // contentColor is the color markup for the content 56 // infoColor is the color markup for the info 57 // label, content and info are the strings to print 58 func (c *CmdExecutorImpl) drawRowWithLabels(leftLabel, rightLabel, label, labelColor, content, contentColor, info, infoColor string) { 59 if leftLabel == "" { 60 leftLabel = "<sign runident> " 61 } 62 if rightLabel == "" { 63 rightLabel = "<sign stopident> " 64 } 65 leftLabel = ctxout.ToString(ctxout.NewMOWrap(), ctxout.ForeYellow+leftLabel+labelColor) 66 rightLabel = ctxout.ToString(ctxout.NewMOWrap(), ctxout.ForeYellow+rightLabel+contentColor) 67 c.Println( 68 ctxout.Row( 69 70 ctxout.TD( 71 label, 72 ctxout.Prop(ctxout.AttrSize, 10), 73 ctxout.Prop(ctxout.AttrOrigin, 2), 74 ctxout.Prop(ctxout.AttrPrefix, leftLabel), 75 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 76 //ctxout.Margin(4), // 4 spaces (run + space * 2 ) 77 ), 78 79 ctxout.TD( 80 content, 81 ctxout.Prop(ctxout.AttrSize, 85), 82 ctxout.Prop(ctxout.AttrPrefix, rightLabel), 83 ctxout.Prop(ctxout.AttrOverflow, "wordwrap"), 84 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 85 ), 86 ctxout.TD( 87 info, 88 ctxout.Prop(ctxout.AttrSize, 5), 89 ctxout.Prop(ctxout.AttrOrigin, 2), 90 ctxout.Prop(ctxout.AttrPrefix, infoColor), 91 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 92 ctxout.Margin(1), // 1 space for being sure 93 ), 94 ), 95 ) 96 } 97 98 // handles all the incomming messages from the tasks 99 // depending on the message type it will print the message. 100 // for this we parsing at the fist level the message type for each message. 101 102 func (c *CmdExecutorImpl) getOutHandler() func(msg ...interface{}) { 103 return func(msg ...interface{}) { 104 var m sync.Mutex 105 m.Lock() 106 // go through all messages 107 for _, m := range msg { 108 // hanlde the message type 109 switch tm := m.(type) { 110 111 case tasks.MsgPid: 112 targetColor, ok := randColors.GetOrSetRandomColor(tm.Target) 113 if !ok { 114 targetColor = RandColor{foreColor: "white", backColor: "black"} 115 } 116 c.Println( 117 ctxout.Row( 118 119 ctxout.TD( 120 "PROCESS PID "+ctxout.BaseSignScreen+" ", 121 ctxout.Prop(ctxout.AttrSize, 10), 122 ctxout.Right(), 123 ctxout.Prop(ctxout.AttrPrefix, processPreDef), 124 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 125 ), 126 127 ctxout.TD( 128 tm.Pid, 129 ctxout.Right(), 130 ctxout.Prop(ctxout.AttrSize, 5), 131 ctxout.Prop(ctxout.AttrPrefix, pidPreDef), 132 ctxout.Prop(ctxout.AttrOverflow, "ignore"), 133 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 134 ), 135 ctxout.TD( 136 " .... ", 137 ctxout.Prop(ctxout.AttrSize, 70), 138 ctxout.Prop(ctxout.AttrPrefix, commentPreDef), 139 ctxout.Prop(ctxout.AttrOverflow, "ignore"), 140 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 141 ), 142 ctxout.TD( 143 " "+tm.Target, 144 ctxout.Prop(ctxout.AttrSize, 14), 145 ctxout.Prop(ctxout.AttrPrefix, targetColor.ColorMarkup()), 146 ctxout.Prop(ctxout.AttrOverflow, "ignore"), 147 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 148 ), 149 ), 150 ) 151 152 case tasks.MsgCommand: 153 c.drawRow( 154 "executed command", 155 ctxout.ForeYellow+ctxout.BoldTag, 156 systools.AnyToStrNoTabs(tm), 157 ctxout.ForeDarkGrey, 158 ctxout.BaseSignScreen+" ", 159 ctxout.ForeYellow, 160 ) 161 162 // this is a special case where we need to 163 // check against the context of the message 164 case tasks.MsgTarget: 165 // we get the command for the target 166 // because we handle a target message, 167 // we look for the target color 168 targetColor, ok := randColors.GetOrSetRandomColor(tm.Target) 169 if !ok { 170 targetColor = RandColor{foreColor: "white", backColor: "black"} 171 } 172 switch tm.Context { 173 174 case "command": 175 c.drawRow( 176 tm.Target, 177 targetColor.ColorMarkup(), 178 "cmd: "+tm.Info, 179 ctxout.ForeDarkGrey, 180 ctxout.BaseSignScreen+" ", 181 ctxout.ForeYellow, 182 ) 183 184 case "needs_required": 185 c.drawRow( 186 tm.Target, 187 targetColor.ColorMarkup(), 188 "require: "+strings.Join(strings.Split(tm.Info, ","), " "), 189 ctxout.ForeDarkGrey, 190 ctxout.BaseSignDebug, 191 ctxout.ForeBlue, 192 ) 193 194 case "needs_execute": 195 c.drawRow( 196 tm.Target, 197 targetColor.ColorMarkup(), 198 "execute: "+tm.Info, 199 ctxout.ForeDarkGrey+ctxout.BoldTag+ctxout.Dim, 200 ctxout.BaseSignScreen+" ", 201 ctxout.ForeMagenta, 202 ) 203 204 case "needs_done": 205 c.drawRow( 206 tm.Target, 207 ctxout.ForeLightCyan, 208 tm.Info, 209 ctxout.ForeDarkGrey, 210 ctxout.BaseSignSuccess+ctxout.BaseSignSuccess+ctxout.BaseSignSuccess+" ", // three green success signs for all subneeds done 211 ctxout.ForeGreen, 212 ) 213 214 case "wait_next_done": 215 c.drawRow( 216 ctxout.BaseSignSuccess+" "+tm.Target, 217 ctxout.ForeGreen, 218 "DONE ..."+tm.Info, 219 ctxout.ForeDarkGrey, 220 ctxout.BaseSignSuccess+" ", 221 ctxout.ForeBlue, 222 ) 223 224 default: 225 c.Println( 226 ctxout.ForeCyan, 227 " [", 228 ctxout.ForeLightYellow, 229 tm.Target, 230 ctxout.ForeCyan, 231 "]", 232 ctxout.ForeLightCyan, 233 tm.Info, 234 ctxout.ForeCyan, 235 tm.Context, 236 ctxout.CleanTag, 237 ) 238 } 239 // end of switch tm.Context 240 case tasks.MsgReason, tasks.MsgType: 241 msg := fmt.Sprintf("%v", tm) 242 if msg == "target-async-group-created" { 243 c.drawRow( 244 "system", 245 ctxout.ForeLightBlue, 246 "running async group ...", 247 ctxout.ForeBlue, 248 ctxout.BaseSignInfo+" ", // three green success signs for all subneeds done 249 ctxout.ForeYellow, 250 ) 251 } else { 252 c.drawRow( 253 "info", 254 ctxout.ForeLightCyan, 255 fmt.Sprintf("%v", tm), 256 ctxout.ForeDarkGrey, 257 ctxout.BaseSignInfo+" ", // three green success signs for all subneeds done 258 ctxout.ForeBlue, 259 ) 260 } 261 case *tasks.MsgInfo: 262 c.Println( 263 ctxout.ForeLightMagenta, 264 "[info]", 265 ctxout.ForeMagenta, 266 tm, 267 ctxout.CleanTag, 268 ) 269 // something depending the process is changed. 270 // could be one of these: 271 // - started 272 // - stopped 273 // - aborted 274 // the comment contains more details. 275 // on started it contains the command that is executed 276 // on stopped it contains the exit codes (first the real code from the process, second the code from the command) 277 // on aborted it contains the reason why the process is aborted. this is a controlled abort. nothing from system side. 278 // this depends on a defined stopreason, so contxt itself is aborting the process. 279 case tasks.MsgProcess: 280 targetColor, ok := randColors.GetOrSetRandomColor(tm.Target) 281 if !ok { 282 targetColor = RandColor{foreColor: "white", backColor: "black"} 283 } 284 c.Println( 285 ctxout.Row( 286 287 ctxout.TD( 288 "PROCESS "+ctxout.BaseSignScreen+" ", 289 ctxout.Prop(ctxout.AttrSize, 10), 290 ctxout.Right(), 291 ctxout.Prop(ctxout.AttrPrefix, processPreDef), 292 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 293 ), 294 295 ctxout.TD( 296 " "+tm.StatusChange+" ", 297 ctxout.Prop(ctxout.AttrSize, 5), 298 ctxout.Right(), 299 ctxout.Prop(ctxout.AttrPrefix, stateColorPreDef), 300 ctxout.Prop(ctxout.AttrOverflow, "ignore"), 301 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 302 ), 303 ctxout.TD( 304 " "+tm.Comment, 305 ctxout.Prop(ctxout.AttrSize, 70), 306 ctxout.Prop(ctxout.AttrPrefix, commentPreDef), 307 ctxout.Prop(ctxout.AttrOverflow, "ignore"), 308 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 309 ), 310 311 ctxout.TD( 312 " "+tm.Target, 313 ctxout.Prop(ctxout.AttrSize, 14), 314 ctxout.Prop(ctxout.AttrPrefix, targetColor.ColorMarkup()), 315 ctxout.Prop(ctxout.AttrOverflow, "ignore"), 316 ctxout.Prop(ctxout.AttrSuffix, ctxout.CleanTag), 317 ), 318 ), 319 ) 320 case tasks.MsgError: 321 c.drawRow( 322 tm.Target, 323 ctxout.ForeLightYellow+ctxout.BoldTag+ctxout.BackRed, 324 tm.Err.Error(), 325 ctxout.ForeLightRed, 326 " "+ctxout.BaseSignError+" ", 327 //"error", 328 ctxout.ForeYellow+ctxout.BoldTag+ctxout.BackRed, 329 ) 330 331 case tasks.MsgInfo: 332 c.Println( 333 ctxout.ForeYellow, 334 "INFO", 335 ctxout.ForeLightYellow, 336 tm, 337 ctxout.CleanTag, 338 ) 339 case tasks.MsgExecOutput: 340 // getting forground, background and the sign color for the arrow char 341 fg, bg, sc := randColors.GetColorAsCtxMarkup(tm.Target) 342 c.drawRowWithLabels( 343 " ", 344 sc+"<sign runident> ", 345 tm.Target, 346 fg+bg, //ctxout.ForeWhite+ctxout.BackBlue, 347 systools.AnyToStrNoTabs(tm.Output), 348 ctxout.ResetCode, 349 ctxout.BaseSignScreen+" ", 350 ctxout.ForeLightBlue, 351 ) 352 353 default: 354 // uncomment for dispaying the type of the message that is not handled yet 355 356 /* 357 c.Println( 358 fmt.Sprintf("%T", tm), 359 ctxout.ForeLightYellow, 360 fmt.Sprintf("%v", msg), 361 ctxout.ForeWhite, 362 ctxout.BackBlack, 363 "not implemented yet", 364 ctxout.CleanTag, 365 ) 366 */ 367 368 } 369 } 370 371 m.Unlock() 372 } 373 }