github.com/swaros/contxt/module/taskrun@v0.0.0-20240305083542-3dbd4436ac40/placeholder.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  	"os"
    27  	"strings"
    28  	"sync"
    29  
    30  	"github.com/sirupsen/logrus"
    31  )
    32  
    33  var keyValue sync.Map
    34  
    35  // SetPH add key value pair
    36  func SetPH(key, value string) {
    37  	GetLogger().WithField(key, value).Trace("add/overwrite placeholder")
    38  	keyValue.Store(key, value)
    39  }
    40  
    41  func AppendToPH(key, value string) bool {
    42  	if val, ok := keyValue.Load(key); ok {
    43  		value = val.(string) + value
    44  		keyValue.Store(key, value)
    45  		return true
    46  	}
    47  	return false
    48  }
    49  
    50  func SetIfNotExists(key, value string) {
    51  	_, ok := keyValue.Load(key)
    52  	if !ok {
    53  		keyValue.Store(key, value)
    54  	}
    55  
    56  }
    57  
    58  // GetPH the content of the key as string. if exists.
    59  func GetPHExists(key string) (string, bool) {
    60  	result, ok := keyValue.Load(key)
    61  	if ok {
    62  		return result.(string), ok
    63  	}
    64  	return "", ok
    65  }
    66  
    67  // GetPH the content of the key. but at least a empty
    68  // string if not exists. so this is not usefull
    69  // to test if the PH was set.
    70  func GetPH(key string) string {
    71  	result, ok := keyValue.Load(key)
    72  	if ok {
    73  		GetLogger().WithField(key, result.(string)).Trace("deliver content from placeholder")
    74  		return result.(string)
    75  	}
    76  	GetLogger().WithField("key", key).Trace("returns empty string because key is not set")
    77  	return ""
    78  }
    79  
    80  func GetPlaceHoldersFnc(inspectFunc func(phKey string, phValue string)) {
    81  	keyValue.Range(func(key, value any) bool {
    82  		inspectFunc(key.(string), value.(string))
    83  		return true
    84  	})
    85  }
    86  
    87  // HandlePlaceHolder replaces all defined placeholders
    88  func HandlePlaceHolder(line string) string {
    89  	var scopeVars map[string]string = make(map[string]string)
    90  	for {
    91  		return handlePlaceHolder(line, scopeVars)
    92  	}
    93  }
    94  
    95  func HandlePlaceHolderWithScope(line string, scopeVars map[string]string) string {
    96  	for {
    97  		return handlePlaceHolder(line, scopeVars)
    98  	}
    99  }
   100  
   101  func handlePlaceHolder(line string, scopeVars map[string]string) string {
   102  
   103  	// this block is for logging at trace level only
   104  	if GetLogger().IsLevelEnabled(logrus.TraceLevel) {
   105  
   106  		for key, value := range scopeVars {
   107  			keyName := "${" + key + "}"
   108  			if strings.Contains(line, keyName) {
   109  				GetLogger().WithField("line", line).Trace("scope replace: source")
   110  				GetLogger().WithField(keyName, value).Trace("scope replace: variables")
   111  			}
   112  			line = strings.ReplaceAll(line, keyName, value)
   113  		}
   114  
   115  		keyValue.Range(func(key, value interface{}) bool {
   116  			keyName := "${" + key.(string) + "}"
   117  			if strings.Contains(line, keyName) {
   118  				GetLogger().WithField("line", line).Trace("replace: source")
   119  				GetLogger().WithField(keyName, value.(string)).Trace("replace: variables")
   120  			}
   121  			line = strings.ReplaceAll(line, keyName, value.(string))
   122  			line = handleMapVars(line)
   123  			return true
   124  		})
   125  	}
   126  
   127  	for key, value := range scopeVars {
   128  		keyName := "${" + key + "}"
   129  		line = strings.ReplaceAll(line, keyName, value)
   130  	}
   131  
   132  	keyValue.Range(func(key, value interface{}) bool {
   133  		keyName := "${" + key.(string) + "}"
   134  		line = strings.ReplaceAll(line, keyName, value.(string))
   135  		return true
   136  	})
   137  
   138  	line = handleMapVars(line)
   139  	for _, value := range os.Environ() {
   140  		pair := strings.SplitN(value, "=", 2)
   141  		if len(pair) == 2 {
   142  			key := pair[0]
   143  			val := pair[1]
   144  			keyName := "${" + key + "}"
   145  			line = strings.ReplaceAll(line, keyName, val)
   146  		}
   147  	}
   148  	return line
   149  }
   150  
   151  func handleMapVars(line string) string {
   152  	dataKeys := GetDataKeys()
   153  	if len(dataKeys) == 0 {
   154  		return line
   155  	}
   156  	GetLogger().WithField("key-count", len(dataKeys)).Trace("parsing keymap placeholder")
   157  	for _, keyname := range dataKeys {
   158  		lookup := "${" + keyname + ":"
   159  		if strings.Contains(line, lookup) {
   160  			start := strings.Index(line, lookup)
   161  			if start > -1 {
   162  				end := strings.Index(line[start:], "}")
   163  				if end > -1 {
   164  					pathLine := line[start+len(lookup) : start+end]
   165  					if pathLine != "" {
   166  						replace := lookup + pathLine + "}"
   167  						GetLogger().Debug("replace ", replace)
   168  						line = strings.ReplaceAll(line, replace, GetJSONPathValueString(keyname, pathLine))
   169  					}
   170  				} else {
   171  					GetLogger().WithField("key", lookup).Warn("error by getting end position of prefix")
   172  				}
   173  			} else {
   174  				GetLogger().WithField("key", lookup).Warn("error by getting start position of prefix")
   175  			}
   176  		}
   177  	}
   178  	return line
   179  }
   180  
   181  // ClearAll removes all entries
   182  func ClearAll() {
   183  	keyValue.Range(func(key, _ interface{}) bool {
   184  		keyValue.Delete(key)
   185  		return true
   186  	})
   187  	watchTaskList.Range(func(key, _ interface{}) bool {
   188  		keyValue.Delete(key)
   189  		return true
   190  	})
   191  }