There has been high desires to be able to tailor the version according to many rules, some of these include:
add part of a VCS hash.
read the version which is some other file.
do some something dynamic like adding the date.
While most of this information can be encoded from the grade and channel installed from, users seem to just want to look at the version. To solve that matter my proposal is to extend the schema to allow
If version-script is selected, then rules for scripts apply and whatever is echoed is what ends up as the version (stripping any trailing newlines). To make things more dynamic, the script will have access to a variable SNAPCRAFT_GRADE with the already existing SNAPCRAFT_PROJECT_VERSION which makes something like this construct possible:
if [ "$SNAPCRAFT_GRADE" = "stable" ]
echo $SNAPCRAFT_PROJECT_VERSION-$(git rev-parse HEAD)
Given that parts can chain together in different ways with the after keyword and we don’t want to complicate the logic for any user, this will run during the creation of meta which happens after all parts have been staged and is only useful for visualization purposes.
Additionally version will allow an entry of git which is a hint for snapcraft to construct a version for you with the following rules for the VCS repo containing the snapcraft project (from running git describe):
if HEAD == $latest_tag → version will be set to $latest_tag.
if HEAD has commits ahead of $latest_tag → version will be set to $latest_tag+gitN.ABCDEF1 where N is the number of commits ahead and ABCDEF1 the commit hash for HEAD.
if there is no tag defined → version will be set to 0+git.ABCDEF1 where ABCDEF1 is the commit hash for HEAD
so how would i dynamically use a specific package version from one of the packages installed inside the snap or read from a file that is created during the build step of my snap ?
i.e. i guess something like the git rev example above is not executed during build but eariler.
That is a good constraint to make it something we do at the end of the build, and then this brings in the constraint that the SNAPCRAFT_PROJECT_VERSION exported anywhere in the environment will always be the one in the version field.
I guess this is ok, but I need to sit on it and probably wait for some other opinions to land.
I initially thought, either or. Which makes SNAPCRAFT_PROJECT_VERSION reusable in the version-scriptlet, we can also make this an oneOf but that means we need to compute the version at the beginning of snapcraft.
The other option, would be to do a two pass on the version, but it feels like it would be something rather broken. I am torn here, which is why I have left this task in limbo for so long.
how about introducing a second variable SNAPCRAFT_VERSION_OVERRIDE, that is only used after the build step and overrides in any case. that way you can have both and have a clear separation through the variable naming.
For this case I think we will need to go with @ogra’s suggestion of an override as this would invalidate any use of SNAPCRAFT_PROJECT_VERSION which gets injected into the environment early in the build so it is usable by parts and all the lifecycle steps.
Seems easy to establish a better pattern now, while remaining compatible. The -script (no need for let) suffix also sounds like a nice touch to make them alike.
That said, the suggestion above doesn’t seem so interesting… pull-build? pull-install? build-build? Not very intuitive.
pull-script (runs instead of)
build-script (runs instead of)
install-script (runs instead of)
I understand that build+install is done by a single method inside snapcraft’s implementation, but perhaps it should be considered further whether this is a good idea. It’s definitely not something people will expect upfront at least, so perhaps it might be tweaked so the steps above could make sense.
We’ve already crossed that line as you note above, and we did that very consciously.
Constraining the language to being entirely declarative so that it can then call a Makefile that is almost entirely procedural is not a great advantage. We’re making people’s lives more difficult without giving much in return.
That pain hurts more because most build systems don’t have a very strict way of running, which means project documentation ends up with that “how to build” section that needs to be translated into a snapcraft.yaml file. If we are too strict about it being declarative, we’ll then end up with thousands of trivial plugins simply adapting the way the underlying build system is called.
Having tiny scripts inline for that sort of tuning is more comfortable.
That’s the motivation behind allowing small scripts in snapcraft.yaml.
It feels to me that foo-script could easily become overkill, when really what we want in most cases is variable substitution.
I haven’t read the full thread, but have we explored the idea that a scriptlet early in the whole process, which is run every time, can set environment variables (“SNAPCRAFT_FOO”) which are then accessible inside the snapcraft.yaml with $SNAPCRAFT_FOO?
So this means there is ONE scriptlet which is always run if defined, and that sets environment variables, and environment variables can be substituted into snapcraft.yaml. I far prefer this to a xxx-script for anything we might want to substitute.