%{lua: --[[------------------------------------------------------------------------------------------------ File: vdb.lua Copyright 🄯 2022 Van de Bugger. SPDX-License-Identifier: GPL-3.0-or-later --]]------------------------------------------------------------------------------------------------ if not _vdb_loaded_ then --[[ Some older rpms evaluate the file twice, so I added these guards. It looks like it is not required any more, at least in rpm 4.15.1. ]]-- _vdb_subpackages_ = {} --[[------------------------------------------------------------------------------------------------ String manipulation routines. --]]------------------------------------------------------------------------------------------------ --[[ Substitution, or search and replace. `string.gsub` returns *two* results (the modified string and the number of replacements done), it may break code, e. g.: split( " ", string.gsub( str, "\n", " " ) ) -- bang! `split` will receive 3 arguments, not 2! `subst` returns only one result, it makes nested calls safe: split( " ", subst( str, "\n", " " ) ) ]]-- function subst( str, ... ) local subs = { ... } if # subs % 2 == 1 then push( subs, "" ) end local i = 1 while i < # subs do str = string.gsub( str, subs[ i ], subs[ i + 1 ] ) i = i + 2 end return str end -- Escapes % characters, returns string with all % characters doubled. function escape( str ) return subst( str, "%%", "%%%%" ) end -- Quotes string for using in shell scripts. function quote( str ) -- TODO: Do not quote string if it is does not contain spaces and special characters. return "'" .. subst( str, "'", "'\\''" ) .. "'" end -- Drops leading and trailing white space. function trim( str ) return subst( str, "^%s+", "", "%s+$", "" ) end -- Drops trailing newline, if any. function chomp( str ) return subst( str, "\n$", "" ) end -- Drops leading and trailing white space, and shrinks internal white space. function shrink( str ) return trim( subst( str, "%s+", " " ) ) end --[[-- Returns a concatenation of all hash values in order of their keys. Note the difference between join and table.concat: * table.concat process only keys in range [1 .. #has], other keys are ignored. join process all keys. * table.concat can't process boolean values, join can. --]]-- function join( sep, hash ) -- table.concat doesn't like boolean values, so let's convert all values to strings: return table.concat( map( tostring, hash ), sep ) end -- Perl-like split: split string into items. function split( sep, str, limit ) if sep == " " then -- Special case. sep = "%s+" str = subst( str, "^" .. sep, "" ) end local list = {} if # str == 0 then -- One more special case. return list end limit = limit or 0 local strip = limit == 0 if limit <= 0 then limit = math.maxinteger end local pos = 1 repeat -- I have just one more slot: grab the rest of the string and exit the loop. if # list + 1 == limit then push( list, string.sub( str, pos ) ) break end -- Ok, I have some more slots, I can continue splitting. Try to find the next separator. local start, finish = string.find( str, sep, pos + ( # sep == 0 and 1 or 0 ) ) -- No more separators, grab the rest of the string and exit the loop. if start == nil then push( list, string.sub( str, pos ) ) break end -- Ok, the next separator found. Grab the piece of the string up to the next separator. push( list, string.sub( str, pos, start - 1 ) ) -- And move forward the current position behing the separator. pos = finish + 1 until false -- If limit is zero, drop trailing empty items: if strip then while # list > 0 and list[ # list ] == "" do pop( list ) end end return list end -- Perl-like uc: convert string to upper case. uc = string.upper -- Perl-like lc: convert string to lower case. lc = string.lower --[[-- Title case: convert the given string to lower case, then capitalize the first lettwer of every word. --]]-- function tc( str ) return subst( lc( str ), '^([^%s])', uc, '(%s[^%s])', uc ) end -- Perl-like sprintf. sprintf = string.format --[[-- Makes identifier (i. e. package name) from a string (e. g. program or font family name). The function replaces spaces with dashes and converts everything to lower case. Function accepts many arguments. e. g.: ident( 'Iosevka', 'Full', 'Ssans' ) -- returns 'iosevka-full-sans' --]]-- function ident( ... ) return lc( subst( join( ' ', { ... } ), ' ', '-' ) ) end --[[-- Prepends every line of text with prefix. --]]-- function prepend( prefix, text ) if text == "" then return text else local nl = string.sub( text, -1 ) == "\n" if nl then text = string.sub( text, 1, -2 ) end text = prefix .. subst( text, "\n", "\n" .. prefix ) if nl then text = text .. "\n" end return text end end --[[ Reflows text. Text may include multiple paragraphs separated by empty lines. Each paragraph will be reflowed. During reflow all leading and trailing spaces and tabs are dropped, spaces and tabs are shrinked to exactly one space, words will be (re)distributed between lines so each line does not exceed specified width (if possible). Current limitations are: * The function is not Unicode-aware. ]]-- function reflow( text, width ) text = subst( text, "^%s+", "", -- Drop leading whitespace in the text. "%s+$", "", -- Drop trailing whitespace in the text. "[ \t]+", " ", -- Shrink spaces and tabs to one space. "\n ", "\n", -- Drop leading spaces in every line (except the first line). " \n", "\n", -- Drop trailing spaces in every line (except the last line). "\n\n+", "\n\n" -- Shrink empty lines. ) width = width or 80 local paragraphs = {} for p, paragraph in ipairs( split( "\n\n", text ) ) do local words = split( " ", paragraph ) local lines = {} -- Lines of the new paragraph. local line = "" -- Current line for w, word in ipairs( words ) do if # line == 0 then line = word elseif # line + 1 + # word <= width then line = line .. " " .. word else push( lines, line ) line = word end end if # line > 0 then push( lines, line ) end push( paragraphs, join( "\n", lines ) ) end text = join( "\n\n", paragraphs ) return text end -- Convert a value to string for debug purposes. function str( value ) local t = type( value ) if t == 'nil' then return 'nil' elseif t == 'boolean' or t == 'number' then return tostring( value ) elseif t == 'string' then return "'" .. subst( value, "[%c'\\]", function ( chr ) if chr == '\a' then return '\\a' elseif chr == '\b' then return '\\b' elseif chr == '\f' then return '\\f' elseif chr == '\n' then return '\\n' elseif chr == '\r' then return '\\r' elseif chr == '\t' then return '\\t' elseif chr == '\v' then return '\\v' elseif chr == '\\' then return '\\\\' elseif chr == "'" then return "\\'" end local result = '' for i, k in ipairs( table.pack( string.byte( chr, 1, -1 ) ) ) do result = result .. sprintf( '\\x%02X', k ) end return result end ) .. "'" elseif t == 'table' then local lines = {} push( lines, '{' ) for i, k in ipairs( keys( value ) ) do push( lines, prepend( ' ', sprintf( '%s → %s,', str( k ), str( value[ k ] ) ) ) ) end if # lines > 1 then push( lines, '}' ) else lines[ 1 ] = '{}' end return join( '\n', lines ) elseif t == 'function' then return tostring( value ) elseif t == 'userdata' then die( 'oops: userdata' ) else die( 'oops: unknown type: %s', t ) end end --[[------------------------------------------------------------------------------------------------ Array manipulation routines. --]]------------------------------------------------------------------------------------------------ -- Appends element(s) to the given array. function push( array, ... ) for i, v in ipairs( { ... } ) do table.insert( array, v ) end end -- Removes the last element from the given array and returns the removed element. function pop( array ) local value if # array > 0 then value = table.remove( array ) end return value end -- Removes the first element from the given array, and returns the removed element. function shift( array ) local value if # array > 0 then value = table.remove( array, 1 ) end return value end --[[-- Sorts values of the given array in-place. It is table.sort with custom compare function. Default compare function can't compare boolean values, can't compare string with number, etc. Custom compare function works well with booleans, numbers and strings: booleans go first (false, then true), then go numbers (in natural order), then strings. This function should be local, but it made public for testing purposes. --]]-- function _sort( array ) _sort_order = { [ 'nil' ] = 0, [ 'boolean' ] = 1, [ 'number' ] = 2, [ 'string' ] = 3, [ 'table' ] = 4, [ 'function' ] = 5, [ 'thread' ] = 6, [ 'userdata' ] = 7, } table.sort( array, function ( a, b ) local ta = _sort_order[ type( a ) ] local tb = _sort_order[ type( b ) ] -- Lua can't compare values if their types differ, so let's make sure types if ta == tb then if ta == 1 then -- Lua can't compare boolean values return ( a and 1 or 0 ) < ( b and 1 or 0 ) end return a < b else return ta < tb end end ) return array end --[[------------------------------------------------------------------------------------------------ Hash manipulation routines. --]]------------------------------------------------------------------------------------------------ --[[-- Creates a hash. --]]-- function hash( keys, value ) if value == nil then value = false -- In Lua, nil value can't be stored in hash, let's use false instead. end local hash = {} for k, v in pairs( keys ) do hash[ v ] = value end return hash end --[[-- Returns sorted array of hash keys. --]]-- function keys( hash ) local keys = {} for k, v in pairs( hash ) do push( keys, k ) end return _sort( keys ) end --[[-- Returns array of hash values sorted by their keys. --]]-- function vals( hash ) local values = {} for i, k in ipairs( keys( hash ) ) do push( values, hash[ k ] ) end return values end --[[-- Returns sorted array of hash values. --]]-- function sort( hash ) --[[-- `table.sort` works on elements with keys in range [1 .. #table], other elements are ignored. Let's build array of hash values first, so all the values are sorted. --]]-- local values = {} for k, v in pairs( hash ) do push( values, v ) end return _sort( values ) end --[[-- Returns array, constructed from the given hash by applying the given function to each hash item (value and key), and pushing the function's result to the array. Hash items are enumerated in order defined by their sorted keys. --]]-- function map( func, hash ) local result = {} for i, k in ipairs( keys( hash ) ) do push( result, func( hash[ k ], k ) ) end return result end --[[-- Returns array, constructed from the given hash by applying the given pred function to each hash item (value and key), and pushing the hash value to the array if pred returned true for the item. If pred returned false, the item does not go into the array. Hash items are enumerated in order defined by their sorted keys. If pred is not a function, only values equal to pred go to the array. --]]-- function grep( pred, hash ) local func if type( pred ) == "function" then func = pred else func = function ( it ) return it == pred; end end local result = {} for i, k in ipairs( keys( hash ) ) do if func( hash[ k ], k ) then push( result, hash[ k ] ) end end return result end --[[------------------------------------------------------------------------------------------------ RPM primitive routines. --]]------------------------------------------------------------------------------------------------ -- Expands rpm macros in the given string, returns result of expansion. expand = rpm.expand -- Returns true if rpm macro is defined, and false otherwise. function defined( name ) if rpm[ 'isdefined' ] then local defined, parametrized = rpm.isdefined( name ) return defined else return expand( "%{?" .. escape( name ) .. ":1}" ) == "1" end end --[[-- Define rpm macro. Note that rpm macros are stacked: (re)defining a macro does not simply overwrite the old value but pushes a new value on the stack. See also `unset`. --]]-- function set( name, value ) --[[-- If value is empty, rpm will complain on empty macro value. Let's use `%{nil}` in such a case to avoid warning. Also, RPM work with strings only, so let's convert Lua boolean values to strings. --]]-- if value == nil or value == "" then value = "%{nil}" elseif value == true then value = "1" elseif value == false then value = "0" end value = subst( value, "\\", "\\\\", -- Backslashes in macro body must be doubled. "\n", "\\\n" -- And newlines must be preceeded by backslashes. ) local l = name .. " " .. value spc( "%%define %s", l ) rpm.define( l ) return value end --[[-- Undefine rpm macro. Note that rpm macros are stacked: (re)defining a macro does not simply overwrite the old value but pushes a new value on the stack. Unsetting macro pops a value from the top of the stack, restoring the previous macro value. `count` — how many values to pop from the stack. By default 1. If 0, all the values will be popped, leaving the macro undefined. --]]-- function unset( name, count ) if count == nil then count = 1 end if count > 0 then while count > 0 do spc( "%%undefine %s", name ) rpm.undefine( name ) count = count - 1 end else while defined( name ) do spc( "%%undefine %s", name ) rpm.undefine( name ) end end end -- Get expanded value of rpm macro. If macro is not defined, default value is returned, and nil if -- default is not specified. Note, that resul type depends on default type: if default is number, -- result is converted to number too, if default is boolean, the result is converted to boolean -- too, otherwise result will be either string or nil. function get( name, default ) local result if defined( name ) then result = expand( "%{" .. escape( name ) .. "}" ) if type( default ) == "number" then -- If default value is number, convert result to number. result = tonumber( result ) elseif type( default ) == "boolean" then -- If default value is boolean, convert result to number. -- Note: empty string and "0" are treated as false, everything else — as true. result = not ( result == "" or result == "0" ) end end if result == nil then result = default end return result end -- Generate spec code. If the first parameter is table, it is interpreted as set of macros, which -- will be temporary defined. function spec( ... ) local lines = { ... } -- See if macros are present. local macros = {} if # lines > 0 and type( lines[ 1 ] ) == "table" then macros = shift( lines ) end -- Set macros: for name, value in pairs( macros ) do set( name, value ) end -- Generate spec code: for i, line in ipairs( lines ) do local l = expand( line ) spc( "%s", l ) if # lines == 1 then print( l ) else print( l .. "\n" ) end end -- Restore original macro values: for name in pairs( macros ) do unset( name ) end end --[[------------------------------------------------------------------------------------------------ OS and filesystem routines. --]]------------------------------------------------------------------------------------------------ -- Get value of environment variable. If variable is not defined, default value is returned, and -- nil if default is not specified. Note, that resul type depends on default: if default is number, -- result is converted to number, if default is boolean, the result is converted to boolean, -- otherwise result will be either string or nil. function get_env( name, default ) local result result = posix.getenv( name ) if result then if type( default ) == "number" then -- If default value is number, convert result to number. result = tonumber( result ) elseif type( default ) == "boolean" then -- If default value is boolean, convert result to number. -- Note: empty string and "0" are treated as false, everything else — as true. result = not ( result == "" or result == "0" ) end end if result == nil then result = default end return result end -- Returns true if file exists. function exist( path ) return not not posix.stat( path ) end -- Rename file or directory. function rename( old, new ) -- `+` mimics `rpmbuild` output. say( "+ mv %s %s", old, new ) local ok, error = os.rename( old, new ) if not ok then die( "mv: %s", error ) end return ok end --[[-- Read file. Read first `limit` lines of file. If limit is zero or nil, read all the lines, but drop empty lines at the end. If `limit` is negative, read all the lines. --]]-- function slurp( path, limit ) local lines = {} if limit == nil then limit = 0 end for line in io.lines( path ) do push( lines, line ) if limit > 0 and # lines >= limit then break end end if limit == 0 then while # lines > 0 and lines[ # lines ] == "" do pop( lines ) end end return lines end -- Write file. function spurt( path, ... ) local temp = path .. ".tmp" say( "+ > %s", temp ) local file, err = io.open( temp, "w" ) if file == nil then die( "Can't open file %s for writing: %s", temp, err ) end local lines = { ... } for i, line in ipairs( lines ) do file, err = file:write( line .. "\n" ) if file == nil then die( "Can't write file %s: %s", temp, err ) end end -- TODO: Does close report errors? file:close() rename( temp, path ) end -- Execute shell command. function shell( command ) -- `+` mimics `rpmbuild` output. say( "+ %s", command ) local ok, status, code = os.execute( command ) if not ok then if status == "exit" then die( "command exited with status %d", code ) else die( "command died with signal %d", code ) end end return ok end --[[------------------------------------------------------------------------------------------------ Logging routines. --]]------------------------------------------------------------------------------------------------ function _say( prefix, format, ... ) io.stderr:write( prepend( prefix, sprintf( format, ... ) ) .. "\n" ) end -- Print a message to stderr if debug enabled. function dbg( format, ... ) if get( "_vdb_debug_", false ) then _say( "# ", format, ... ) end end -- Print a message to stderr if debug enabled. function spc( format, ... ) if get( "_vdb_debug_", false ) then _say( "> ", format, ... ) end end -- Print a variable. function dump( value, name ) if name == nil then dbg( "%s", str( value ) ) else dbg( "%s = %s", name, str( value ) ) end end -- Print a message to stderr. function say( format, ... ) _say( "", format, ... ) end function note( format, ... ) _say( "* ", format, ... ) end function warn( format, ... ) _say( "warning: ", format, ... ) end -- Print a error to stderr. -- Building will be stopped in the nearest %prologue. function die( format, ... ) if format ~= nil then _say( "error: ", format, ... ) end error( "oops" ) end ---------------------------------------------------------------------------------------------------- --[[-- Someone can run `rpmbuild -bb name.spec` and build rpm files. However, exact name of built rpm is not known to the caller because name contains version, release, and architecture -- these parameters are encoded into spec and not easily available outside of the spec file. The things are even worse if one spec file generates few subpackages. Let us write them out to the rc file, so the caller can source the rc file and construct rpm name(s), e. g. "$NAME-$VERSION-$RELEASE.$ARCH.rpm". --]]-- function write_rc_file( file ) local function var( name, value ) if type( value ) == "table" then return name .. "=(" .. join( " ", map( quote, value ) ) .. ")" else return name .. "=" .. quote( value ) end end spurt( file, var( "NAME", get( "name" ) ), var( "VERSION", get( "version" ) ), var( "RELEASE", get( "release" ) ), var( "ARCH", get( "_target_cpu" ) ), var( "RPMS", get( "_rpmdir" ) ), var( "SRPMS", get( "_srcrpmdir" ) ), var( "SUBPACKAGES", _vdb_subpackages_ ) ) end function banner( phase ) return ": ---------- " .. phase .. " ---------- :" end -- Prologue to execute in the beginning of every scriptlet: local prologue = "set -e; [ -n \"$BASH_VERSION\" ] && set -o pipefail;" set( "prologue", prologue ) function prep() local file = get_env( "SPEC_RC_FILE", "" ) if file ~= "" then write_rc_file( file ) end spec( banner( "PREP" ), prologue ) end function build() spec( banner( "BUILD" ), prologue ) end function check() spec( banner( "CHECK" ), prologue ) end function install() spec( banner( "INSTALL" ), prologue ) end function clean() spec( banner( "CLEAN" ), prologue ) end ---------------------------------------------------------------------------------------------------- -- Redefine %prep, %build, %check and %install macros: -- Let's add prologue to the every build-time scriptlet. -- The idea is great but Fedora/RedHat rpmbuild macros also use this trick. -- So I can't add prologue to %install. local phases = { "prep", "build", "check", "install", "clean" } for i, phase in ipairs( phases ) do if defined( phase ) then warn( "'%s' macro is already defined, can't add prologue.", phase ) else set( phase, "%%" .. phase .. " \n" .. "%{lua: " .. phase .. "(); }" ) end end --[[------------------------------------------------------------------------------------------------ Let's add prologue to the every install-time scriptlet. --]]------------------------------------------------------------------------------------------------ -- Install-time scriptlets: local phases = { "pretrans", "pre", "post", "triggerin", "triggerun", "preun", "postun", "triggerpostun", "posttrans", } for i, phase in ipairs( phases ) do if defined( phase ) then warn( "'%s' macro already defined", phase ) else -- If -p option present present, do not add prologue. set( phase .. "(p:)", "%%" .. phase .. " %** \n" .. "%{!-p:%prologue}" ) end end --[[------------------------------------------------------------------------------------------------ Play the same trick to collect all subpackage names: --]]------------------------------------------------------------------------------------------------ if defined( "package" ) then die( "'%s' macro already defined", "package" ) end set( -- %package macro may have -n option. If -n is present, it defines full name of the subpackage. -- Oterwise subpackage name is constructed from package name and the first macro argument. "package(n:)", [[ %%package %** %{lua: dbg( "%%package %s", get( "**" ) ) push( _vdb_subpackages_, get( "-n*" ) or get( "name" ) .. "-" .. get( "1" ) ) } ]] ) --[[------------------------------------------------------------------------------------------------ Find out versions of external programs: --]]------------------------------------------------------------------------------------------------ -- Find out version of install program: function install_version() if _vdb_install_version_ == nil then local program = get( "__install" ) local output = rpm.expand( "%( %{__install} --version )" ) if output == "" then die( "Can't find version of '%s' program.", program ) end output = split( "\n", output, 2 )[ 1 ] -- Get the first line of output. local version = string.match( output, "^install %(GNU coreutils%) ([0-9.]+)$" ) if version == nil then die( "Can't parse '%s' program output: '%s'", program, output ) end dbg( "%s version %s", program, version ) _vdb_install_version_ = version end return _vdb_install_version_ end -- Find out version of rpm program: function rpm_version() if _vdb_rpm_version_ == nil then local program = get( "__rpm" ) local output = expand( "%( %{__rpm} --version )" ) if output == "" then die( "Can't find version of '%s' program.", program ) end output = split( "\n", output, 2 )[ 1 ] -- Get the first line of output. local version = string.match( output, "^RPM version ([-0-9a-z.]+)$" ) -- RPM version could be like `4.0.16` or `4.1.0-alpha1`. if version == nil then die( "Can't parse '%s' program output: '%s'", program, output ) end dbg( "%s version %s", program, version ) _vdb_rpm_version_ = version end return _vdb_rpm_version_ end --[[------------------------------------------------------------------------------------------------ Macros to use in spec files: --]]------------------------------------------------------------------------------------------------ --[[ Usage: %{rem: Long multi-line comment. } ]]-- set( "rem" ) --[[ Usage: %Global NAME VALUE Defines global with specified NAME and VALUE, as well as lowercase version (both name and value) of the global. Example: %Global Font Hack # equivalent for # %global Font Hack # %global font hack ]]-- set( "Global()", "%{lua: spec( " .. "\"%global \" .. get( 1 ) .. \" \" .. get( 2 ), " .. "\"%global \" .. lc( get( 1 ) ) .. \" \" .. lc( get( 2 ) ) " .. ") }" ) --[[ Usage: %description %{text -w -- \ Long description. Description may include multiple paragraphs. Description will be reflowed (see `reflow` function for details. } %global common_description %{text -- \ Long description. ... } where: * — integer number, desired max width of reformatted text. Option -w may be omitted, 80 will be used by default. ]]-- set( "text(w:)", "%{lua: spec( reflow( expand( subst( get( \"*\" ), \"^\\\\\" ) ), get( \"-w*\", 80 ) ) ) }" -- Depending on usage (in %description body or in macro body) `get( "*" )` can return a -- string starting with `\` or not. Let's remove starting `\`. ) --[[ Usage: %_install_D OPTION... ARGUMENT... Runs install program with -D and other specified options and arguments. Modern versions of install program treat -D option as instruction to create *all* the components of the target directory. However, older install in RHEL 6 and 7 treats -D option differently: it creates all the components of target directory *but* the last. _install_D macro emulates modern install program on RHEL 6 and 7. The macro recognizes only short options (e. g. `-t`), long options (e. g. `--target-directory`) are not supported. Also, currenly only `-m`, `-p`, and `-t` options are supported. Example: %install %_install_D -p -t %{buildroot}%{_bindir} build/bin/%{name} ]]-- local version = install_version() -- install 8.22 does not create the last component of target directory. -- install 8.29 does create all components. if rpm.vercmp( version, "8.23" ) > 0 then -- looks like vercmp returns -1, 0, and 1. -- install is recent enough to handle -D properly: dbg( "install %s: ok", version ) set( "_install_D", "%{__install} -D" ) else -- install is too old, create target directory before calling install: dbg( "install %s: too old", version ) -- Expanding two macros in adjacent lines: -- %_install_D -t dir0 file0 -- %_install-D -t dir1 file1 -- gives strange result in EPEL 6: -- mkdir -p dir0; install -D -t dir0 file0mkdir -p dir1; install -D -t dir1 file1 -- The macros are expanded to a single line with neither new line nor space between them. -- Other distros (EPEL 7, Fedora, Mageia, OpenSuse) do not have such a problem. -- Let's add a semicolon to the end of macro value to avoid error. set( "_install_D(m:pt:)", "%{-t:%{__mkdir_p} %{-t*}; }%{__install} -D %{-m:-m %{-m*}} %{-p:-p} %{-t:-t %{-t*}} %*; " ) end --[[ Usage: %if %{author_check} ... %else ... %endif %{author_check} expands to 0 (false) if SPEC_AUTHOR_CHECK environment variable is not set or is empty or is zero. Otherwise %{author_check} evaluates to 1 (true). Example: %check %if %{author_check} %{_bindir}/appstreamcli validate "%{name}.metainfo.xml" %endif ]]-- local author_check = os.getenv( "SPEC_AUTHOR_CHECK" ) if author_check == nil or author_check == "" or author_check == "0" then author_check = "0" else author_check = "1" end set( "author_check", author_check ) --[[------------------------------------------------------------------------------------------------ External programs and directories: --]]------------------------------------------------------------------------------------------------ if not get( "__m4" ) then set( "__m4", "%{_bindir}/m4" ) end set( "__rpm", "%{_bindir}/rpm" ) set( "_licensedir", "%{_datadir}/licenses" ) set( "_fontdir", "%{_datadir}/fonts" ) if not defined( "_pkgdocdir" ) then -- Fedora defines _pkgdocdir, but OpenSuse doesn't. set( "_pkgdocdir", "%{_docdir}/%{name}" ) end if not get( "_metainfodir" ) then -- Mageia 6 does not define _metainfodir macro. -- As weel as OpenSuse 15.0, 15.1 and tumbleweed. set( "_metainfodir", "%{_datadir}/metainfo" ) end ---------------------------------------------------------------------------------------------------- --[[-- Platform detection: CentOS: %{centos} ("8"). EPEL: %{epel} ("7"). Fedora: %{fedora} ("34"). Fedora ELN: %{eln} (???). Mageia: %{mageia} ("9"). OpenMandriva: %{omvver} ("4003000" for rolling, "4050000" for cooker)?? %{mandriva_branch} ("Cooker" or "Rolling"). OpenSuse: %{suse_version} ("1500" for leap 15.2 and 15.3, "1550" for tumbleweed). --]]-- _vdb_loaded_ = 1 end } # end of file #