patrickdappollonio / kubectl-slice

Split multiple Kubernetes files into smaller files with ease. Split multi-YAML files into individual files.
MIT License
296 stars 22 forks source link

Providing arguments to CLI on Windows PowerShell becomes difficult due to special characters #53

Closed lbrpsoftware closed 1 year ago

lbrpsoftware commented 2 years ago

Hi, thanks for this tool!

This is not really and Issue anymore because I've managed to get it to work perfectly👍, but maybe you can add this use-case to your examples folder?

  1. I downloaded metrics-server-0.6.1.yaml and first tried this command: kubectl-slice --template '{{.kind|lower}}/{{.metadata.name|dottodash}}.yaml' --input-file components.yaml --output-dir ./base Due to a colon in the name of a clusterrole-kind (system:aggregated-metrics-reader) I received an error.
  2. I tried adding a template function to replace ':' with '-' but got an error on: kubectl-slice --template '{{.kind|lower}}/{{.metadata.name|dottodash|replace ":" "-"}}.yaml' --input-file components.yaml --output-dir ./base
  3. So, the thing is: I'm on a windows machine and didn't get the replace function to work. So I've switched to a bash-shell. This works perfect, but maybe could be worth mentioning? Maybe also worth mentioning how to pipe multiple functions?

Cheers!

patrickdappollonio commented 2 years ago

Hey @lbrpsoftware!

Appreciate the report! I think this issue might be due to how the terminal you were using was parsing the contents. In a Mac/Linux terminal, the single quotes mean a raw string.

If I remember correctly, Windows does not support single quotes, and instead, you must escape the quotes yourself. This isn't really a limitation of kubectl-slice but instead of Windows' own terminal.

I tried by running the following command against this file:

X:\> type code.yaml
foo: true
---
bar: false
---
baz: true
X:\> kubectl-slice.exe -t "{{ printf \"%v\" . | replace \"[\" \"-\" | replace \"]\" \"\" | replace \":\" \"-\" }}" -f code.yaml --stdout
# File: map-foo-true (11 bytes)
foo: true

---

# File: map-bar-false (12 bytes)
bar: false

---

# File: map-baz-true (11 bytes)
baz: true

3 files parsed to stdout.

Granted, it's quite the ugly command, and if you were to replace them for single quotes inside the -t parameter, it will fail because in Go single quotes are meant for byte characters (aka a single character instead of a string). You get this error instead:

error: unable to render file name for YAML file number 0: expected string; found '['

Which shows it's expecting a string, since the replace function is meant to replace strings of 1+ characters.

While I won't be able to cover every specific case scenario for Windows (we've had our fair share of issues, see #41 for example), this falls more into the "know your terminal" situation. I will document some of the caveats like single vs double quotes, or your recommendation to move to a different terminal.

One thing I do want to do though is allowing setting some of these parameters as environment variables. That way, they're not affected by parsing/handling of the terminal prompt. However, setting them on a per-execution basis won't solve the issue in your case.

Finally, one last cool options I'm looking to explore too is allowing passing the template name via a file, rather than from the command prompt itself. This so people can commit the template to their source control and track it. This will solve your issue since you can write in the file anything you want to, even if you need some sort of multiline file for better reading (although the final filename will have line breaks removed).

I would love if you can provide feedback on these ideas since you're a user!

lbrpsoftware commented 2 years ago

Thanks for those pointer! Lets combine some knowledge then 🤓 because I do know my terminal a little 😁

PowerShell does handle a grave accent ` inside string literals, so modifying the command as follows will work on Windows:

 kubectl-slice --template '{{.kind|lower}}/{{.metadata.name|dottodash|replace `:` `-`}}.yaml' --input-file deploy.yaml --output-dir ./_base

Regarding a new --templatefile variable, maybe some quick reflections:

lbrpsoftware commented 2 years ago

My mistake closing it 🙄

Another thing ... it could be handy to not only use templates to split a manifest into files, but something like an --output-template for generating the report would be nice. I often need to manually edit the output to put into terraform like so:

  configuration = {
    dev = {
      namespace = "default"
      resources = [
        "${path.module}/kind/deployment.yaml",
        "${path.module}/kind/service.yaml",
      ]
    }

It could be something like this:

--output-template '"${path.module}/{{outfile}}",'

I'm using this and append the rest:

(Get-ChildItem -File -Name -Include *.yaml -Recurse).replace("\", "/") | %{"""`${path.module}$_,"""}

Cheers.

patrickdappollonio commented 1 year ago

Hey @lbrpsoftware!

Apologies for the long delay, doing my rounds today I noticed this was left in the void. I'll make note so it doesn't happen again.

So the original issue was about "improving documentation". Based on the comments above, I think the current documentation explains enough for the CLI use case. Using it in, say zsh, powershell or any other shell interpreter really is up to the reader. We couldn't possibly cover how you should be able to pass, or not, special characters on every possible terminal out there. What's best for us today is that you know what the format is, how it's processed and the likes, and the expectation is that you will cover the remaining pieces yourself tailored to your terminal.

For the "configuration" file, I'll open a new issue, one that more accurately reflects the state of what we're trying to achieve with the config file itself.

Since from a documentation perspective there's not much else to add (unless you disagree, I'm more than happy to take a pull request with your suggestions!) I'll close the issue and link here from the new issue.