Hello community, here is the log from the commit of package python-rpm-macros for openSUSE:Factory checked in at 2017-03-17 15:00:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-rpm-macros (Old) and /work/SRC/openSUSE:Factory/.python-rpm-macros.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-rpm-macros" Fri Mar 17 15:00:07 2017 rev:4 rq:479619 version:1.0.git.1489505194.b32e02a Changes: -------- --- /work/SRC/openSUSE:Factory/python-rpm-macros/python-rpm-macros.changes 2017-02-27 18:41:30.479485838 +0100 +++ /work/SRC/openSUSE:Factory/.python-rpm-macros.new/python-rpm-macros.changes 2017-03-17 15:00:12.443521066 +0100 @@ -1,0 +2,27 @@ +Mon Mar 13 16:05:15 UTC 2017 - [email protected] + +- more intelligent %python_install_alternatives +- multiline macro support +- support for %requires_ge and %requires_eq as well as Requires(pre) + and friends +- "%python_clone -a" auto-creates alternative entries + +------------------------------------------------------------------- +Thu Mar 9 17:20:12 UTC 2017 - [email protected] + +- implement %python_clone to clone files for alternatives + +------------------------------------------------------------------- +Wed Mar 8 15:22:55 UTC 2017 - [email protected] + +- support "Supplements" and "Enhances" tags +- support packageand() expression +- fix handling of %name in requires + +------------------------------------------------------------------- +Wed Mar 8 13:18:14 UTC 2017 - [email protected] + +- make macros more resilient to missing %python_subpackages +- expand %python_bin_suffix properly + +------------------------------------------------------------------- Old: ---- python-rpm-macros-1.0.git.1487869271.c6e9bfc.tar.bz2 New: ---- python-rpm-macros-1.0.git.1489505194.b32e02a.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-rpm-macros.spec ++++++ --- /var/tmp/diff_new_pack.t9y5OT/_old 2017-03-17 15:00:13.199414403 +0100 +++ /var/tmp/diff_new_pack.t9y5OT/_new 2017-03-17 15:00:13.203413838 +0100 @@ -17,7 +17,7 @@ Name: python-rpm-macros -Version: 1.0.git.1487869271.c6e9bfc +Version: 1.0.git.1489505194.b32e02a Release: 0 Summary: RPM macros for building of Python modules License: WTFPL ++++++ python-rpm-macros-1.0.git.1487869271.c6e9bfc.tar.bz2 -> python-rpm-macros-1.0.git.1489505194.b32e02a.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/README.md new/python-rpm-macros-1.0.git.1489505194.b32e02a/README.md --- old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/README.md 2017-02-23 18:01:11.000000000 +0100 +++ new/python-rpm-macros-1.0.git.1489505194.b32e02a/README.md 2017-03-14 16:26:34.000000000 +0100 @@ -72,6 +72,12 @@ `python3 generatefile.py %python3_bin_suffix` etc. +__`%python_clone filename`__ creates a copy of `filename` under a flavor-specific name for every +flavor. This is useful for packages that install unversioned executables: `/usr/bin/foo` is copied +to `/usr/bin/foo-%{python_bin_suffix}` for all flavors, and the shebang is modified accordingly. +__`%python_clone -a filename`__ will also invoke __%prepare_alternative__ with the appropriate +arguments. + __`%python2_build`, `%python3_build`, `%pypy3_build`__ expands to build instructions for the particular flavor. __`%python2_install`, `%python3_install`, `%pypy3_install`__ expands to install @@ -103,9 +109,17 @@ `/etc/alternatives`, and the target file called `<file>-%python_bin_suffix`. In case the file is a manpage (`file.1.gz`), the target is called `file-%suffix.1.gz`. -__`%python_install_alternative <name>`__: runs `update-alternatives` for `<name>-%{py_ver}`. - -__`%python_uninstall_alternative <name>`__: reverse of the preceding. +__`%python_install_alternative <name> [<name> <name>...]`__: runs `update-alternatives` +for `<name>-%{python_bin_suffix}`. If more than one argument is present, the remaining ones are +converted to `--slave` arguments. +If a `name` is in the form of `something.1` or `something.4.gz` (any number applies), it is +handled as a manpage and assumed to live in the appropriate `%{_mandir}` subdirectory, otherwise +it is handled as a binary and assumed to live in `%{_bindir}`. You can also supply a full path +to override this behavior. + +__`%python_uninstall_alternative <name>`__: reverse of the preceding. +Note that if you created a group by specifying multiple arguments to `install_alternative`, only +the first one applies for `uninstall_alternative`. Each of these has a flavor-specific spelling: `%python2_alternative` etc. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/apply-macros.sh new/python-rpm-macros-1.0.git.1489505194.b32e02a/apply-macros.sh --- old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/apply-macros.sh 2017-02-23 18:01:11.000000000 +0100 +++ new/python-rpm-macros-1.0.git.1489505194.b32e02a/apply-macros.sh 2017-03-14 16:26:34.000000000 +0100 @@ -9,5 +9,5 @@ ) rpmspec -v \ - --macros=$MYPATH/macros.python_all:$MYPATH/macros-default-pythons:/usr/lib/rpm/macros:/etc/rpm/macros.python:/etc/rpm/macros.python3 \ + --macros=$MYPATH/macros.python_all:/usr/lib/rpm/macros:/etc/rpm/macros.python2:/etc/rpm/macros.python3 \ -P "$1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/compile-macros.sh new/python-rpm-macros-1.0.git.1489505194.b32e02a/compile-macros.sh --- old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/compile-macros.sh 2017-02-23 18:01:11.000000000 +0100 +++ new/python-rpm-macros-1.0.git.1489505194.b32e02a/compile-macros.sh 2017-03-14 16:26:34.000000000 +0100 @@ -19,7 +19,7 @@ if echo "$line" | grep -q '^function '; then # entering top-level Lua function INFUNC=1; - echo "$line" | sed -r -e 's/^function (.*)\(\)$/%\1() %{lua: \\/' + echo "$line" | sed -r -e 's/^function (.*)\((.*)\)$/%\1(\2) %{lua: \\/' elif [ "$line" == "end" ]; then # leaving top-level Lua function INFUNC=0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/flavor.in new/python-rpm-macros-1.0.git.1489505194.b32e02a/flavor.in --- old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/flavor.in 2017-02-23 18:01:11.000000000 +0100 +++ new/python-rpm-macros-1.0.git.1489505194.b32e02a/flavor.in 2017-03-14 16:26:34.000000000 +0100 @@ -20,13 +20,14 @@ %__#FLAVOR# %{py_setup} %{?py_setup_args} install \\\ -O1 --skip-build --root %{buildroot} --prefix %{_prefix} -%#FLAVOR#_alternative() \ -%{alternative_for} \ -%{_python_alternative_origin -b %#FLAVOR#_bin_suffix} \ -%{nil} +%#FLAVOR#_alternative() %_python_define_install_alternative \ +%{lua:local link, name, path = python_alternative_names(rpm.expand("%1"), rpm.expand("%#FLAVOR#_bin_suffix")) \ +print(rpm.expand("%ghost %{_sysconfdir}/alternatives/" .. name .. "\\\n")) \ +print(link .. "\\\n") \ +print(path .. "\\\n") } -%#FLAVOR#_install_alternative() \ -%{install_alternative -n %1 -t %{_bindir}/%1-%#FLAVOR#_bin_suffix -p %#FLAVOR#_version_nodots} +%#FLAVOR#_install_alternative() %_python_define_install_alternative \ +%{lua:python_install_alternative("#FLAVOR#")} %#FLAVOR#_uninstall_alternative() \ %{uninstall_alternative -n %1 -t %{_bindir}/%1-%#FLAVOR#_bin_suffix} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/macros/001-alternatives new/python-rpm-macros-1.0.git.1489505194.b32e02a/macros/001-alternatives --- old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/macros/001-alternatives 2017-02-23 18:01:11.000000000 +0100 +++ new/python-rpm-macros-1.0.git.1489505194.b32e02a/macros/001-alternatives 2017-03-14 16:26:34.000000000 +0100 @@ -1,6 +1,11 @@ %prepare_alternative(t:) \ %define alternative_target %{-t:%{-t*}}%{!-t:%{_bindir}/%1} \ rm -f %{buildroot}%{alternative_target} \ +alternative_target="%{alternative_target}" \ +if [[ "$alternative_target" == %{_mandir}* ]]; then \ + rm -f %{buildroot}${alternative_target%%%%%{ext_man}} \ + rm -f %{buildroot}%{alternative_target}%{ext_man} \ +fi \ mkdir -p %{buildroot}%{_sysconfdir}/alternatives \ touch %{buildroot}%{_sysconfdir}/alternatives/%1 \ ln -sf %{_sysconfdir}/alternatives/%1 %{buildroot}%{alternative_target} \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/macros/010-common-defs new/python-rpm-macros-1.0.git.1489505194.b32e02a/macros/010-common-defs --- old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/macros/010-common-defs 2017-02-23 18:01:11.000000000 +0100 +++ new/python-rpm-macros-1.0.git.1489505194.b32e02a/macros/010-common-defs 2017-03-14 16:26:34.000000000 +0100 @@ -23,22 +23,17 @@ %python_version_nodots %python2_version_nodots %python_prefix %python2_prefix -# I am honestly not quite sure how the following works. By all logic it should not. -# I suppose that the macro body is copied here and applied on the `%1`? -%python_alternative() %{expand:%python2_alternative} -%python_install_alternative() %{expand:%python2_install_alternative} -%python_uninstall_alternative() %{expand:%python2_uninstall_alternative} +%python_bin_suffix %python2_bin_suffix -%py_ver %python_version +%_rec_macro_helper %{lua: + rpm.define("_rec_macro_helper %{nil}") + function recurse_macro(name) + local aa = rpm.expand("%**") + print(rpm.expand("%{" .. name .. " " .. aa .."}")) + end} -##### common code for alternative name creation ##### -%_python_alternative_origin(b:) %{lua: do \ - local param = rpm.expand("%1") \ - local binsuffix = rpm.expand("%{-b*}") \ - -- try manpage syntax \ - local try = param:gsub("(.*)%.(%d)%.gz$", "%1-" .. binsuffix .. ".%2.gz") \ - -- append binsuffix - if try == param then try = param .. "-" .. binsuffix end \ - print(try) \ -end } +%python_alternative() %{_rec_macro_helper}%{lua:recurse_macro("python2_alternative")} +%python_install_alternative() %{_rec_macro_helper}%{lua:recurse_macro("python2_install_alternative")} +%python_uninstall_alternative() %{_rec_macro_helper}%{lua:recurse_macro("python2_uninstall_alternative")} +%py_ver %python_version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/macros.lua new/python-rpm-macros-1.0.git.1489505194.b32e02a/macros.lua --- old/python-rpm-macros-1.0.git.1487869271.c6e9bfc/macros.lua 2017-02-23 18:01:11.000000000 +0100 +++ new/python-rpm-macros-1.0.git.1489505194.b32e02a/macros.lua 2017-03-14 16:26:34.000000000 +0100 @@ -11,11 +11,19 @@ -- declare common functions function string.startswith(str, prefix) - return str:find(prefix) == 1 + return str:sub(1, prefix:len()) == prefix end function string.endswith(str, suffix) - return suffix == str:sub(-suffix:len()) + return str:sub(-suffix:len()) == suffix + end + + function string.basename(str) + while true do + local idx = str:find("/") + if not idx then return str end + str = str:sub(idx + 1) + end end function lookup_table(tbl) @@ -75,7 +83,7 @@ function pkgname_from_param(param) if param == modname then return "" - elseif param:startswith(modname .. "%-") then + elseif param:startswith(modname .. "-") then return param:sub(modname:len() + 2) else return "-n " .. param @@ -155,6 +163,8 @@ end function _python_emit_subpackages() + _python_subpackages_emitted = true + -- line processing functions local function print_altered(line) -- set %name macro to proper flavor-name @@ -165,27 +175,75 @@ local function ignore_line(line) end - local PROPERTY_COPY_UNMODIFIED = lookup_table { "Summary", "Version", "BuildArch" } + local PROPERTY_COPY_UNMODIFIED = lookup_table { "Summary:", "Version:", "BuildArch:" } local PROPERTY_COPY_MODIFIED = lookup_table { - "Requires", "Provides", - "Recommends", "Suggests", - "Conflicts", "Obsoletes", + "Requires:", "Provides:", + "Recommends:", "Suggests:", + "Conflicts:", "Obsoletes:", + "Supplements:", "Enhances:", + "%requires_eq", "%requires_ge", + "Requires(pre):", "Requires(preun):", "Requires(post):", "Requires(postun):", + "Requires(pretrans):", "Requires(posttrans):", } local function process_package_line(line) + -- This function processes lines like "Requires: something something". + -- "Requires: python-foo" -> "Requires: python3-foo" + -- "Requires: %{name} = %{version}" -> "Requires: python3-modname = %{version}" + -- "Supplements: packageand(python-a:python-b)" -> "Supplements: packageand(python3-a:python3-b)" + -- you get the idea. -- TODO implement %$flavor_only support here? - local property, value = line:match("^([A-Z]%S-):%s*(.*)$") + + -- first split Property: value + local property, value = line:match("^([A-Z%%]%S+)%s*(.*)$") + + -- "python-foo" -> "python3-foo" + local function rename_package(package, flavor) + if package == "python" or package == flavor then + -- specialcase plain "python" + package = current_flavor + else + package = package:gsub("^" .. flavor .. "(%W)", current_flavor .. "%1") + package = package:gsub("^python(%W)", current_flavor .. "%1") + end + return package + end + + -- split and rewrite "packageand(a:b:c)", using rename_package() for each of a, b, c + local function fix_packageand(packageand, flavor) + local inner = packageand:match("^packageand%((.*)%)$") + if not inner then return packageand end + local eat = inner + local result = "packageand(" + while eat do + local idx = eat:find(":") + local n = "" + if idx then + n = eat:sub(1, idx) + eat = eat:sub(idx+1) + else + n = eat + eat = nil + end + n = n:gsub("^%s*", "") + result = result .. rename_package(n, flavor) + end + return result .. ")" + end + if PROPERTY_COPY_UNMODIFIED[property] then print_altered(line) elseif PROPERTY_COPY_MODIFIED[property] then - if value == "python" or value == flavor then - value = current_flavor + -- specifically handle %name macro before expansion + line = line:gsub("%%{?name}?", current_flavor .. "-" .. modname) + -- convert value using the appropriate function + if value:startswith("packageand") then + value = fix_packageand(value, flavor) else - value = value:gsub("^" .. flavor .. "(%W)", current_flavor .. "%1") - value = value:gsub("^python(%W)", current_flavor .. "%1") + value = rename_package(value, flavor) end - local expanded = rpm.expand(value) - print_altered(string.format("%s: %s", property, expanded)) + -- rely on print_altered to perform expansion on the result + print_altered(string.format("%s %s", property, value)) end end -- end line processing functions @@ -220,7 +278,6 @@ return "%files -n " .. package_name(flavor, modname, mymodname, append) .. "\n" end - local function section_headline(section, flavor, param) if section == "files" then return files_headline(flavor, param) @@ -229,6 +286,16 @@ end end + local function match_braces(line) + local count = 0 + for c in line:gmatch(".") do + if c == "{" then count = count + 1 + elseif c == "}" and count > 0 then count = count - 1 + end + end + return count == 0 + end + local KNOWN_SECTIONS = lookup_table {"package", "description", "files", "prep", "build", "install", "check", "clean", "pre", "post", "preun", "postun", "pretrans", "posttrans", "changelog"} @@ -262,9 +329,17 @@ print_obsoletes(modname) while true do - line = spec:read() - --io.stderr:write(current_flavor .. " >".. tostring(line) .."<\n") + -- collect lines until braces match. it's what rpm does, kind of. + local eof = false + local line = spec:read() if line == nil then break end + while not match_braces(line) do + local nl = spec:read() + if nl == nil then eof = true break end + line = line .. "\n" .. nl + end + if eof then break end + --io.stderr:write(current_flavor .. " >".. tostring(line) .."<\n") -- match section delimiter local section_noparam = line:match("^%%(%S+)(%s*)$") @@ -273,7 +348,7 @@ if KNOWN_SECTIONS[newsection] then -- enter new section - if param and param:startswith("%-n") then + if param and param:startswith("-n") then -- ignore named section section_function = ignore_line elseif newsection == "package" then @@ -288,9 +363,9 @@ else section_function = ignore_line end - elseif line:startswith("%%python_subpackages") then + elseif line:startswith("%python_subpackages") then -- ignore - elseif line:startswith("%%if") then + elseif line:startswith("%if") then -- RPM handles %if on top level, whole sections can be conditional. -- We must copy the %if declarations always, even if they are part -- of non-copied sections. Otherwise we miss this: @@ -305,7 +380,7 @@ -- macros like %ifpython3 are evaluated differently in the top-level spec -- itself and in the copied sections. --io.stderr:write(rpm.expand(line) .. "\n") - elseif line:startswith("%%else") or line:startswith("%%endif") then + elseif line:startswith("%else") or line:startswith("%endif") then print(line .. "\n") --io.stderr:write(line .. "\n") else @@ -339,12 +414,14 @@ end function python_build() + rpm.expand("%_python_scan_spec") for _, python in ipairs(pythons) do print(rpm.expand("%" .. python .. "_build %**")) end end function python_install() + rpm.expand("%_python_scan_spec") for _, python in ipairs(pythons) do print(rpm.expand("%" .. python .. "_install %**")) end @@ -357,10 +434,93 @@ -- for "re" command, all these things are nil because scan_spec doesn't seem to run? -- checking for validity of python_files_flavor seems to fix this. - if python_files_flavor and python_files_flavor ~= "" then + if _python_subpackages_emitted + and python_files_flavor and python_files_flavor ~= "" then print("-n " .. package_name(python_files_flavor, modname, param)) current_flavor = python_files_flavor else print(param) end end + +function python_clone(a) + rpm.expand("%_python_scan_spec") + rpm.expand("%_python_define_install_alternative") + local param = rpm.expand("%1") + local link, name, path + for _, python in ipairs(pythons) do + local binsuffix = rpm.expand("%" .. python .. "_bin_suffix") + link,name,path = python_alternative_names(param, binsuffix, true) + print(rpm.expand(string.format("cp %s %s\n", param, path))) + print(rpm.expand(string.format("sed -ri '1s@#!.*python.*@#!/usr/bin/%s@' %s\n", python, path))) + end + + -- %python_clone -a + if rpm.expand("%{?-a}") == "-a" then + local buildroot = rpm.expand("%{buildroot}") + if link:startswith(buildroot) then link = link:sub(buildroot:len() + 1) end + print(rpm.expand(string.format("%%{prepare_alternative -t %s %s}\n", link, name))) + end +end + +function _python_define_install_alternative() + rpm.define("_python_define_install_alternative %{nil}") + bindir = rpm.expand("%{_bindir}") + mandir = rpm.expand("%{_mandir}") + ext_man = rpm.expand("%{ext_man}") + if ext_man == "" then + ext_man_expr = "%.%d$" + else + -- ASSUMPTION: ext_man:startswith(".") + ext_man_expr = "%.%d%" .. ext_man .. "$" + end + + function python_alternative_names(arg, binsuffix, keep_path_unmangled) + local link, name, path + name = arg:basename() + local man_ending = arg:match(ext_man_expr) or arg:match("%.%d$") + if arg:startswith("/") then + link = arg + elseif man_ending then + link = mandir .. "/man" .. man_ending:sub(2,2) .. "/" .. arg + else + link = bindir .. "/" .. arg + end + if man_ending then + path = link:sub(1, -man_ending:len()-1) .. "-" .. binsuffix .. man_ending + else + path = link .. "-" .. binsuffix + end + + -- now is the time to append ext_man if appropriate + -- "link" and "name" get ext_man always + if ext_man ~= "" and man_ending and not arg:endswith(ext_man) then + link = link .. ext_man + name = name .. ext_man + if not keep_path_unmangled then path = path .. ext_man end + end + return link, name, path + end + + function python_install_alternative(flavor) + local prio = rpm.expand("%" .. flavor .. "_version_nodots") + local binsuffix = rpm.expand("%" .. flavor .. "_bin_suffix") + + local params = {} + for p in string.gmatch(rpm.expand("%*"), "%S+") do + table.insert(params, p) + end + + if #params == 0 then + print("error") + return + end + + local link, name, path = python_alternative_names(params[1], binsuffix) + print(string.format("update-alternatives --install %s %s %s %s", link, name, path, prio)) + table.remove(params, 1) + for _, v in ipairs(params) do + print(string.format(" \\\n --slave %s %s %s", python_alternative_names(v, binsuffix))) + end + end +end
