Get {{.Host}} inside a range loop - Caddy server browse template - go

So I can use {{.Host}} just fine in the template file, but once inside a {{range .Items}} loop it doesn't work since it's trying to get the .Host from the .Items (array?)thing..
I get this as an error
template: listing:41:46: executing "listing" at <.Host>: can't evaluate field Host in type browse.FileInfo
I've never used Go before, I've tried reading the text template documentation page but it's all rather confusing.

ooooh, nevermind guys, I knew it was a simple fix.
{{$.Host}}
Just add the $, then you'll be using the global context again, instead of the context inside of the range loop.
Source, thanks HUGO for the clear documentation.

{{range}} changes the pipeline (the dot, .) to the current Items. You can use {{$.Host}} which will refer to the "top-level" Host.
{{$.Host}}
golang template.

Related

Question about weird behavior referencing a YAML pipeline resource using a variable for the pipeline resource name

I am experiencing weird behavior with YAML variables, parameters, and Azure pipeline resource references. The following shows the original implementation that works compared to my new implementation with a single line change that fails.
Working Implementation
Template A (makes a call to template B):
- template: Templates\TemplateB.yml
serviceBuildResourceName: resourceName
Template B (uses serviceBuildResourceName param to get pipeline run information):
$projectId = '$(resources.pipeline.${{ parameters.serviceBuildResourceName }}.projectID)'
$pipelineId ='$(resources.pipeline.${{ parameters.serviceBuildResourceName }}.PipelineID)'
Template B goes on to use the values in $projectId and $pipelineId (along with other values not listed here since it is irrelevant) to successfully retrieve information about the a pipeline run from the specific pipeline resource, serviceBuildResourceName. Note that all pipeline resources are correctly defined at the beginning yaml file for the pipeline. In this implementation above, everything works perfectly.
Failing Implementation
Template A (makes a call to template B):
- template: Templates\TemplateB.yml
serviceBuildResourceName: $(ServiceBuildResourceName)
Template B (uses serviceBuildResourceName param to get pipeline run information):
$projectId = '$(resources.pipeline.${{ parameters.serviceBuildResourceName }}.projectID)'
$pipelineId ='$(resources.pipeline.${{ parameters.serviceBuildResourceName }}.PipelineID)'
Note that the only difference is the following: instead of passing the hard-coded string into the serviceBuildResourceName parameter, I pass in a variable, which has the same value as before, resourceName. The variable is defined in an earlier template as such:
- name: ServiceBuildResourceName
value: resourceName
I feel it should still work the same, but I know get the following error in my pipeline run:
WARNING: 2023-02-12 15:52:29.5071 Response body: {"$id":"1","innerException":null,"message":"The value is not an integer.
$(resources.pipeline.resourceName.PipelineID)
I know that the variable is being correctly populated since the error message above contains "resourceName" in resources.pipeline.resourceName.PipelineID, as it should.
However, for reasons unknown to me, it now throughs an error. It seems like it doesn't recognize the pipeline resource, and instead recognizes it as a string.
Any help or insight here would be greatly appreciated, thanks!
As far as I can tell, this is because of how predefined variables work in YAML. Since resources.pipeline... is a predefined variable, it gets resolved at compile time. Thus, you can't use run-time defined variables like I am doing. Instead of resolving it as a predefined variable, it will get resolved to be a string at runtime.

How to access nested values in Cypress.json

Cannot access nested values in Cypress.json file.
I have just started learning Cypress and trying to organise some variables into the Cypress.json file.
The usual dot and bracket notation do not work because the key is already in single/double quotes, so I think Cypress sees it as a complete string eg. (Cypress.env('login.username')).
This is my simple Cypress.json file
{
"env":{
"login":{
"username":"Joe"
}
}
}
How can I access the name Joe?
Try this, it will return the username.
Cypress.env('login').username // returns "Joe"
Read more about Environment Variables
To expand upon Yevhen's answer.
Nested environment variables only work when placed inside a separate cypress.env.json file in the root of your project, next to your cypress.json file.
This can be seen under option #2 on the environment variables link that Yevhen already provided.
It isn't explicitly documented where this cypress.env.json file needs to be placed, I just wanted to share this information after having to figure it out for myself.

Golang templates won't load

I started to write a Gin application and my project tree looks like
-assets
--css
---{bootstrap}
-templates
--layouts
---footer.html
---head.html
---header.html
--book.html
-main.go
In main.go I load templates and there is no error
router.LoadHTMLGlob("./templates/layouts/*.html")
I define templates
{{ define "head" }}
<head>
//Head
</head>
{{ end }}
And I nest them
{{ define "header" }}
{{ template "head.html" . }}
//HTML
{{ end }}
But when I try to use them, I get empty output
{{ template "header" . }}
<h1>{{ .Title}}</h1>
<h3>{{ .Author.Fullname}}</h3>
[Edit] Function that executes the template:
func getBook(c *gin.Context) {
//DB stuff
var book models.Book
t, err := template.ParseFiles("templates/book.html")
if err != nil {
log.Println(err)
}
t.Execute(c.Writer, book)
}
Full-code can be found on github
router.LoadHTMLGlob and template.ParseFiles are two separate approaches to deal with templates. The template returned by ParseFiles has no knowledge of the templates loaded by LoadHTMLGlob. Once you decide to use LoadHTMLGlob you should then use c.HTML to render your templates. And the name argument to this c.HTML method would be either the name specified in a {{define "name"}} action or the base name of the template file (including the extention I believe).
So in your case you should probably do something like this:
c.HTML(http.StatusOK, "book.html", book)
More examples can be found here: https://gin-gonic.com/docs/examples/html-rendering/
Keep in mind that LoadHTMLGlob relies on template.ParseGlob which states:
When parsing multiple files with the same name in different
directories, the last one mentioned will be the one that results.
That means that if you want all of your templates to be accessible through c.HTML you need to make sure that they either have unique base names or they need to contain the {{ define "name"}} action.
Moving from the default templating system where 'everything simply worked' to Gin is a bit confusing, namely, there seem to be some naming restrictions when using files for templates. I have no idea if this is the case, but, in my setup, I had to make sure that:
The name of the template (the define keyword) needs to be the filename — at least when that's the only define in the template (I haven't tested with multiple defines) — i.e. if you're using ./templates/book.html as a template, you need to have {{ define "book.html" }} at the top of that file (this is true for templates included in other templates; I didn't experiment with blocks or other more esoteric ways to jinx templates together)
Similarly, when calling c.HTML(http.StatusOK, "book.html", book), you have to put the full name of the file containing that template (as shown!)
In other words, although the manual says otherwise, and #mkopriva confirms what the manual says, I have had a different experience: it was only I started matching the filename with the define and the c.HTML() call that I stopped getting blank pages...
Also, while running from the console (in debug mode), it was clear that my programme was 'finding' far more templates than it should — namely, almost every template was duplicated (one copy for the filename, another copy for the define, etc.). This confused not only me but the application itself...

Setting variable from file content in dockerize golang template

I want to use the jsonQuery syntax in dockerize to parse traefik's acme.json and emit cert/key files for TLS settings in another service.
jsonQuery accepts a string, which the example gives as an environment variable {{ .Env.myJson }}
How might I get the string contents of a file:
{{with $myJsonContent := <insert magic here> }}
# extract key to file
{{end}}
Go's text/template doesn't natively support that. It looks like the dockerize tool provides a couple of extension functions but none of them allow this either.
(The nearest thing I can think of is that kubernetes-helm supports reading a file from a Helm chart, but that's implemented at the Go level by injecting a special accessor object that can provides the file-access API to template code, and it's intentionally limited to files physically located within the Helm chart directory.)
I can't see any way to add a function to the template, as dockerize doesn't expose the addition of functions to the template prior to parsing. So you'll either have to (1) get the contents of acme.json into an environment variable, or (2) modify dockerize to include a jsonFileQuery function in the templates.
Add the contents of acme.json to the environment variables before running dockerize - then access as in the example. This could be done with a small go program, added to the container and run via CMD prior to the CMD dockerize
Fork dockerize and change jsonQuery: Fork dockerize and change line 83 of template.go:
from: parser, err := gojq.NewStringQuery(jsonObj)
to: parser, err := gojq.NewFileQuery(jsonObj)
Then use:
{{with $myJsonContent := jsonQuery "/opt/traefik/acme.json" "toplevelobject" }}
# extract key to file
{{end}}
gojq.NewStringQuery() is a function behind the jsonQuery template function. The gojq.NewFileQuery() version has the same signature as the StringQuery but reads the file at the path in the input string instead of using the input string as json.
OR
Merge new jsonFileQuery template function into dockerize: submit an issue to dockerize to add jsonFileQuery to the template functions. Seems like it could be set up the same as jsonQuery but with the small difference above. In template.go, add the jsonFileQuery function and assign it to jsonFileQuery in the template.FuncMap{} within generateFile().

Variable autoescape in Smarty templates

I have recently found out that Smarty, differently from Django template engine, does not escape variables automatically and I need to put |escape next to most of the variables in my templates.
Following the docs, http://www.smarty.net/docsv2/en/variable.default.modifiers.tpl I need to set default modifiers, needn't I?
So, here's my code:
$smarty = new Smarty();
$smarty->default_modifiers = array('escape:"htmlall"');
... and still variables ARE NOT escaped until I add |escape next to them.
What am I doing wrong?
If you are on Smarty 3, try this:
$smarty = new Smarty();
$smarty->loadFilter(Smarty::FILTER_VARIABLE, "htmlentities");
Tadà!
Update: Smarty::FILTER_VARIABLE is undocumented as of 28/11/2014. Use $smarty->escape_html = true if you want to stick to offical docs.
It appears that this feature was removed from Smarty v3, and docs are outdated. See:
http://www.smarty.net/forums/viewtopic.php?p=62207
I'd recommend a workaround - which is template level. Either create a new style v3 function to take care of filtration, or, do a simple include.
Include method
Put this in a clean.tpl file:
{$text|escape:htmlall}
Then invoke as {include file=clean.tpl text=$myvariabletofilter}
Function method
The new functions in Smarty could also take care of that:
{function clean}
{$text|escape:htmlall}
{/function}
And invoke as {clean text=$myvariabletofilter}
As always, make sure that these things get trimmed right and don't insert unncessary spaces.

Resources