From fa2127cde48738447fb8697cfe224f63924b354b Mon Sep 17 00:00:00 2001
From: Anders Blomdell <anders.blomdell@gmail.com>
Date: Mon, 11 Jan 2021 18:25:49 +0100
Subject: [PATCH] Implement auto filtering of Cargo.toml

---
 filter-toml.py      | 141 ++++++++++++++++++++++++++++++++++++++++++++
 make-srpms          |  39 ++++++++++++
 rust-package-dir.sh |  36 -----------
 rust-package.sh     |  40 -------------
 4 files changed, 180 insertions(+), 76 deletions(-)
 create mode 100755 filter-toml.py
 create mode 100755 make-srpms
 delete mode 100755 rust-package-dir.sh
 delete mode 100755 rust-package.sh

diff --git a/filter-toml.py b/filter-toml.py
new file mode 100755
index 0000000..8d0f353
--- /dev/null
+++ b/filter-toml.py
@@ -0,0 +1,141 @@
+#!/usr/bin/python3
+
+import sys
+import re
+import subprocess
+from  pyparsing import Keyword, QuotedString, Suppress, Regex, OneOrMore
+from pyparsing import Forward, Group, Dict, delimitedList
+from  pyparsing import lineno
+
+class Cfg:
+
+    def __init__(self):
+        self.cfg = {}
+        def cfg(s):
+            m = re.match('([^=]+)(?:="(.*)")?', s)
+            return m.group(1), m.group(2) or True
+        self.cfg = dict([ cfg(l) for l
+                         in subprocess.check_output(
+                             [ 'rustc', '--print=cfg'],
+                             encoding='utf8').splitlines() ])
+        pass
+
+    def compare(self, key, value):
+        if key in self.cfg:
+            return value == self.cfg[key]
+        return False
+
+    pass
+
+cfg = Cfg()
+
+"""
+https://doc.rust-lang.org/reference/conditional-compilation.html
+
+ConfigurationPredicate :
+     ConfigurationOption
+   | ConfigurationAll
+   | ConfigurationAny
+   | ConfigurationNot
+
+ConfigurationOption :
+   IDENTIFIER (= (STRING_LITERAL | RAW_STRING_LITERAL))?
+
+ConfigurationAll
+   all ( ConfigurationPredicateList? )
+
+ConfigurationAny
+   any ( ConfigurationPredicateList? )
+
+ConfigurationNot
+   not ( ConfigurationPredicate )
+
+ConfigurationPredicateList
+   ConfigurationPredicate (, ConfigurationPredicate)* ,?
+"""
+
+_predicate_ = Forward()
+
+_all_ = (
+    Suppress(Keyword('all')) +
+    Suppress('(') +
+    delimitedList(_predicate_) +
+    Suppress(')')
+).setParseAction(lambda predicates: set([True]) == set(predicates))
+    
+_any_ = (
+    Suppress(Keyword('any')) +
+    Suppress('(') +
+    delimitedList(_predicate_) +
+    Suppress(')')
+).setParseAction(lambda predicates: True in set(predicates))
+
+_not_ = (
+    Suppress(Keyword('not')) +
+    Suppress('(') +
+    _predicate_ +
+    Suppress(')')
+).setParseAction(lambda predicate: not predicate[0])
+
+_option_ = (
+    (
+        Regex('[A-Za-z_]+') +
+        Suppress('=') +
+        QuotedString('"')
+    ).setParseAction(lambda i_s: cfg.compare(i_s[0], i_s[1])) |
+    (
+        Regex('[A-Za-z_]+')
+    ).setParseAction(lambda i: cfg.compare(i[0], True))
+)
+
+_predicate_ <<= (
+    _all_ |
+    _any_ |
+    _not_ |
+    _option_
+)
+
+_cfg_ = (
+    Suppress(Keyword('cfg')) +
+    Suppress('(') +
+    _predicate_ +
+    Suppress(')')
+)
+
+def evaluate_cfg(s):
+    result = _cfg_.parseString(s.replace('\\', ''))
+    return result[0]
+    
+def filter_dependencies(f):
+    result = []
+    suppress = False
+    for l in f.split('\n'):
+        if m := re.match(r'^\[target\.(.)(cfg\(.*)\1\.dependencies\.', l):
+            cfg = m.group(2).replace('\\', '')
+            suppress = not evaluate_cfg(cfg)
+            pass
+        elif l.startswith('['):
+            suppress = False
+            pass
+        if not suppress:
+            result.append(l)
+            pass
+        else:
+            print("# Suppress", l, file=sys.stderr)
+            pass
+        pass
+    return '\n'.join(result)
+    pass
+
+if __name__ == '__main__':
+    for p in sys.argv[1:]:
+        old = open(p).read()
+        new = filter_dependencies(old)
+        if old != new:
+            print("# ", p, file=sys.stderr)
+            with open(p, 'w') as f:
+                f.write(new)
+                pass
+            pass
+        pass
+    pass
diff --git a/make-srpms b/make-srpms
new file mode 100755
index 0000000..3825458
--- /dev/null
+++ b/make-srpms
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+set -e
+
+DEFAULT_TARGET=$(eval $(rustc --print cfg | grep target) ; \
+                 echo $target_arch-$target_vendor-$target_os-$target_env)
+
+export EDITOR=$(realpath $(dirname $0)/filter-toml.py)
+#export TMPDIR=$(mktemp -d /var/tmp/make-srpms-XXXXXX)
+export TMPDIR=/var/tmp/make-srpms
+export PROJECTDIR=$(realpath .)
+export RPMDIR=${PROJECTDIR}/rpms
+export CARGO_HOME=${TMPDIR}/cargo
+mkdir -p "${RPMDIR}"
+
+# Fetch dependencies and build SRPMS
+cargo fetch --target ${DEFAULT_TARGET}
+cargo package
+cd ${TMPDIR}
+for crate in $(find "${CARGO_HOME}" \
+                    "${PROJECTDIR}/target/package" -name '*.crate') ; do
+    if [[ "$(basename ${crate})" =~ ^(.*)-([^-]*)$ ]] ; then
+        set -x
+        NAME=${BASH_REMATCH[1]}
+        VERSION=${BASH_REMATCH[2]}
+        rust2rpm --target fedora \
+                 --patch \
+                 --store-crate \
+                 --no-dynamic-buildrequires \
+                 ${crate}
+        sed -i -re 's/(BuildRequires:\s*)\((crate[\(][^\)]+\)).*/&\n\1\2/' \
+            "${TMPDIR}/rust-${NAME}.spec"
+       rpmbuild -bs \
+                 --define "_sourcedir ${TMPDIR}" \
+                 --define "_srcrpmdir ${TMPDIR}" \
+                 "${TMPDIR}/rust-${NAME}.spec"
+    fi
+done
+mv ${TMPDIR}/*.src.rpm ${RPMDIR}/
diff --git a/rust-package-dir.sh b/rust-package-dir.sh
deleted file mode 100755
index 413a77e..0000000
--- a/rust-package-dir.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-set -e
-set -x
-
-post_package() {
-    if [ -x post-package-$1-$2 ] ; then
-        $(realpath post-package-$1-$2) $3
-    elif [ -x post-package-$1 ] ; then
-       $(realpath post-package-$1) $3
-    elif [ -x post-package ] ; then
-        $(realpath post-package) $3
-    fi
-}
-
-CACHE=${HOME}/.cache/rust2rpm
-cargo package
-mkdir -p ${CACHE}
-for f in $(pwd)/target/package/*.crate ; do
-    echo $f
-    SYMLINK=${CACHE}/$(basename "$f")
-    if [ -L "${SYMLINK}" ] ; then
-        rm -f "${SYMLINK}"
-    fi
-    ln -s "$f" "${SYMLINK}"
-    if [[ "$(basename "$f")" =~ (.*)-(.*).crate ]] ; then
-        NAME=${BASH_REMATCH[1]}
-        VERSION=${BASH_REMATCH[2]}
-        SPEC=rust-${NAME}-${VERSION}.spec
-        rust2rpm -t plain --stdout ${NAME} ${VERSION} > ${SPEC}
-        sed -i -re 's/(BuildRequires:\s*)\((crate[\(][^\)]+\)).*/&\n\1\2/' \
-            ${SPEC}
-        post_package ${NAME} ${VERSION} ${SPEC}
-        rpmbuild -bs ${SPEC} -D'_sourcedir target/package/.' -D'_srcrpmdir .'
-    fi
-done
diff --git a/rust-package.sh b/rust-package.sh
deleted file mode 100755
index a3c62d9..0000000
--- a/rust-package.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-
-set -e
-
-TARGET="-t plain"
-
-POSITIONAL=()
-while [ $# -gt 0 ] ; do
-    case $1 in
-        -p|--patch)
-            PATCH="$1"
-            shift
-            ;;
-        -t|--target)
-            TARGET="$1 $2"
-            shift
-            shift
-            ;;
-        *)    # unknown option
-            POSITIONAL+=("$1")
-            shift # past argument
-            ;;
-    esac
-done
-set -- "${POSITIONAL[@]}" # restore positional parameters
-NAME=${POSITIONAL[0]}
-
-rust2rpm ${PATCH} ${TARGET} ${POSITIONAL[@]}
-sed -i -re 's/(BuildRequires:\s*)\((crate[\(][^\)]+\)).*/&\n\1\2/' \
-    rust-${NAME}.spec
-DOWNLOAD=$(rpmspec -P rust-${NAME}.spec \
-               | grep Source0 \
-               | sed -re 's/^Source0:\s+(.*)$/\1/')
-curl -L ${DOWNLOAD} > ${HOME}/rpmbuild/SOURCES/$(basename ${DOWNLOAD})
-if [ -n "${PATCH}" ] ; then
-    DIFF=$(basename ${DOWNLOAD} | sed -e 's/.crate//')-fix-metadata.diff
-    cp ${DIFF} ${HOME}/rpmbuild/SOURCES/
-fi
-rpmbuild -bb rust-${NAME}.spec
-rpmbuild -bs rust-${NAME}.spec
-- 
GitLab