-
-
Notifications
You must be signed in to change notification settings - Fork 603
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
yq write strips completely blank lines from the output #515
Comments
Same story, sorry but this issue looks more like a bug nether then enhancement. |
Any update on this, this is a really nice feature. |
Any update on this ? It's getting difficult when it comes to readability |
This is an effect of the underlying yaml parser, an issue was raised there go-yaml/yaml#627 - the owner said
|
I've been dealing with this issue for a couple of days when updating very large YAML files and found a workaround using doc:
version: 1.0.0
name: numbers & letters
numbers:
- 1
letters:
- a we call this file yq e '.doc.version = "1.0.1"' a.yaml > a-updated.yaml as expected, command above stripped all blank lines so doc:
version: 1.0.1
name: numbers & letters
numbers:
- 1
letters:
- a at this point, the first step to get the blank lines back is to create a diff file that ignores blank lines changes: diff -U0 -w -b --ignore-blank-lines a.yaml a-updated.yaml > a.diff
--- a.yaml 2021-04-30 15:28:38.000000000 -0500
+++ a-updated.yaml 2021-04-30 15:18:53.000000000 -0500
@@ -2 +2 @@
- version: 1.0.0
+ version: 1.0.1 then final step is to patch original file with the diff: patch a.yaml < a.diff after that, the original file looks like: doc:
version: 1.0.1
name: numbers & letters
numbers:
- 1
letters:
- a the issue comes when the updated line is right before a blank line. For example, let's add an element to one of the arrays: yq e '.numbers += 2' a.yaml > a-updated.yaml the updated file is now: doc:
version: 1.0.1
name: numbers & letters
numbers:
- 1
- 2
letters:
- a if we generate the diff file as before we'll get the following: --- a.yaml 2021-04-30 15:30:22.000000000 -0500
+++ a-updated.yaml 2021-04-30 15:35:26.000000000 -0500
@@ -7 +6 @@
-
+ - 2 and patching the original file with diff above results in: doc:
version: 1.0.1
name: numbers & letters
numbers:
- 1
- 2
letters:
- a notice how the blank line after the new element in This is not ideal in any means but in my case it has helped a lot since my files are big and with lots of blank lines. I'm sharing this in case someone else can find it useful too. |
Thanks ! I use @arcesino approach for this 1 liner.
|
Thanks for the idea with diff & patch @arcesino . I my case the removal of blanks introduced by And found a solution. Approach is following: i remove blanks from the original yaml and create a diff between that and my altered yaml. Here an example: Starting point is my original yaml where the value of key "secrets.TEST" should be updated
Step 1: updating the value & creating a copy
Step 2: removing blanks from the original
Step 3: creating a patch
the patch contains then only the value diffs:
Step 4: apply the patch to the original
Here a screenshot: Utils used:
OS: debian 11 |
good idea! I turned that in a fish and bash functions in this Gist: #fish
function yqblank;
yq eval "$argv[1]" "$argv[2]" | diff -B "$argv[2]" - | patch "$argv[2]" -o -
end
#bash
yqblank() {
yq eval $1 $2 | diff -B $2 - | patch $2 -o -
} this makes it possible to use yq without changing (most) of the blank lines. usage as follows:
|
@clementnuss I think #bash
yqblank() {
yq eval $1 $2 | diff -B $2 - | patch $2 -
} |
@raQai, thank you! Just that the arguments have to be quoted properly, also #bash
yqblank() {
yq "$1" "$2" | diff -B "$2" - | patch "$2" -
} |
Oh yeah, I forgot about the quote part 😅 edit: source:
fruits: [
Apple,
Banana,
Calamansi,
]
becomes:
fruits: [Apple, Banana, Calamansi,] source:
fruits: [
Apple, # comment 1
Banana, # comment 2
Calamansi, # comment 3
]
becomes:
fruits: [
Apple, # comment 1
Banana, # comment 2
Calamansi, # comment 3
] (I did not verify this on my current machine but that was roughly the result) edit2: Long story short: We still use Something along those lines should work $ sed -i "$(yq '.info.version | line' "$file")s/$old_val/$new_val/" "$file" This also returns the correct line if the value of info:
version: 1.x.x # line 2 info:
version:
1.x.x # line 3 |
I'm hit by this too. No fix, only workarounds? |
Unfortunately this only works for changes in already existed values. The patch would be with offsetted blank lines if try to add lines to the yaml. I've already tested that and it does not work as expected for additions: Search for: So, only the diff-versus-edited-yaml instead of diff-versus-unblanked-yaml looks reliable as @arcesino showed. |
This one has one disadvantage, it does remove comments. And there is no any way to completely correctly retain comments outside the yq utility, because the comments format depends on yaml syntax. |
I've new implementation of bash scripts which is better of all above. Implementation: https://github.com/andry81-devops/gh-workflow/blob/master/bash/github/init-yq-workflow.sh # Usage example:
#
>yq_edit '<prefix-name>' 'edit' "<input-yaml>" "$TEMP_DIR/<output-yaml-edited>" \
<list-of-yq-eval-strings> && \
yq_diff "$TEMP_DIR/<output-yaml-edited>" "<input-yaml>" "$TEMP_DIR/<output-diff-edited>" && \
yq_restore_edited_uniform_diff "$TEMP_DIR/<output-diff-edited>" "$TEMP_DIR/<output-diff-edited-restored>" && \
yq_patch "$TEMP_DIR/<output-yaml-edited>" "$TEMP_DIR/<output-diff-edited-restored>" "$TEMP_DIR/<output-yaml-edited-restored>" "<output-yaml>"
#
# , where:
#
# <input-yaml> - input yaml file path
# <output-yaml> - output yaml file path
#
# <output-yaml-edited> - output file name of edited yaml
# <output-diff-edited> - output file name of difference file generated from edited yaml
# <output-diff-edited-restored> - output file name of restored difference file generated from original difference file
# <output-yaml-edited-restored> - output file name of restored yaml file stored as intermediate temporary file Example with # This file is automatically generated
#
content-index:
timestamp: 1970-01-01T00:00:00Z
entries:
- dirs:
- dir: dir-1/dir-2
files:
- file: file-1.dat
md5-hash:
timestamp: 1970-01-01T00:00:00Z
- file: file-2.dat
md5-hash:
timestamp:
- file: file-3.dat
md5-hash:
timestamp:
- dir: dir-1/dir-2/dir-3
files:
- file: file-1.dat
md5-hash:
timestamp:
- file: file-2.dat
md5-hash:
timestamp: export GH_WORKFLOW_ROOT='<path-to-gh-workflow-root>' # https://github.com/andry81-devops/gh-workflow
source "$GH_WORKFLOW_ROOT/bash/github/init-yq-workflow.sh"
[[ -d "./temp" ]] || mkdir "./temp"
export TEMP_DIR="./temp"
yq_edit 'content-index' 'edit' "test.yml" "$TEMP_DIR/test-edited.yml" \
".\"content-index\".timestamp=\"2022-01-01T00:00:00Z\"" && \
yq_diff "$TEMP_DIR/test-edited.yml" "test.yml" "$TEMP_DIR/test-edited.diff" && \
yq_restore_edited_uniform_diff "$TEMP_DIR/test-edited.diff" "$TEMP_DIR/test-edited-restored.diff" && \
yq_patch "$TEMP_DIR/test-edited.yml" "$TEMP_DIR/test-edited-restored.diff" "$TEMP_DIR/test.yml" "test-patched.yml" || exit $? PROs:
CONs:
Related issues: |
Here is another possible workaround. We basically pre-format the file once with no content changes. Then make the content change. Then compare the pre-formatted and the content-changed versions to get a patch. Then apply the patch to the original file. I've only tried it for simple cases like patching the version in a helm values file. It seems to work well, and also seems to preserve comments. $ yq --version
yq version 4.9.8
$ # The original file
$ cat values.yaml
# The app name
name: "some-app"
image:
# The image tag
tag: "1.2.0"
# Some other comments...
# ...
$ # Don't change anything; just let yq do its default formatting
$ yq eval --exit-status '.' values.yaml | tee out1.yaml
# The app name
name: "some-app"
image:
# The image tag
tag: "1.2.0"
# Some other comments...
# ...
$ # Now make the actual change
$ yq eval --exit-status '.image.tag = "1.3.0"' values.yaml | tee out2.yaml
# The app name
name: "some-app"
image:
# The image tag
tag: "1.3.0"
# Some other comments...
# ...
$ # Diff the two stripped files to get a minimal diff with no special flags.
$ diff out1.yaml out2.yaml | tee out.patch
5c5
< tag: "1.2.0"
---
> tag: "1.3.0"
$ # Apply the patch to the original file, which was unchanged so far.
$ patch values.yaml < out.patch
patching file values.yaml
$ # Inspect the final file.
$ # Note the version was changed and everything else remained the same.
$ cat values.yaml
# The app name
name: "some-app"
image:
# The image tag
tag: "1.3.0"
# Some other comments...
# ... |
It has the same issues with comments and blanks remove. |
I think it works fine with comments. I updated my original post to include comments. LMK if you still see some issue. Maybe I'm overlooking something subtle. |
The diff shows position in already edited file:
Better to use uniform diff to see: > diff -u out1.yaml out2.yaml | tee out-uniform.patch
--- out1.yaml
+++ out2.yaml
@@ -1,3 +1,3 @@
name: some-app
image:
- tag: "1.2.0"
+ tag: "1.3.0" To exploit: values.yaml # The app name
name: "some-app"
image1:
# The image1 tag
tag: "1.2.0"
image2:
# The image2 tag
tag: "1.2.0" > yq -y '.image2.tag = "1.3.0"' values.yaml | tee out2.yaml
name: some-app
image1:
tag: "1.2.0"
image2:
tag: "1.3.0" > patch values.yaml -i out.patch out.patch 5c5
< tag: "1.2.0"
---
> tag: "1.3.0" values.yaml # The app name
name: "some-app"
image1:
# The image1 tag
tag: "1.3.0"
image2:
# The image2 tag
tag: "1.2.0" This additionally shows why the non uniform diff even without default options is less stable for patching. |
There will be any fixes to this issue in the future? |
It sounds like there's no workaround? |
prettier is the only yaml formatter I have tried that preserves blank lines correctly Considering I switched to |
There are several workarounds mentioned throughout the thread. Look for 👍 |
Micro-improvement to the workaround that leaves blank lines alone: I have some YAML files with comments preceded by two blanks, like the SemVer comments left by dependabot when you reference an action by its full commit hash, like uses: rymndhng/release-on-push-action@aebba2bbce07a9474bf95e8710e5ee8a9e922fe2 # v0.25.0 These blanks also get squashed to just one when you use yq to modify something else. To prevent, diff has an option yq "$1" "$2" | diff -Bw "$2" - | patch "$2" - |
Hello @bewuethr, I have thoroughly tested the workaround you provided, and it demonstrates excellent functionality, effectively addressing the initial issue. However, I have observed that it does not preserve the newline character that exists after the line modification.
|
That's right, a blank line after a modified line gets removed! I haven't found a better workaround other than moving lines to modify away from a blank line, I'm afraid. |
There is an alternate underlying yaml library that claims to encode whitespace. This is a competitor to the library currently used in yq. |
This is dumb, but I'm just going to say it. If are are only using whitespace to separate sections and your sections each start with a comment like awk '/^---$/{flag=!flag; print; next} flag && /^#/{print ""} {print}' |
Looks like when yq is run on any yaml file it strip the blank like from the output so as part of parse mikefarah/yq#515 we use to parse this file to update the go version using the script in next commit so this commit just to make sure the formatting is right when it parsed with `yq` It is generated using `yq --inplace .github/workflows/windows-artifacts.yml`
Looks like when yq is run on any yaml file it strip the blank like from the output so as part of parse mikefarah/yq#515 we use to parse this file to update the go version using the script in next commit so this commit just to make sure the formatting is right when it parsed with `yq` It is generated using `yq --inplace .github/workflows/windows-artifacts.yml`
This approach does not work if the diff ONLY appends new lines, e.g., if doing something like:
...the reason is because the line numbers will be completely wrong since the diff was computed using two files without the original blank lines. It will apply but to the wrong location in the original, which is very wrong. You could try to fix this approach by getting Given this limitation, @arcesino 's approach was the only one that actually worked correctly. |
Just as a suggestion, one could pre-process insert a tag in to maintain the whitespace or empty lines into a separate place that uses a tag-parser to identify the ordering and where those tag occurances happen in the hierarchy. Then as a post processing step re-insert the whitespace in the right location after processing the original file. This may work better than a diff since it would identify it before the underlying output is created and may handle the cases where the previous diff method may fall short. |
Hi, I have tried all the suggested methods, but nothing seems to work correctly. Blank lines, comments, anchor and alias references in yaml files are all destroyed. Will this support be available in the future? I saw go-yaml#627 closed. |
Can you give an example what does not work with this method: #515 (comment) |
Sorry, that should be my problem, The yq version I used is 3.x. After updating to the latest version 4.x, the options of yq itself can already retain the format, except that the blank lines are deleted, which needs to be combined with diff and patch. |
Is your feature request related to a problem? Please describe.
when run through
yq w - foo.baz 3
produces
Describe the solution you'd like
Keep my extra blank line (it's better for readability / produces less of a diff)
The text was updated successfully, but these errors were encountered: