github.com/swaros/contxt/module/taskrun@v0.0.0-20240305083542-3dbd4436ac40/lint.go (about) 1 // Copyright (c) 2020 Thomas Ziegler <thomas.zglr@googlemail.com>. All rights reserved. 2 // 3 // Licensed under the MIT License 4 // 5 // 6 // Permission is hereby granted, free of charge, to any person obtaining a copy 7 // of this software and associated documentation files (the "Software"), to deal 8 // in the Software without restriction, including without limitation the rights 9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 // copies of the Software, and to permit persons to whom the Software is 11 // furnished to do so, subject to the following conditions: 12 // 13 // The above copyright notice and this permission notice shall be included in all 14 // copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 // SOFTWARE. 23 package taskrun 24 25 import ( 26 "bytes" 27 "errors" 28 "fmt" 29 "strconv" 30 "strings" 31 32 "github.com/kylelemons/godebug/pretty" 33 "github.com/swaros/contxt/module/configure" 34 "github.com/swaros/contxt/module/systools" 35 "github.com/swaros/manout" 36 "gopkg.in/yaml.v3" 37 ) 38 39 func compareContent(a, b interface{}, showBooth bool, size int, right int, noOut bool) bool { 40 diffOut := pretty.Compare(a, b) 41 diffParts := strings.Split(diffOut, "\n") 42 var errors []string 43 noDiff := true 44 i := 0 45 for _, line := range diffParts { 46 backColor := manout.BackWhite 47 if i%2 == 0 { 48 backColor = manout.BackLightGrey 49 } 50 leftDiff := strings.HasPrefix(line, "+") 51 rightDiff := strings.HasPrefix(line, "-") 52 53 if leftDiff && showBooth { 54 lft := getMaxLineString("", size) 55 line = getMaxLineString(line, right) 56 if !noOut { 57 fmt.Println(manout.MessageCln(backColor, manout.ForeYellow, manout.Dim, lft, line)) 58 } 59 i++ 60 } 61 if rightDiff { 62 errors = append(errors, "unsupported: "+line) 63 rgt := getMaxLineString(" unsupported element ", right) 64 line = getMaxLineString(line, size) 65 backColor := manout.BackYellow 66 if i%2 == 0 { 67 backColor = manout.BackLightYellow 68 } 69 i++ 70 if !noOut { 71 fmt.Println(manout.MessageCln(backColor, manout.BoldTag, manout.ForeDarkGrey, line, manout.ForeRed, manout.BoldTag, rgt)) 72 } 73 } 74 if !leftDiff && !rightDiff { 75 line = getMaxLineString(line, size+right) 76 i++ 77 if !noOut { 78 fmt.Println(manout.MessageCln(backColor, manout.ForeBlue, line)) 79 } 80 } 81 82 } 83 84 if len(errors) > 0 { 85 noDiff = false 86 manout.Error("found unsupported elements.", "count of errors:", len(errors)) 87 } 88 89 for _, errMsg := range errors { 90 fmt.Println(manout.MessageCln(manout.ForeYellow, errMsg)) 91 } 92 return noDiff 93 } 94 95 func trySupressDefaults(yamlString string) string { 96 ln := "\n" 97 outStr := "" 98 // first find all defauls values 99 lines := strings.Split(yamlString, ln) 100 for _, line := range lines { 101 checks := strings.Split(line, ": ") 102 if len(checks) == 2 { 103 // these should have all possible defaults as values. 104 if checks[1] != "[]" && checks[1] != "" && checks[1] != "\"\"" && checks[1] != "false" && checks[1] != "0" { 105 outStr = outStr + line + ln 106 } 107 } else { 108 outStr = outStr + line + ln 109 } 110 } 111 // next find empty nodes 112 lines = strings.Split(outStr, ln) 113 newOut := "" 114 max := len(lines) 115 for index, recheck := range lines { 116 if index > 0 && recheck != "" { 117 118 last := recheck[len(recheck)-1:] 119 if last == ":" && index < max { 120 nextStr := lines[index+1] 121 lastNext := nextStr[len(nextStr)-1:] 122 if lastNext != ":" { 123 newOut = newOut + recheck + ln 124 } 125 } else { 126 newOut = newOut + recheck + ln 127 } 128 129 } else { 130 newOut = newOut + recheck + ln 131 } 132 } 133 return newOut 134 } 135 136 // ShowAsYaml prints the generated source of the task file 137 func ShowAsYaml(fullparsed bool, trySupress bool, indent int) { 138 template, path, exists, terr := GetTemplate() 139 if terr != nil { 140 fmt.Println(manout.MessageCln(manout.ForeRed, "Error ", manout.CleanTag, terr.Error())) 141 systools.Exit(systools.ErrorTemplateReading) 142 return 143 } 144 var b bytes.Buffer 145 if exists { 146 if fullparsed { 147 yamlEncoder := yaml.NewEncoder(&b) 148 yamlEncoder.SetIndent(indent) 149 conerr := yamlEncoder.Encode(&template) 150 if conerr == nil { 151 if trySupress { 152 fmt.Println(trySupressDefaults(b.String())) 153 } else { 154 fmt.Println(b.String()) 155 } 156 157 } else { 158 manout.Error("error parsing template", conerr) 159 systools.Exit(systools.ErrorTemplateReading) 160 } 161 162 } else { 163 data, err := GetParsedTemplateSource(path) 164 if err != nil { 165 manout.Error("template loading", err) 166 systools.Exit(systools.ErrorTemplateReading) 167 } 168 fmt.Println(data) 169 } 170 } 171 } 172 173 func TestTemplate() error { 174 if template, _, exists, terr := GetTemplate(); terr != nil { 175 return terr 176 } else { 177 if !exists { 178 GetLogger().Debug("no template exists to check") 179 } else { 180 // check version 181 // if they is not matching, we die with an error 182 if !configure.CheckCurrentVersion(template.Version) { 183 return errors.New("unsupported version " + template.Version) 184 } 185 } 186 } 187 return nil 188 } 189 190 // LintOut prints the source code and the parsed content 191 // in a table view, and marks configured and not configured entries 192 // with dfferent colors 193 func LintOut(leftcnt, rightcnt int, all bool, noOut bool) bool { 194 template, path, exists, terr := GetTemplate() 195 if terr != nil { 196 manout.Error("ERROR", terr.Error()) 197 return false 198 } 199 if exists && rightcnt >= 0 && leftcnt >= 0 { 200 data, err := GetParsedTemplateSource(path) 201 if err != nil { 202 manout.Error("template loading", err) 203 return false 204 } 205 origMap, yerr := YAMLToMap(data) 206 if yerr == nil { 207 conversionres, conerr := yaml.Marshal(template) 208 if conerr == nil { 209 m := make(map[string]interface{}) 210 amlerr := yaml.Unmarshal(conversionres, &m) 211 if amlerr != nil { 212 fmt.Println(amlerr) 213 systools.Exit(1) 214 } 215 216 return compareContent(origMap, m, all, leftcnt, rightcnt, noOut) 217 } 218 219 } else { 220 prinfFile(path, leftcnt+rightcnt) 221 manout.Error("parsing error", yerr) 222 } 223 224 } else { 225 manout.Error("template not found ", path) 226 } 227 return false 228 } 229 230 func getMaxLineString(line string, length int) string { 231 if len(line) < length { 232 for i := len(line); i < length; i++ { 233 line = line + " " 234 } 235 } 236 if len(line) > length { 237 line = line[0:length] 238 } 239 return line 240 } 241 242 func prinfFile(filename string, size int) error { 243 data, err := GetParsedTemplateSource(filename) 244 if err != nil { 245 return err 246 } 247 248 backColor := manout.BackWhite 249 lines := strings.Split(data, "\n") 250 i := 0 251 for _, line := range lines { 252 i++ 253 prefix := getMaxLineString(strconv.Itoa(i), 5) 254 line = getMaxLineString(line, size) 255 fmt.Println(manout.MessageCln(manout.BackCyan, manout.ForeWhite, prefix, backColor, manout.ForeBlue, line)) 256 } 257 return nil 258 }