Define Version with script in RPM spec file
Asked Answered
A

3

18

I have an RPM Spec file, building on rhel7 with rpmbuild, where I would like to define the Version with a script.

I read here http://www.techrepublic.com/article/rpmproc-spec-file/ , That I can do this:

%define version 1.2

Version: %{version}

And here RPM spec file - Is it possible to dynamically populate a spec file variable , That I can define with a script:

%define whoami %(cmd)

So I tried to do this in my Spec File:

%define version %(echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' /fullfilepath/values.txt | sed 's/^\(.*\)-.*$/\1/')")

Version: %{version}  **Line 23**

But I get a

error: line 23: Empty tag: Version:

Things I have tested so far:

%define version %(echo "12") --basic script works ok, version becomes 12

//As a command straight in terminal
$ echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' /fullfilepath/values.txt | sed 's/^\(.*\)-.*$/\1/')"
//returns 1.2

These work well, So I have no idea what it could be thats causing it to fail. Any ideas what could be casuing it to fail when I call the same thing in define tag in spec file?

Update

I tried replacing the file name with the actual value so it looks like this

echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' <<< "appVersion = \"1.2-SNAPSHOT\"" | sed 's/^\(.*\)-.*$/\1/')"

That works when called in terminal but as a

%(echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' <<< "appVersion = \"1.2-SNAPSHOT\"" | sed 's/^\(.*\)-.*$/\1/')") 

but I still get the

Empty tag: Version: Error

Update 2

I tested a different more complex command then echo "12":

%define version %(echo "$(git log -1 | grep commit | awk -F"commit " '{print $2}' | cut -c1-8)")

This works ok too! Makes the version the 7 first digits of the commit hash.

Update 3

The mystery continues, I did a test to check if its the sed command thats the cause but the following command gives me 1.2 as the version

%define version %(echo "$( sed 's/.*= //' <<< "appVersion = 1.2" )")

If this command works but not my first one, then its got to be with something in my first command that only works when called directly in terminal and not in %(cmd). Getting closer!

Update 4

Ok so I seem to have isolated what it must be, curious, looks like it could be the -n or the s| | \1 |p syntax that rpmbuild doesn't like. I made a more simpler version of my original. Check it out:

#Error, doesn`t set version to 1.2
%define version %(echo "$( sed -n 's|^.*-\(-*\)|\1|p' <<< "foo-1.2" )") 

#Works ok! sets version to 1.2
%define version %(echo "$( sed 's/.*= //' <<< "appVersion = 1.2" )") 

Unfortunately though I don't think I can do anymore to isolate and figure out what the issue is. Theres nothing wrong with using a sed in the style of the second command but its still very interesting as to why the first command doesn't work.

Update 5

I have discovered that there is some deep issue here when working with any script inside %() with a spec file and rpmbuild. I tried using awk just to see what would happen and it too breaks! This goes way deeper then I initially thought, like discovering a conspiracy:

#In terminal it prints 1.2-SNAPSHOT, but in Spec it's an error 
%define version %(echo "$(awk '/appVersion /{ print $3 }' <<< "appVersion = \"1.2-SNAPSHOT\"" | tr -d \")")

sh: -c: line 0: unexpected EOF while looking for matching `)'
sh: -c: line 1: syntax error: unexpected end of file
error: line 23: Empty tag: Version:

Update 6

Good news and bad news for everyone, I found that rpm seems to be doing some of its own work in the backround and not showing what its doing, I finally found a command that gives different values when called through rpm:

%define version %(echo "$(awk '/midonetVersion /{ print $3 }' <<< "midonetVersion = \"5.1-SNAPSHOT\"")")
#In terminal it echos "5.1-SNAPSHOT" (literally wrapped in "" )
#When in spec it set version to 5.1-SNAPSHOT , rpmbuild is removing the ""

So now I made an adjustment and called this:

#echos "5.1 in terminal and sets version to 5.1 in spec
%define version %(echo "$(awk '/appVersion /{ print $3 }' <<< "appVersion = \"1.2-SNAPSHOT\"")"| cut -d'-' -f1)

So from looking at this, I think there maybe is a similar kind of behind the scenes parsing of the result of my first sed command from rpm. We will have our way rpm!

Final Update

A truce was made with rpm, I am going to use this command instead:

%define version %(echo "$(awk '/ appVersion =/{ print $3 }' /filepath/values.txt" | sed 's/\"//g' | cut -d'-' -f1)

It does the same thing as my first command and works inside specfile setting the version number correctly. If anyone has any guess as to why the first command wouldn't run I would be thrilled to read it. Peace!

Aerostat answered 18/11, 2015 at 4:15 Comment(1)
Could be because of permission issue with /fullfilepath/values.txt. Try replacing that with the actual (or simplified) value.Duroc
S
5

You must be having a shell script that invokes rpmbuild command. You can use that script to compute version (or for that matter, any command that you are trying to use in rpm spec file).

Change your original code,

%define version %(echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' /fullfilepath/values.txt | sed 's/^\(.*\)-.*$/\1/')")
Version: %{version}

to,

%define version _VERSION_
Version: %{version}

and sed _VERSION_ to its computed value in the shell script that calls rpmbuild (before invoking rpmbuild). After the actual spec contents are dumped to some file, pass on that generated file to rpmbuild in the same shell script.

Here is a summary of the steps:

Assuming you have a builder.sh shell script that calls rpmbuild, follow below steps:

  1. Update your spec file to have _VERSION_ placeholder string/macro as show above
  2. Move current rpm spec file to my_package_template.spec
  3. in builder.sh, run command(s) to get your version and save the version to a variable
  4. Use sed command on my_package_template.spec file to replace _VERSION_ by this computed version, and save the sed output to my_package.spec
  5. Pass my_package.spec to rpmbuild command.

Repeat steps 1, 3 and 4 for replacing usage of any other shell commands inside your spec file.

Sybilsybila answered 22/11, 2015 at 8:9 Comment(1)
rpmbuild allows setting variables from the command line, and that's a lot easier than requiring sed and temporary files.Basophil
B
1

I would do a wrapper script. That allows you to decide things like if it is a regular release or a development one, etc. Then you can pass the variables with the --define option - see this question for more options.

To respond to @Herrgott's comment "if you %define it in spec and try to redefine with --define it won't override that" (can't have newlines in comments) - you can set an "_override" variable of the same name with --define.

%if 0%{?val_override:1}
%define val %{val_override}
%else
%define val whatever
%endif
Basophil answered 22/11, 2015 at 13:46 Comment(2)
if you %define it in spec and try to redefine with --define it won't override thatSimplism
@Herrgott replied in main response; cannot do newlines in comments.Basophil
N
0

Necro, but here we go.

First of all, all \ have to be escaped, so you need to switch them all to \\.
Second, when you invoked:

%define version %(echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' /fullfilepath/values.txt | sed 's/^\(.*\)-.*$/\1/')")

you're actually calling a subshell that prints the text of a command you want to run. However when you use:

Version: %{version}

You need %{version} to evaluate to an in-place string, not a command to get it. Likely you just need to drop the echo part, which also simplifies the command.

If I'm not mistaken, I believe you're also using regex syntax in your sed command that's only available with extended regex, so you need the -E option to it. However what you're doing with the first sed command is extracting everything after appVersion = " up to the last " on the line from your file, then trying to drop everything after the last - on the line. Presuming you actually want the part of your version number before the first -, this is is easier to accomplish with a grep -Po that makes use of the \K operator to return only what's matched.

%define version %(grep -P '^[ ]*appVersion = "\\K([^"-]+)' /fullfilepath/values.txt)

Now %{version} is set to the value that's returned when the parsing command is run, rather than to the command itself. If there's any issues parsing, it will bet set to %{nil} (empty) instead.

However, you do need to keep in mind that the path to /fullfilepath/values.txt is the path when rpmbuild or rpmspec is called. If the host system running it doesn't have the file at exactly /fullfilepath/values.txt, then it won't find the file to parse.


If you really did need to set it to the command to run instead of the value from running it, you would leave off the surrounding %() and just set to

%define version grep -P '^[ ]*appVersion = "\\K([^"-]+)' /fullfilepath/values.txt
Ns answered 11/5, 2023 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.