jsonnet icon indicating copy to clipboard operation
jsonnet copied to clipboard

jsonnet file argument does not use the importer (and doesn't respect jpath).

Open dosmanak opened this issue 3 years ago • 5 comments

jsonnet v0.15.0 does not scan library folders.

When folder specified using -J | --jpath, only current working directory is searched for the given filename. I have found in the code that also /usr/local/share/jsonnet-<version> and /usr/share/jsonnet-<version> should be scanned for jsonnet "libraries". https://github.com/google/jsonnet/blob/v0.15.0/core/libjsonnet.cpp#L184

root@e99caf4f0657:/tmp# jsonnet -v          
Jsonnet commandline interpreter v0.15.0
root@e99caf4f0657:/tmp# mkdir /usr/local/share/jsonnet-0.15.0
root@e99caf4f0657:/tmp# touch /usr/local/share/jsonnet-0.15.0/somefileinfoobarbaz
root@e99caf4f0657:/tmp# strace -s 2048  -f -E JSONNET_PATH=./foobarbaz jsonnet --jpath ./foobarbaz -J ./foobarbaz -- somefileinfoobarbaz |& grep foobarbaz
execve("/go/bin/jsonnet", ["jsonnet", "--jpath", "./foobarbaz", "-J", "./foobarbaz", "--", "somefileinfoobarbaz"], 0x558d1eb83340 /* 11 vars */) = 0
[pid   694] openat(AT_FDCWD, "somefileinfoobarbaz", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   694] write(2, "Opening input file: somefileinfoobarbaz: no such file or directory\n", 67 <unfinished ...>
Opening input file: somefileinfoobarbaz: no such file or directory

dosmanak avatar Jun 30 '21 12:06 dosmanak

Hmmm... Thanks for reporting, but it works on my machine™. Could you say more about your setup and the exact steps to reproduce?

sbarzowski avatar Jul 14 '21 19:07 sbarzowski

Well I tried it in some container I found on the web...

docker run -ti quay.io/coreos/jsonnet-ci bash

And run the following inside the container, but you can try the same command on your machine, just replace apt with your package manager if you don't have strace already installed.

apt update && apt install -y strace
jsonnet --version
mkdir /usr/local/share/jsonnet-0.15.0
touch /usr/local/share/jsonnet-0.15.0/somefileinfoobarbaz
cd /tmp/ && mkdir ./foobarbaz && touch somefileinfoobarbaz
strace -s 2048  -f -E JSONNET_PATH=./foobarbaz jsonnet --jpath ./foobarbaz -J ./foobarbaz -- somefileinfoobarbaz |& grep foobarbaz

The invocation jsonnet --jpath ./foobarbaz -J ./foobarbaz -- somefileinfoobarbaz Should mean that jsonnet searches for file in library ./foobarbaz with both argument variant from help:

-J / --jpath

Specify an additional library search dir (right-most wins)

Also, the strace sets up the environment variable JSONNET_PATH which is another way to define directories to search in.

The jsonnet program should then open the file somefileinfoobarbaz in ./foobarbaz or /usr/local/share/jsonnet-0.15.0, but as seen from the strace output, none of the locations is searched.

The only path which is searched for somefileinfoobarbaz is current directory

[pid 235809] openat(AT_FDCWD, "somefileinfoobarbaz", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

I was able to reproduce the behavior also my machine with jsonnet v0.17.0 :-(

dosmanak avatar Jul 15 '21 08:07 dosmanak

Ah, I get it now.

This will work: jsonnet --jpath ./foobarbaz -e 'import "somefileinfoobarbaz"'

This won't: `jsonnet --jpath ./foobarbaz somefileinfoobarbaz

JSONNET_PATH and --jpath are relevant for imported paths. The command does a direct filesystem lookup for the starting file.

I think always using the imports would make more sense, but it may also break some people. Maybe we can change that behavior, but it's not on top of my list. In the meantime you can easily work around it by using -e 'import "$YOUR_FILE"'

sbarzowski avatar Jul 24 '21 20:07 sbarzowski

Thank you for the insight. I have checked the -e 'import "somefileinfoobarbaz"' and I see the --jpath/-J works well, but all paths are tried, not the right-most as claimed in the usage ;-)

But I don't see the program try to open the file the at standard library path as defined in constructor at: https://github.com/google/jsonnet/blob/v0.17.0/core/libjsonnet.cpp#L184 Perhaps I just do not understand well the C++ code :-) but the default_import_callback should iterate all available paths but there is also some cpython_import_callback which maybe overrides it's function.

dosmanak avatar Jul 26 '21 07:07 dosmanak

Thank you for the insight. I have checked the -e 'import "somefileinfoobarbaz"' and I see the --jpath/-J works well, but all paths are tried, not the right-most as claimed in the usage ;-)

All of the paths are tried until a match is found (unless I'm missing something). If you get a match on first try, there will be no lookup in the remaining paths. So, yeah potentially all of them, but the leftmost component of JSONNET_PATH is tried first. Each --jpath prepends to JSONNET_PATH, so the rightmost jpath is the leftmost JSONNET_PATH component.

AFAICT tt checks these global paths. Here's what I get when stracing trying to import a nonexistent file:

openat(AT_FDCWD, "foobar.libsonnet", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/local/share/jsonnet-v0.17.0/foobar.libsonnet", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/jsonnet-v0.17.0/foobar.libsonnet", O_RDONLY) = -1 ENOENT (No such file or directory)

And when I actually put it at any of these paths, it works.

This has never been documented and people don't seem to depend on that. The Go implementation doesn't perform these global lookups (mostly because I was unaware of them until recently) and so far no one complained. For me personally, an explicitly defined JSONNET_PATH makes more sense for the kind of things Jsonnet is good at (i.e. when you are actively trying to eliminate dependence on the environment).

sbarzowski avatar Jul 26 '21 22:07 sbarzowski