google / jsonnet

Jsonnet - The data templating language
http://jsonnet.org
Apache License 2.0
6.97k stars 440 forks source link

Thoughts on folded text block? #915

Open drewgingerich opened 3 years ago

drewgingerich commented 3 years ago

This is cross-posted at google/go-jsonnet.

YAML has folded-style multi-line strings, which means that new-lines are replaced with spaces to end up with a single-line string. I find this convenient for splitting long shell commands over multiple lines for readability. Does this seem like something potentially good to implement?

I know that jsonnet has the ||| text block but this does not replace newlines, behaving like a "literal" instead of "folded" YAML multi-line string. Syntax for a "folded" text block in jsonnet could be an extension of the text block syntax: e.g. |||>.

For example and context, I'm looking at using jsonnet to produce YAML Gitlab CI config files. By hand a simplified version looks like this:

build:
  stage: build
  only:
    - main
  image: my.kaniko.image
  script:
    - init-kaniko
    - >-
      /kaniko/executor
      --context .
      --dockerfile Dockerfile
      --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      --destination $CI_REGISTRY_IMAGE:latest

To reproduce this in jsonnet I need to use a function to replace the newlines:

local folded_text_block(text_block) = std.strReplace(text_block, '\n', ' ');

{
  build: {
    stage: 'build',
    only: ['main'],
    image: 'my.kaniko.image',
    script: [
      'init-kaniko',
      folded_text_block(
        |||
          /kaniko/executor
          --context .
          --dockerfile Dockerfile
          --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
          --destination $CI_REGISTRY_IMAGE:latest
        |||
      ),
    ],
  },
}

Whereas with a builtin folded text block (using my made-up syntax from above) I could do:

{
  build: {
    stage: 'build',
    only: ['main'],
    image: 'my.kaniko.image',
    script: [
      'init-kaniko',
      |||>
        /kaniko/executor
        --context .
        --dockerfile Dockerfile
        --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
        --destination $CI_REGISTRY_IMAGE:latest
      |||,
    ],
  },
}

The "long line" in the above example is also pretty tame and could be squished into a single line. Some commands are far longer and simply must be split over multiple lines for readability, and I think a "folded" text block could make these easy handle.

This is a small deal in the scheme of things. I get a lot of joy from the flexibility of YAML's multi-line strings and would love to see some of it in jsonnet.

sbarzowski commented 3 years ago

Are you aware of ||| text blocks? See the tutorial: https://jsonnet.org/learning/tutorial.html.

drewgingerich commented 3 years ago

Hi @sbarzowski I did see the ||| text block, but I did not see a way to replace the newlines with it. I've done this with a small function, but I like the terseness and flow of the YAML folded-style multi-line string for long shell commands.

I've updated the question to better describe what I'm talking about related to the current ||| text block.

sbarzowski commented 3 years ago

Ah, so you want the newlines replaced with spaces. I see how it can be quite useful sometimes.

zc-devs commented 2 days ago

Hi, I use >- folded style with chomping indicator for writing CSP headers in Traefik middleware:

apiVersion: traefik.io/v1alpha1
kind: Middleware
spec:
  headers:
    contentSecurityPolicy: >-
      upgrade-insecure-requests;
      base-uri 'self';
      default-src 'self';

Example above works great. Recently, I've migrated to Grafana Tanka and that snippet was replaced by:

      middlewareHeaders:
        local mw = traefik.middleware;
        mw.new(fullName + '-headers', namespace)
        + mw.metadata.withLabels(labels)
        + mw.spec.headers.withContentSecurityPolicy(|||
          upgrade-insecure-requests;
          base-uri 'self';
          default-src 'self';
        |||),

which renders into

    contentSecurityPolicy: |
      upgrade-insecure-requests;
      base-uri 'self';
      default-src 'self';

While std.stripChars can convert | to |-, it will be multi-line string anyway. Therefore, it doesn't work as HTTP header. As a workaround I can replace line endings

        + mw.spec.headers.withContentSecurityPolicy(std.strReplace(|||
          upgrade-insecure-requests;
          base-uri 'self';
          default-src 'self';
        |||, '\n', ' ')),

and it would be rendered as

    contentSecurityPolicy: 'upgrade-insecure-requests; base-uri ''self''; default-src
      ''none''; form-action ''none''; frame-ancestors ''none''; '

which works, but looks ugly. So, it would be nice to have ability to render multi-line block as folded YAML, whether it would be addition to||| or some standard function.