]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- use C++11 regexes instead of own regcomp/regexec wrapper class
authorArvin Schnell <aschnell@suse.de>
Wed, 18 Nov 2020 11:59:25 +0000 (12:59 +0100)
committerArvin Schnell <aschnell@suse.de>
Wed, 18 Nov 2020 11:59:25 +0000 (12:59 +0100)
23 files changed:
LIBVERSION
package/snapper.changes
snapper/AsciiFile.cc
snapper/AsciiFile.h
snapper/Btrfs.cc
snapper/Lvm.cc
snapper/Lvm.h
snapper/LvmUtils.cc
snapper/Regex.cc
snapper/Regex.h
snapper/Snapper.cc
snapper/SnapperDefines.h
snapper/SnapperTypes.h
snapper/Snapshot.cc
testsuite/sysconfig-get1.cc
testsuite/sysconfig-get1.txt
zypp-plugin/Makefile.am
zypp-plugin/regex_test.cc [deleted file]
zypp-plugin/snapper_zypp_plugin.cc
zypp-plugin/solvable_matcher.cc
zypp-plugin/solvable_matcher.h
zypp-plugin/solvable_matcher_test.cc [new file with mode: 0644]
zypp-plugin/zypp_plugin.cc

index 831446cbd27a6de403344b21c9fa93a25357f43d..91ff57278e37ef9cecfeaea47f0d77966799af28 100644 (file)
@@ -1 +1 @@
-5.1.0
+5.2.0
index 2b0fba158f6d4791c2545a71af10f45f84579c1d..81113b41f4ad7e755cd2688d1dd718b3211fdb05 100644 (file)
@@ -1,3 +1,9 @@
+-------------------------------------------------------------------
+Wed Nov 18 12:13:56 CET 2020 - aschnell@suse.com
+
+- use C++11 regexes instead of own regcomp/regexec wrapper class
+  (see gh#openSUSE/snapper#583)
+
 -------------------------------------------------------------------
 Tue Sep 22 09:17:28 CEST 2020 - aschnell@suse.com
 
index 1ee9788cbe69350b615ff7af0b30a28a5997fc88..bc141d4d19dc065c3b509b85a1553aab541277b0 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2004-2015] Novell, Inc.
+ * Copyright (c) 2020 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -22,6 +23,7 @@
 
 #include <unistd.h>
 #include <fstream>
+#include <regex>
 
 #include "snapper/Log.h"
 #include "snapper/AppUtil.h"
@@ -36,9 +38,9 @@ namespace snapper
 
 
     AsciiFileReader::AsciiFileReader(int fd)
-       : file(fdopen(fd, "r")), buffer(NULL), len(0)
+       : file(fdopen(fd, "r"))
     {
-       if (file == NULL)
+       if (!file)
        {
            y2war("file is NULL");
            SN_THROW(FileNotFoundException());
@@ -47,9 +49,9 @@ namespace snapper
 
 
     AsciiFileReader::AsciiFileReader(FILE* file)
-       : file(file), buffer(NULL), len(0)
+       : file(file)
     {
-       if (file == NULL)
+       if (!file)
        {
            y2war("file is NULL");
            SN_THROW(FileNotFoundException());
@@ -58,10 +60,9 @@ namespace snapper
 
 
     AsciiFileReader::AsciiFileReader(const string& filename)
-       : file(NULL), buffer(NULL), len(0)
+       : file(fopen(filename.c_str(), "re"))
     {
-       file = fopen(filename.c_str(), "re");
-       if (file == NULL)
+       if (!file)
        {
            y2war("open for '" << filename << "' failed");
            SN_THROW(FileNotFoundException());
@@ -171,9 +172,9 @@ AsciiFile::save()
     void
     SysconfigFile::checkKey(const string& key) const
     {
-       Regex rx("^" "([0-9A-Z_]+)" "$");
+       static const regex rx("([0-9A-Z_]+)", regex::extended);
 
-       if (!rx.match(key))
+       if (!regex_match(key, rx))
            SN_THROW(InvalidKeyException());
     }
 
@@ -209,39 +210,41 @@ AsciiFile::save()
     {
        checkKey(key);
 
-       Regex rx('^' + Regex::ws +
-                 key + '=' + "(['\"]?)([^'\"]*)\\1" +
-                 '(' + Regex::ws + Regex::trailing_comment + ")$");
+       modified = true;
 
-       vector<string>::iterator it = find_if(lines(), regex_matches(rx));
-       if (it == lines().end())
-       {
-           string line = key + "=\"" + value + "\"";
-           push_back(line);
-       }
-       else
+       for (vector<string>::iterator it = Lines_C.begin(); it != Lines_C.end(); ++it)
        {
-           string line = key + "=\"" + value + "\"" + rx.cap(3);
-           *it = line;
+           ParsedLine parsed_line;
+
+           if (parse_line(*it, parsed_line) && parsed_line.key == key)
+           {
+               string line = key + "=\"" + value + "\"" + parsed_line.comment;
+               *it = line;
+               return;
+           }
        }
 
-       modified = true;
+       string line = key + "=\"" + value + "\"";
+       push_back(line);
     }
 
 
     bool
     SysconfigFile::getValue(const string& key, string& value) const
     {
-        Regex rx('^' + Regex::ws +
-                 key + '=' + "(['\"]?)([^'\"]*)\\1" +
-                 Regex::ws + Regex::trailing_comment + '$');
+       for (const string& line : Lines_C)
+       {
+           ParsedLine parsed_line;
 
-       if (find_if(lines(), regex_matches(rx)) == lines().end())
-           return false;
+           if (parse_line(line, parsed_line) && parsed_line.key == key)
+           {
+               value = parsed_line.value;
+               y2mil("key:" << key << " value:" << value);
+               return true;
+           }
+       }
 
-       value = rx.cap(2);
-       y2mil("key:" << key << " value:" << value);
-       return true;
+       return false;
     }
 
 
@@ -303,17 +306,47 @@ AsciiFile::save()
     {
        map<string, string> ret;
 
-       Regex rx('^' + Regex::ws +
-                 "([0-9A-Z_]+)" + '=' + "(['\"]?)([^'\"]*)\\2" +
-                 Regex::ws + Regex::trailing_comment + '$');
-
-       for (vector<string>::const_iterator it = Lines_C.begin(); it != Lines_C.end(); ++it)
+       for (const string& line : Lines_C)
        {
-           if (rx.match(*it))
-               ret[rx.cap(1)] = rx.cap(3);
+           ParsedLine parsed_line;
+
+           if (parse_line(line, parsed_line))
+               ret[parsed_line.key] = parsed_line.value;
        }
 
        return ret;
     }
 
+
+    bool
+    SysconfigFile::parse_line(const string& line, ParsedLine& parsed_line) const
+    {
+       const string whitespace = "[ \t]*";
+       const string comment = "(#.*)?";
+
+       // Note: Avoid back references. Whether they work depend on the regex flags. Also
+       // the old regcomp/regexec based implementation did not work with them with some
+       // libc implementations.
+
+       static const regex rx1(whitespace + "([0-9A-Z_]+)" + '=' + "\"([^\"]*)\"" +
+                              '(' + whitespace + comment + ")");
+
+       static const regex rx2(whitespace + "([0-9A-Z_]+)" + '=' + "'([^']*)'" +
+                              '(' + whitespace + comment + ")");
+
+       static const regex rx3(whitespace + "([0-9A-Z_]+)" + '=' + "([^ \t]*)" +
+                              '(' + whitespace + comment + ")");
+
+       smatch match;
+
+       if (!regex_match(line, match, rx1) && !regex_match(line, match, rx2) && !regex_match(line, match, rx3))
+           return false;
+
+       parsed_line.key = match[1];
+       parsed_line.value = match[2];
+       parsed_line.comment = match[3];
+
+       return true;
+    }
+
 }
index 63e0abb31486a9e71216a4db971709419ffbbcfd..218f92e9833c68f786ac233449fb0ecc544d991e 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2004-2015] Novell, Inc.
+ * Copyright (c) 2020 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -51,9 +52,9 @@ namespace snapper
 
     private:
 
-       FILE* file;
-       char* buffer;
-       size_t len;
+       FILE* file = nullptr;
+       char* buffer = nullptr;
+       size_t len = 0;
 
     };
 
@@ -127,6 +128,15 @@ namespace snapper
 
        bool modified;
 
+       struct ParsedLine
+       {
+           string key;
+           string value;
+           string comment;
+       };
+
+       bool parse_line(const string& line, ParsedLine& parsed_line) const;
+
     };
 
 }
index 69362974efef08ec4ffae6e0dac63902892ee952..0ec9dde1fefbdaef62a3b3e61bc3182b754e5ac3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
- * Copyright (c) [2016-2018] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -44,6 +44,7 @@
 #include <boost/version.hpp>
 #include <boost/thread.hpp>
 #endif
+#include <regex>
 #include <boost/algorithm/string.hpp>
 
 #include "snapper/Log.h"
@@ -55,7 +56,6 @@
 #include "snapper/SnapperDefines.h"
 #include "snapper/Acls.h"
 #include "snapper/Exception.h"
-#include "snapper/Regex.h"
 #ifdef ENABLE_ROLLBACK
 #include "snapper/MntTable.h"
 #endif
@@ -1473,11 +1473,13 @@ namespace snapper
     {
        string path = get_subvolume(fd, id);
 
-       Regex rx("/([0-9]+)/snapshot$");
-       if (!rx.match(path))
+       static const regex rx("/([0-9]+)/snapshot$", regex::extended);
+       smatch match;
+
+       if (!regex_search(path, match, rx))
            return make_pair(false, 0);
 
-       unsigned int num = stoi(rx.cap(1));
+       unsigned int num = stoi(match[1].str());
 
        if (!checkSnapshot(num))
            return make_pair(false, 0);
index 2a452707f327ee4305d2a4deb7bc77411434475c..cb829aac3d91195fd3deae501cd3108f44beb671 100644 (file)
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <asm/types.h>
+#include <regex>
 #include <boost/algorithm/string.hpp>
 
 #include "snapper/Log.h"
@@ -41,7 +42,6 @@
 #include "snapper/SnapperTmpl.h"
 #include "snapper/SystemCmd.h"
 #include "snapper/SnapperDefines.h"
-#include "snapper/Regex.h"
 #include "snapper/LvmCache.h"
 #ifdef ENABLE_SELINUX
 #include "snapper/Selinux.h"
@@ -56,9 +56,11 @@ namespace snapper
     Filesystem*
     Lvm::create(const string& fstype, const string& subvolume, const string& root_prefix)
     {
-       Regex rx("^lvm\\(([_a-z0-9]+)\\)$");
-       if (rx.match(fstype))
-           return new Lvm(subvolume, root_prefix, rx.cap(1));
+       static const regex rx("lvm\\(([_a-z0-9]+)\\)", regex::extended);
+       smatch match;
+
+       if (regex_match(fstype, match, rx))
+           return new Lvm(subvolume, root_prefix, match[1]);
 
        return NULL;
     }
@@ -421,7 +423,7 @@ namespace snapper
     string
     Lvm::getDevice(unsigned int num) const
     {
-       return "/dev/mapper/" + boost::replace_all_copy(vg_name, "-", "--") + "-" +
+       return DEV_MAPPER_DIR "/" + boost::replace_all_copy(vg_name, "-", "--") + "-" +
            boost::replace_all_copy(snapshotLvName(num), "-", "--");
     }
 
@@ -474,9 +476,11 @@ namespace snapper
        }
        else
        {
-           Regex rx(".*LVM[[:space:]]+version:[[:space:]]+([0-9]+)\\.([0-9]+)\\.([0-9]+).*$");
+           static const regex rx(".*LVM[[:space:]]+version:[[:space:]]+([0-9]+)\\.([0-9]+)\\.([0-9]+).*$",
+                                 regex::extended);
+           smatch match;
 
-           if (!rx.match(cmd.get_stdout().front()))
+           if (!regex_search(cmd.get_stdout().front(), match, rx))
            {
                y2war("LVM version format didn't match");
            }
@@ -484,9 +488,9 @@ namespace snapper
            {
                uint16_t maj, min, rev;
 
-               rx.cap(1) >> maj;
-               rx.cap(2) >> min;
-               rx.cap(3) >> rev;
+               match[1] >> maj;
+               match[2] >> min;
+               match[3] >> rev;
 
                lvm_version version(maj, min, rev);
 
index ea86bd72c6d5acbd2a76445481db7402469d9ff9..ff9a56699d6905907661f45ea5abf722ca991ce3 100644 (file)
@@ -71,7 +71,7 @@ namespace snapper
        // empty or " -K" if lvm supports ignore activation skip flag
        string ignoreactivationskip;
        // true if lvm2 supports time info stored in metadata
-       bool time_support;
+       bool time_support = false;
     };
 
     class SelinuxLabelHandle;
index 47e769544db85302b3f431a30bb5637a5a097841..b8589f8c24d409524cd2a2172deee92ab5ac7e5d 100644 (file)
  */
 
 
+#include <regex>
 #include <boost/algorithm/string.hpp>
 
 #include "snapper/LvmUtils.h"
-#include "snapper/Regex.h"
-#include "snapper/AppUtil.h"
+#include "snapper/SnapperDefines.h"
 
 
 namespace snapper
@@ -37,16 +37,19 @@ namespace snapper
        pair<string, string>
        split_device_name(const string& name)
        {
-           Regex rx("^/dev/mapper/(.*[^-])-([^-].*)$");
-           if (!rx.match(name))
+           static const std::regex rx(DEV_MAPPER_DIR "/(.*[^-])-([^-].*)", std::regex::extended);
+           std::smatch match;
+
+           if (!regex_match(name, match, rx))
                throw std::runtime_error("faild to split device name into volume group and "
                                         "logical volume name");
 
-           string vg_name = boost::replace_all_copy(rx.cap(1), "--", "-");
-           string lv_name = boost::replace_all_copy(rx.cap(2), "--", "-");
+           string vg_name = boost::replace_all_copy(match[1].str(), "--", "-");
+           string lv_name = boost::replace_all_copy(match[2].str(), "--", "-");
 
            return make_pair(vg_name, lv_name);
        }
 
     }
+
 }
index da8f862507f231b80f19afaba41889311ac13c93..26962c1dedaaff6cd908c1e2032fab2e8f23abba 100644 (file)
  * find current contact information at www.novell.com.
  */
 
+
+// This file is obsolete. It is only present for compatibility of libsnapper, esp. the
+// Regex class was used in older versions of the zypp-plugin and we must avoid potentially
+// problems during updates.
+
+
 #include <stdexcept>
 #include "snapper/Regex.h"
 
index 1d32a9eb0acc220897e315ab228c93e312868a31..cd47686532616d95b4ac4eb562f8fa5210f5e333 100644 (file)
  */
 
 
+// This file is obsolete. It is only present for compatibility of libsnapper, esp. the
+// Regex class was used in older versions of the zypp-plugin and we must avoid potentially
+// problems during updates.
+
+
 #ifndef SNAPPER_REGEX_H
 #define SNAPPER_REGEX_H
 
index 6b9f51a2454c332d203a42ed3cf470e65b4bf780..a509880534e0ffdab988d13f3feef0f0fa112630 100644 (file)
@@ -31,6 +31,7 @@
 #include <sys/acl.h>
 #include <acl/libacl.h>
 #include <set>
+#include <regex>
 #include <boost/algorithm/string.hpp>
 
 #include "snapper/Snapper.h"
@@ -49,7 +50,6 @@
 #include "snapper/BtrfsUtils.h"
 #ifdef ENABLE_SELINUX
 #include "snapper/Selinux.h"
-#include "snapper/Regex.h"
 #endif
 
 
@@ -874,8 +874,8 @@ namespace snapper
     Snapper::syncSelinuxContextsInInfosDir(bool skip_snapshot_dir) const
     {
 #ifdef ENABLE_SELINUX
-       Regex rx("^[0-9]+$");
-       Regex rx_filelist("^filelist-[0-9]+.txt$");
+       static const regex rx("[0-9]+", regex::extended);
+       static const regex rx_filelist("filelist-[0-9]+.txt", regex::extended);
 
        y2deb("Syncing Selinux contexts in infos dir");
 
@@ -884,7 +884,7 @@ namespace snapper
        vector<string> infos = infos_dir.entries();
        for (vector<string>::const_iterator it1 = infos.begin(); it1 != infos.end(); ++it1)
        {
-           if (!rx.match(*it1))
+           if (!regex_match(*it1, rx))
                continue;
 
            SDir info_dir(infos_dir, *it1);
@@ -902,7 +902,7 @@ namespace snapper
            vector<string> info_content = info_dir.entries();
            for (vector<string>::const_iterator it2 = info_content.begin(); it2 != info_content.end(); ++it2)
            {
-               if (!rx_filelist.match(*it2))
+               if (!regex_match(*it2, rx_filelist))
                    continue;
 
                SFile fl(info_dir, *it2);
index 133331214519ba2f0b7d432894a194180f2f071b..d03a12223edcb89b46fedb7f9d211c17f84bfc7f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2004-2014] Novell, Inc.
+ * Copyright (c) 2020 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -33,6 +34,9 @@
 
 #define FILTERS_DIR "/etc/snapper/filters"
 
+#define DEV_DIR "/dev"
+#define DEV_MAPPER_DIR "/dev/mapper"
+
 
 // keys from the config files
 
index 6b482ce3e57003bc79a749379cc5c5a2eb43cfec..d1b6d4910cf0df96ab5f95b1d27e436465ae66e6 100644 (file)
@@ -29,8 +29,6 @@
 #include <ostream>
 #include <boost/algorithm/string.hpp>
 
-#include "snapper/Regex.h"
-
 
 namespace snapper
 {
@@ -38,13 +36,6 @@ namespace snapper
     using std::vector;
 
 
-    struct regex_matches
-    {
-       regex_matches(const Regex& t) : val(t) {}
-       bool operator()(const string& s) const { return val.match(s); }
-       const Regex& val;
-    };
-
     struct string_starts_with
     {
        string_starts_with(const string& t) : val(t) {}
index f242d4647807091fcf5d6264d7f20412c5f7af53..288bf26987a9dee22a81163b97749526353c853f 100644 (file)
@@ -30,6 +30,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <string.h>
+#include <regex>
 #include <boost/algorithm/string.hpp>
 
 #include "snapper/Snapshot.h"
@@ -42,7 +43,6 @@
 #include "snapper/SnapperTmpl.h"
 #include "snapper/SnapperDefines.h"
 #include "snapper/Exception.h"
-#include "snapper/Regex.h"
 #include "snapper/Hooks.h"
 
 
@@ -185,14 +185,14 @@ namespace snapper
     void
     Snapshots::read()
     {
-       Regex rx("^[0-9]+$");
+       static const regex rx("[0-9]+", regex::extended);
 
        SDir infos_dir = snapper->openInfosDir();
 
        vector<string> infos = infos_dir.entries();
        for (vector<string>::const_iterator it1 = infos.begin(); it1 != infos.end(); ++it1)
        {
-           if (!rx.match(*it1))
+           if (!regex_match(*it1, rx))
                continue;
 
            try
index 1ec0c73c63506c8741cc1bcd76deedc5b9578052..8fcbaadf5c6a062e919cf48fda6ea1f780b3f7cc 100644 (file)
@@ -19,6 +19,9 @@ BOOST_AUTO_TEST_CASE(sysconfig_get1)
     BOOST_CHECK(s.getValue("S1", tmp_string));
     BOOST_CHECK_EQUAL(tmp_string, "hello");
 
+    BOOST_CHECK(s.getValue("S2", tmp_string));
+    BOOST_CHECK_EQUAL(tmp_string, "hello");
+
     bool tmp_bool;
 
     BOOST_CHECK(s.getValue("B1", tmp_bool));
index 1bd059effbcdf359dd5f84a6e6b218aa54460c9e..fb26e41fe0218ca7001597c7aa53241d1d4bc03d 100644 (file)
@@ -1,5 +1,6 @@
 
 S1="hello"
+S2=hello       # this is a comment
 
 B1="yes"
 B2="no"
index e1cff3fdee460cf21ba55712f61ec4728f7e4958..cdfc38c2c49f3610aafd6462850da601ce072ff6 100644 (file)
@@ -23,7 +23,7 @@ snapper_zypp_plugin_LDADD = \
     ../dbus/libdbus.la \
     $(JSONC_LIBS)
 
-check_PROGRAMS = regex.test forwarding-zypp-plugin
+check_PROGRAMS = solvable_matcher.test forwarding-zypp-plugin
 
 forwarding_zypp_plugin_SOURCES = \
     forwarding_zypp_plugin.cc \
@@ -34,12 +34,12 @@ forwarding_zypp_plugin_LDADD = \
     -lboost_system \
     -lpthread
 
-TESTS = regex.test
+TESTS = solvable_matcher.test
 
-regex_test_SOURCES = regex_test.cc \
+solvable_matcher_test_SOURCES = solvable_matcher_test.cc \
     solvable_matcher.cc solvable_matcher.h
 
-regex_test_LDADD = \
+solvable_matcher_test_LDADD = \
     ../snapper/libsnapper.la \
     $(XML2_LIBS) \
     -lboost_unit_test_framework
diff --git a/zypp-plugin/regex_test.cc b/zypp-plugin/regex_test.cc
deleted file mode 100644 (file)
index 21ffe48..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#define BOOST_TEST_DYN_LINK
-#define BOOST_TEST_MODULE regex
-
-#include <boost/test/unit_test.hpp>
-#include "solvable_matcher.h"
-
-static
-SolvableMatcher rx(const char* regex) {
-    bool is_important = false;
-    return SolvableMatcher(regex, SolvableMatcher::Kind::REGEX, is_important);
-}
-
-BOOST_AUTO_TEST_CASE(regex)
-{
-    BOOST_CHECK(rx("mypkg").match("mypkg"));
-    BOOST_CHECK(!rx("mypkg").match("yourpkg"));
-
-    // substrings don't count
-    BOOST_CHECK(!rx("foo").match("afool"));
-    // prefixes must match
-    BOOST_CHECK(rx("foo").match("fool"));
-    // explicit anchor is OK
-    BOOST_CHECK(rx("^foo").match("foo"));
-    // double anchor is also OK
-    BOOST_CHECK(rx("^^foo").match("foo"));
-    // exclude prefix matches
-    BOOST_CHECK(!rx("foo$").match("foo-devel"));
-
-    SolvableMatcher ror = rx("ruby[.0-9]+-rubygem-active(model|record)");
-    BOOST_CHECK(ror.match("ruby2.5-rubygem-activemodel-5.2"));
-    BOOST_CHECK(ror.match("ruby2.5-rubygem-activerecord-5_1"));
-}
index 7db0e7a87ece001dcb35862b84ac069888312846..238a196cbad366966109d82033dfafb145d2c49f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -31,6 +31,7 @@
 #include <iostream>
 #include <map>
 #include <string>
+#include <regex>
 using namespace std;
 
 #include <json.h>
@@ -40,7 +41,6 @@ using namespace std;
 #endif
 
 #include "dbus/DBusConnection.h"
-#include "snapper/Regex.h"
 #include "snapper/Exception.h"
 using snapper::Exception;
 using snapper::CodeLocation;
@@ -256,14 +256,19 @@ map<string, string> SnapperZyppPlugin::get_userdata(const Message& msg) {
        const string& userdata_s = it->second;
        vector<string> key_values;
        boost::split(key_values, userdata_s, boost::is_any_of(","));
-       for (auto kv: key_values) {
-           static const snapper::Regex rx_keyval("^([^=]*)=(.+)$");
-           if (rx_keyval.match(kv)) {
-               string key = boost::trim_copy(rx_keyval.cap(1));
-               string value = boost::trim_copy(rx_keyval.cap(2));
+       for (auto kv : key_values)
+       {
+           static const regex rx_keyval("([^=]*)=(.+)", regex::extended);
+           smatch match;
+
+           if (regex_match(kv, match, rx_keyval))
+           {
+               string key = boost::trim_copy(match[1].str());
+               string value = boost::trim_copy(match[2].str());
                result[key] = value;
            }
-           else {
+           else
+           {
                cerr << "ERROR:" << "invalid userdata: expecting comma separated key=value pairs" << endl;
            }
        }
index 53cb556173a32fd44329318f7d3864b2eea92125..61a93ec861ce556f6cf541c8c458066f56ff44b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
 #include <iostream>
 #include <vector>
 #include <string>
+#include <regex>
 using namespace std;
 
 // fnmatch
 #include <fnmatch.h>
-#include "snapper/Regex.h"
 #include "snapper/XmlFile.h"
 using namespace snapper;
 
@@ -44,11 +44,19 @@ bool SolvableMatcher::match(const string& solvable) const {
        static const int flags = 0;
        res = fnmatch(pattern.c_str(), solvable.c_str(), flags) == 0;
     }
-    else {
-       // POSIX Extended Regular Expression Syntax
-       // The original Python implementation allows "foo" to match "foo-devel"
-       snapper::Regex rx_pattern("^" + pattern, REG_EXTENDED | REG_NOSUB);
-       res = rx_pattern.match(solvable);
+    else
+    {
+       try
+       {
+           // POSIX Extended Regular Expression Syntax
+           // The original Python implementation allows "foo" to match "foo-devel"
+           const regex rx_pattern("^" + pattern, regex::extended);
+           res = regex_search(solvable, rx_pattern);
+       }
+       catch (const regex_error& e)
+       {
+           throw std::runtime_error(string("Regex compilation error: ") + e.what());
+       }
     }
     log << "DEBUG:" << "-> " << res << endl;
     return res;
index 1da22ce34daacc851f7284a28a88a5d76470c066..b345ed07ab6a524028dc7a2636e9b2c675eacad0 100644 (file)
@@ -33,7 +33,7 @@ struct SolvableMatcher {
     };
     std::string pattern;
     Kind kind;
-    bool important;
+    bool important = false;
 
     static std::ostream& log;
     SolvableMatcher(const std::string& apattern, Kind akind, bool aimportant)
diff --git a/zypp-plugin/solvable_matcher_test.cc b/zypp-plugin/solvable_matcher_test.cc
new file mode 100644 (file)
index 0000000..77cf9c8
--- /dev/null
@@ -0,0 +1,55 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE regex
+
+#include <boost/test/unit_test.hpp>
+#include "solvable_matcher.h"
+
+
+static
+SolvableMatcher make_glob(const char* regex)
+{
+    bool is_important = false;
+    return SolvableMatcher(regex, SolvableMatcher::Kind::GLOB, is_important);
+}
+
+
+BOOST_AUTO_TEST_CASE(glob)
+{
+    BOOST_CHECK(make_glob("glibc").match("glibc"));
+    BOOST_CHECK(!make_glob("glibc").match("libc"));
+    BOOST_CHECK(!make_glob("glibc").match("glibc-locale"));
+
+    BOOST_CHECK(make_glob("glibc*").match("glibc"));
+    BOOST_CHECK(make_glob("glibc*").match("glibc-locale"));
+    BOOST_CHECK(!make_glob("glibc*").match("libc"));
+}
+
+
+static
+SolvableMatcher make_rx(const char* regex)
+{
+    bool is_important = false;
+    return SolvableMatcher(regex, SolvableMatcher::Kind::REGEX, is_important);
+}
+
+
+BOOST_AUTO_TEST_CASE(regex)
+{
+    BOOST_CHECK(make_rx("mypkg").match("mypkg"));
+    BOOST_CHECK(!make_rx("mypkg").match("yourpkg"));
+
+    // substrings don't count
+    BOOST_CHECK(!make_rx("foo").match("afool"));
+    // prefixes must match
+    BOOST_CHECK(make_rx("foo").match("fool"));
+    // explicit anchor is OK
+    BOOST_CHECK(make_rx("^foo").match("foo"));
+    // double anchor is also OK
+    BOOST_CHECK(make_rx("^^foo").match("foo"));
+    // exclude prefix matches
+    BOOST_CHECK(!make_rx("foo$").match("foo-devel"));
+
+    SolvableMatcher ror = make_rx("ruby[.0-9]+-rubygem-active(model|record)");
+    BOOST_CHECK(ror.match("ruby2.5-rubygem-activemodel-5.2"));
+    BOOST_CHECK(ror.match("ruby2.5-rubygem-activerecord-5_1"));
+}
index 97be4beec85906173247cf7e1144ff50a4d054a6..430cb9088bb2b6753fb0d1eed07b4bfab6d8e266 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -22,9 +22,9 @@
 #include <iostream>
 #include <boost/algorithm/string/trim.hpp>
 #include <string>
+#include <regex>
 using namespace std;
 
-#include "snapper/Regex.h"
 #include "zypp_plugin.h"
 
 int ZyppPlugin::main() {
@@ -70,13 +70,15 @@ ZyppPlugin::Message ZyppPlugin::read_message(istream& is) {
            if (line.empty())
                continue;
 
-           static const snapper::Regex rx_word("^[A-Za-z0-9_]+$");
-           if (rx_word.match(line)) {
+           static const regex rx_word("[A-Za-z0-9_]+", regex::extended);
+           if (regex_match(line, rx_word))
+           {
                msg = Message();
                msg.command = line;
                state = State::Headers;
            }
-           else {
+           else
+           {
                throw runtime_error("Plugin protocol error: expected a command. Got '" + line + "'");
            }
        }
@@ -87,14 +89,19 @@ ZyppPlugin::Message ZyppPlugin::read_message(istream& is) {
 
                return msg;
            }
-           else {
-               static const snapper::Regex rx_header("^([A-Za-z0-9_]+):[ \t]*(.+)$");
-               if (rx_header.match(line)) {
-                   string key = rx_header.cap(1);
-                   string value = rx_header.cap(2);
+           else
+           {
+               static const regex rx_header("([A-Za-z0-9_]+):[ \t]*(.+)", regex::extended);
+               smatch match;
+
+               if (regex_match(line, match, rx_header))
+               {
+                   string key = match[1];
+                   string value = match[2];
                    msg.headers[key] = value;
                }
-               else {
+               else
+               {
                    throw runtime_error("Plugin protocol error: expected a header or new line. Got '" + line + "'");
                }
            }