Searched and only got this question a year ago https://www.reddit.com/r/nim/comments/chcr4m/best_practice_for_embedding_nimble_package/ .
I noticed we have information in <project>.nimble file, can I reuse that information in my code? Or any other alternative?
nimble dump
Better yet:
nimble dump --json
Evaluating it as NimScript is indeed what that nimp parser does (for new-style .nimble), but I agree finding it could be tricky. @Araq's include idea is probably best, if that always works for nimble itself.
I have not tested it against all nimble operations, but if the .nimble file moves, maybe some operation would not find the include file. (Not that I think nimble should be moving around any files at all.)
@Araq's include idea is probably best, if that always works for nimble itself.
Sure it does, Nimble asks the Nim compiler to run the .nimble file as NimScript, no bugs or inconsistencies are possible. :-)
I got the basic idea. My point was about finding the include-ee following up on @SolitudeSF's point about finding the .nimble file.
Basically, if the relative location of some source module and its .nimble can change then finding the .nimble from the source or the .nimble finding the version.nim seem to me to be "dual" problems.
Concretely, if .nimble cannot just include version unqualified but has to include foo/version, and then if there are > 1 versions installed (1.2.3, 1.0.1, say), it likely also has to include "foo-1.0.1/version" to be sure to get the right one, but then the version file is not doing any real work - you had to use a literal version anyway. Anything that moves .nimble so that it cannot do an unqualified include/import seems like it could cause trouble, and this seems independent of which direction "finding" happens in.
I'm just elaborating on what I meant since I think it was not understood. I have never myself seen nimble rearrange .nimble locations things at install time the way @SolitudeSF's relative relocation problem mentions. Maybe I am just lucky and it happens in some nimble "package layout" I don't use (or think should exist). @SolitudeSF can perhaps clarify when he thinks it happens and/or explain why the problems are not "duals".
Interesting, it seems everyone invented their way to update/share version. Let me share my two cents.
Basically, the method is same as @cblake , I made a nim task that can show the current version and update the version
Show version string
> nimble version
0.1.2
Update version string
> nimble version 0.1.3
And then if other files depend on the package version, I will write a proc in nimscript and replace the string in that file. For example, I have a configuration file read by nomad for container orchestration. The version is used to tag container image.
proc updateNomadVersion(ver: string) =
# replace "example.com:443/user/project_name:xxx"
let fname = "conf/project_name.nomad"
let txt = readFile(fname)
let pat = "\"example.com:443/user/project_name:"
let s = txt.find(pat)
let e = txt.find("\"", s + pat.len)
writeFile(fname, txt[0 ..< s+pat.len] & ver & txt[e ..< txt.len])
Also, I use release-it for auto versioning which will create git tag and call a hook to nimble update <version>. (Some people may not like auto versioning, but IMO it is fine at least for internal projects.)
Therefore, git tag, version in nimscript, container image tag, version nomad file all have to be in sync.
Having a separate nim file containing the version will require third party tools to parse/understand that nim file. This is not doable for nomad configuration file (nomad provide some variable interpolation, but no staticRead or enough functionality for parsing). And while it is doable in release-it, it is nicer to just call nimble version <version> , rather than putting the logics directly in the hook.
It maybe subjective that I prefer reading the version in plain text directly in nimble, rather jumping into another file. The abstract question of this problem is choosing single source of truth or having some tools that make values in sync and I choose the later in this case.
You may say that the parsing as shown in updateXXXVersion are not correct/complete. I would say that they are not universal for all cases, but they are reliable for each case.
Apparently it's not properly read by the nimble build command either. If you look at nimble build --version you will see that -d:NimblePkgVersion is set to be empty. So it somehow detects that version is set, but is unable to see what it is actually set to. I created a file similar to yours but renamed the constant to pkgversion and then put this into the .nimble file:
include src/versioninfo
version = pkgversion
Now both -d:NimblePkgVersion is set to the correct number, and nimble test runs fine.
Yeah, to be honest, when I wrote this I had no idea how Nimble really works, it turns out it only sometimes asks Nim to process the Nimscript file and sometimes it's still using its old parser based on Nim's "ini" configuration file parser, I think. It's bad.
This is completely false :)
Nimble always reads .nimble files using Nim. It only attempts to read it as an ini file if that fails, if both fail then you'll get an error letting you know the reason for failure of both parsers. Nimble never starts by assuming it's an ini file.
Apparently, the file is not interpreted as a Nim file when nimble test is executed, but it is with nimble build. I do not know what is the expected behavior here.
Are you sure it works with nimble build? I don't see how const version = "0.1.1" could work, you are defining a new version constant, not setting the version variable that is defined in nimscript...
Why not do it the other way though? Nimble defines NimblePkgVersion when compiling your application
Exactly. This is how everyone should do it.
For those that don't want to use Nimble to build their software, we can have Nimble add this define into the same config file that Nimble's --path's flags end up.
I also often define a release task and use that to build my releases:
task release, "Build a release version of my code":
# So you can customise exactly what needs to be built.
exec "nimble build -d:release"
exec "nimble c -d:release src/foo.nim
But I know some people really don't want to run Nimble to build their software for some reason :)
Thanks a lot @Yardanico and @dom96, I am more than happy to use Nimble, so your suggestion is much appreciated.
I have put these lines in my source code
const NimblePkgVersion {.strdefine.} = "Unknown"
const version = NimblePkgVersion
and everything that refers to version now uses the version specified in the Nimble file.
Thanks a lot!
I don't know i this fully solves @zio_tom78's problem, but if you are building out of your package somewhere then you can maybe just ignore nimble and just do something like this:
const versionStr = staticExec "git describe --tags HEAD"
(possibly with some post processing if you like).You can use pkginfo https://github.com/openpeep/pkginfo 👌
A small utility package that can collect all the .nimble meta data and package dependencies on compile-time.
It can be used to get meta data from all kind of dependencies (direct/indirect).
All the information is stored in a pkginfo.json in the current working project.
import pkginfo
when pkg("jsony").getVersion > v "0.1.1":
echo "using a newer version of jsony"
import pkginfo
when requires "toktok":
when pkg("toktok").getVersion > v("0.1.1"):
echo "backwards compatibility support"
else:
echo "code for newer versions"
import pkginfo
when nimVersion() < v "1.6.6":
{.warning: "You are using an older version of Nim".}
(Tested on OSX. Need some help with Windows)