misc: Make the function for NEVR and NEVRA parsing more generic
authorTomas Mlcoch <tmlcoch@redhat.com>
Wed, 16 Jul 2014 14:55:32 +0000 (16:55 +0200)
committerTomas Mlcoch <tmlcoch@redhat.com>
Wed, 16 Jul 2014 14:55:32 +0000 (16:55 +0200)
src/misc.c
src/misc.h
tests/test_misc.c

index b08a7b9..0001256 100644 (file)
@@ -339,10 +339,10 @@ cr_get_header_byte_range(const char *filename, GError **err)
 char *
 cr_get_filename(const char *filepath)
 {
-    char *filename = NULL;
+    char *filename;
 
     if (!filepath)
-        return filename;
+        return NULL;
 
     filename = (char *) filepath;
     size_t x = 0;
@@ -983,21 +983,32 @@ cr_slist_free_full(GSList *list, GDestroyNotify free_f)
     g_slist_free(list);
 }
 
-
 cr_NEVRA *
 cr_split_rpm_filename(const char *filename)
 {
-    cr_NEVRA *res = NULL;
-    gchar *str, *copy;
+    cr_NEVRA *nevra = NULL;
+    gchar *str, *epoch = NULL;
     size_t len;
-    int i;
+
+    filename = cr_get_filename(filename);
 
     if (!filename)
-        return res;
+        return NULL;
 
-    res = g_new0(cr_NEVRA, 1);
     str = g_strdup(filename);
-    copy = str;
+
+    // N-V-R.rpm:E
+    if (strchr(str, ':')) {
+        gchar **filename_epoch = g_strsplit(str, ":", 2);
+        if (g_str_has_suffix(filename_epoch[0], ".rpm")) {
+            g_free(str);
+            str = filename_epoch[0];
+            epoch = filename_epoch[1];
+        } else {
+            g_strfreev(filename_epoch);
+        }
+    }
+
     len = strlen(str);
 
     // Get rid off .rpm suffix
@@ -1006,109 +1017,109 @@ cr_split_rpm_filename(const char *filename)
         str[len] = '\0';
     }
 
-    // Get arch
-    for (i = len-1; i >= 0; i--)
-        if (str[i] == '.') {
-            res->arch = g_strdup(str+i+1);
-            str[i] = '\0';
-            len = i;
-            break;
-        }
+    nevra = cr_str_to_nevra(str);
+    g_free(str);
 
-    // Get release
-    for (i = len-1; i >= 0; i--)
-        if (str[i] == '-') {
-            res->release = g_strdup(str+i+1);
-            str[i] = '\0';
-            len = i;
-            break;
-        }
-
-    // Get version
-    for (i = len-1; i >= 0; i--)
-        if (str[i] == '-') {
-            res->version = g_strdup(str+i+1);
-            str[i] = '\0';
-            len = i;
-            break;
-        }
-
-    // Get epoch
-    for (i = 0; i < (int) len; i++)
-        if (str[i] == ':') {
-            str[i] = '\0';
-            res->epoch = g_strdup(str);
-            str += i + 1;
-            break;
-        }
-
-    // Get name
-    res->name = g_strdup(str);
-    g_free(copy);
+    if (epoch) {
+        g_free(nevra->epoch);
+        nevra->epoch = epoch;
+    }
 
-    return res;
+    return nevra;
 }
 
-
+/** Split N-V-R:E or E:N-V-R or N-E:V-R
+ */
 cr_NEVR *
 cr_str_to_nevr(const char *instr)
 {
+    gchar *nvr = NULL;
+    gchar *epoch = NULL;
+    gchar **nvr_epoch_list = NULL;
     cr_NEVR *nevr = NULL;
-    gchar *str, *copy;
     size_t len;
     int i;
 
     if (!instr)
         return NULL;
 
+    // 1)
+    // Try to split by ':'
+    // If we have N-V-R:E or E:N-V-R then nvr and epoch will be filled
+    // If we have N-E:V-R or N-V-R then only nvr will be filed
+
+    nvr_epoch_list = g_strsplit(instr, ":", 2);
+
+    if (!nvr_epoch_list || !(*nvr_epoch_list)) {
+        g_strfreev(nvr_epoch_list);
+        return NULL;
+    }
+
+    nvr     = nvr_epoch_list[0];
+    epoch   = nvr_epoch_list[1];  // May be NULL
+
+    if (epoch && strchr(epoch, '-')) {
+        if (!strchr(nvr, '-')) {
+            // Switch nvr and epoch
+            char *tmp = nvr;
+            nvr = epoch;
+            epoch = tmp;
+        } else {
+            // Probably the N-E:V-R format, handle it after the split
+            g_free(nvr);
+            g_free(epoch);
+            nvr = g_strdup(instr);
+            epoch = NULL;
+        }
+    }
+
+    g_free(nvr_epoch_list);
+
+    // 2)
+    // Now split the nvr by the '-' into three parts
+
     nevr = g_new0(cr_NEVR, 1);
-    copy = str = g_strdup(instr);
-    len = strlen(str);
+    len = strlen(nvr);
 
     // Get release
     for (i = len-1; i >= 0; i--)
-        if (str[i] == '-') {
-            nevr->release = g_strdup(str+i+1);
-            str[i] = '\0';
+        if (nvr[i] == '-') {
+            nevr->release = g_strdup(nvr+i+1);
+            nvr[i] = '\0';
             len = i;
             break;
         }
 
-    int epoch = 1;
-
     // Get version
     for (i = len-1; i >= 0; i--)
-        if (str[i] == ':') {
-            nevr->version = g_strdup(str+i+1);
-            str[i] = '\0';
-            len = i;
-            break;
-        } else if (str[i] == '-') {
-            nevr->version = g_strdup(str+i+1);
-            str[i] = '\0';
+        if (nvr[i] == '-') {
+            nevr->version = g_strdup(nvr+i+1);
+            nvr[i] = '\0';
             len = i;
-            epoch = 0;
             break;
         }
 
-    // Get epoch
-    if (epoch) {
-        for (i = len-1; i >= 0; i--)
-            if (str[i] == '-') {
-                nevr->epoch = g_strdup(str+i+1);
-                str[i] = '\0';
-                break;
-            }
-    }
-
     // Get name
-    nevr->name = g_strdup(str);
-    g_free(copy);
+    nevr->name = g_strdup(nvr);
+
+    g_free(nvr);
+
+    // 3)
+    // Now split the E:V
+
+    if (epoch == NULL && (nevr->version && strchr(nevr->version, ':'))) {
+        gchar **epoch_version = g_strsplit(nevr->version, ":", 2);
+        g_free(nevr->version);
+        nevr->epoch = epoch_version[0];
+        nevr->version = epoch_version[1];
+        g_free(epoch_version);
+    } else {
+        nevr->epoch = epoch;
+    }
 
     return nevr;
 }
 
-
 void
 cr_nevr_free(cr_NEVR *nevr)
 {
@@ -1127,7 +1138,7 @@ cr_str_to_nevra(const char *instr)
 {
     cr_NEVR *nevr;
     cr_NEVRA *nevra = NULL;
-    gchar *str, *copy;
+    gchar *str, *epoch = NULL;
     size_t len;
     int i;
 
@@ -1135,7 +1146,24 @@ cr_str_to_nevra(const char *instr)
         return NULL;
 
     nevra = g_new0(cr_NEVRA, 1);
-    copy = str = g_strdup(instr);
+    str = g_strdup(instr);
+
+    // N-V-R.A:E
+    if (strchr(str, ':')) {
+        gchar **nvra_epoch = g_strsplit(str, ":", 2);
+        char *epoch_candidate = nvra_epoch[1];
+        if (epoch_candidate
+            && !strchr(epoch_candidate, '-')
+            && !strchr(epoch_candidate, '.'))
+        {
+            // Strip epoch from the very end
+            epoch = epoch_candidate;
+            str = nvra_epoch[0];
+        } else {
+            g_strfreev(nvra_epoch);
+        }
+    }
+
     len = strlen(str);
 
     // Get arch
@@ -1147,6 +1175,13 @@ cr_str_to_nevra(const char *instr)
             break;
         }
 
+    if (nevra->arch && strchr(nevra->arch, '-')) {
+        g_warning("Invalid arch %s", nevra->arch);
+        cr_nevra_free(nevra);
+        g_free(str);
+        return NULL;
+    }
+
     nevr = cr_str_to_nevr(str);
     nevra->name     = nevr->name;
     nevra->epoch    = nevr->epoch;
@@ -1154,7 +1189,12 @@ cr_str_to_nevra(const char *instr)
     nevra->release  = nevr->release;
     g_free(nevr);
 
-    g_free(copy);
+    g_free(str);
+
+    if (epoch) {
+        g_free(nevra->epoch);
+        nevra->epoch = epoch;
+    }
 
     return nevra;
 }
index 9bd8d23..0506501 100644 (file)
@@ -293,6 +293,11 @@ void cr_log_fn(const gchar *log_domain,
 void cr_slist_free_full(GSList *list, GDestroyNotify free_f);
 
 /** Split filename into the NEVRA.
+ * Supported formats:
+ * [path/]N-V-R:E.A[.rpm]
+ * [path/]E:N-V-R.A[.rpm]
+ * [path/]N-E:V-R.A[.rpm]
+ * [path/]N-V-R.A[.rpm]:E
  * @param filename      filename
  * @return              cr_NEVRA
  */
@@ -470,7 +475,7 @@ cr_append_pid_and_datetime(const char *str, const char *suffix);
 gboolean
 cr_spawn_check_exit_status(gint exit_status, GError **error);
 
-/** Parse NEVR (N-E:V-R) string.
+/** Parse E:N-V-R or N-V-R:E or N-E:V-R string
  * @param str           NEVR string
  * @returns             Malloced cr_NEVR or NULL on error
  */
@@ -483,7 +488,7 @@ cr_str_to_nevr(const char *str);
 void
 cr_nevr_free(cr_NEVR *nevr);
 
-/** Parse NEVRA (N-E:V-R.A) string.
+/** Parse E:N-V-R.A, N-V-R:E.A, N-E:V-R.A or N-V-R.A:E string.
  * @param str           NEVRA string
  * @returns             Malloced cr_NEVRA or NULL on error
  */
index 2ecb8a9..f0d24db 100644 (file)
@@ -982,13 +982,40 @@ test_cr_split_rpm_filename(void)
     g_assert_cmpstr(res->arch, ==, "ia64");
     cr_nevra_free(res);
 
-    res = cr_split_rpm_filename(":a--.");
+    res = cr_split_rpm_filename("bar-2:9-123a.ia64.rpm");
     g_assert(res);
-    g_assert_cmpstr(res->name, ==, "a");
-    g_assert_cmpstr(res->version, ==, "");
-    g_assert_cmpstr(res->release, ==, "");
-    g_assert_cmpstr(res->epoch, ==, "");
-    g_assert_cmpstr(res->arch, ==, "");
+    g_assert_cmpstr(res->name, ==, "bar");
+    g_assert_cmpstr(res->version, ==, "9");
+    g_assert_cmpstr(res->release, ==, "123a");
+    g_assert_cmpstr(res->epoch, ==, "2");
+    g_assert_cmpstr(res->arch, ==, "ia64");
+    cr_nevra_free(res);
+
+    res = cr_split_rpm_filename("bar-9-123a:3.ia64.rpm");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "bar");
+    g_assert_cmpstr(res->version, ==, "9");
+    g_assert_cmpstr(res->release, ==, "123a");
+    g_assert_cmpstr(res->epoch, ==, "3");
+    g_assert_cmpstr(res->arch, ==, "ia64");
+    cr_nevra_free(res);
+
+    res = cr_split_rpm_filename("bar-9-123a.ia64.rpm:4");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "bar");
+    g_assert_cmpstr(res->version, ==, "9");
+    g_assert_cmpstr(res->release, ==, "123a");
+    g_assert_cmpstr(res->epoch, ==, "4");
+    g_assert_cmpstr(res->arch, ==, "ia64");
+    cr_nevra_free(res);
+
+    res = cr_split_rpm_filename("bar-9-123a.ia64:5");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "bar");
+    g_assert_cmpstr(res->version, ==, "9");
+    g_assert_cmpstr(res->release, ==, "123a");
+    g_assert_cmpstr(res->epoch, ==, "5");
+    g_assert_cmpstr(res->arch, ==, "ia64");
     cr_nevra_free(res);
 
     res = cr_split_rpm_filename("b");
@@ -1026,20 +1053,20 @@ test_cr_str_to_nevr(void)
     g_assert_cmpstr(res->epoch, ==, "4");
     cr_nevr_free(res);
 
-    res = cr_str_to_nevr("a--.");
+    res = cr_str_to_nevr("3:foo-2-el.6");
     g_assert(res);
-    g_assert_cmpstr(res->name, ==, "a");
-    g_assert_cmpstr(res->version, ==, "");
-    g_assert_cmpstr(res->release, ==, ".");
-    g_assert(!res->epoch);
+    g_assert_cmpstr(res->name, ==, "foo");
+    g_assert_cmpstr(res->version, ==, "2");
+    g_assert_cmpstr(res->release, ==, "el.6");
+    g_assert_cmpstr(res->epoch, ==, "3");
     cr_nevr_free(res);
 
-    res = cr_str_to_nevr("b");
+    res = cr_str_to_nevr("foo-2-el.6:3");
     g_assert(res);
-    g_assert_cmpstr(res->name, ==, "b");
-    g_assert(!res->version);
-    g_assert(!res->release);
-    g_assert(!res->epoch);
+    g_assert_cmpstr(res->name, ==, "foo");
+    g_assert_cmpstr(res->version, ==, "2");
+    g_assert_cmpstr(res->release, ==, "el.6");
+    g_assert_cmpstr(res->epoch, ==, "3");
     cr_nevr_free(res);
 
     res = cr_str_to_nevr("b-1-2");
@@ -1049,6 +1076,14 @@ test_cr_str_to_nevr(void)
     g_assert_cmpstr(res->release, ==, "2");
     g_assert(!res->epoch);
     cr_nevr_free(res);
+
+    res = cr_str_to_nevr("b");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "b");
+    g_assert(!res->version);
+    g_assert(!res->release);
+    g_assert(!res->epoch);
+    cr_nevr_free(res);
 }
 
 static void
@@ -1059,23 +1094,59 @@ test_cr_str_to_nevra(void)
     res = cr_str_to_nevra(NULL);
     g_assert(!res);
 
-    res = cr_str_to_nevra("crypto-utils-0:2.4.1-52.fc20.x86_64");
+    res = cr_str_to_nevra("crypto-utils-2.4.1-52.fc20.x86_64");
     g_assert(res);
     g_assert_cmpstr(res->name, ==, "crypto-utils");
     g_assert_cmpstr(res->version, ==, "2.4.1");
     g_assert_cmpstr(res->release, ==, "52.fc20");
-    g_assert_cmpstr(res->epoch, ==, "0");
+    g_assert(!res->epoch);
     g_assert_cmpstr(res->arch, ==, "x86_64");
     cr_nevra_free(res);
 
-    res = cr_str_to_nevra("crypto-utils-2.4.1-52.fc20.x86_64");
+    res = cr_str_to_nevra("crypto-utils-1:2.4.1-52.fc20.x86_64");
     g_assert(res);
     g_assert_cmpstr(res->name, ==, "crypto-utils");
     g_assert_cmpstr(res->version, ==, "2.4.1");
     g_assert_cmpstr(res->release, ==, "52.fc20");
-    g_assert(!res->epoch);
+    g_assert_cmpstr(res->epoch, ==, "1");
+    g_assert_cmpstr(res->arch, ==, "x86_64");
+    cr_nevra_free(res);
+
+    res = cr_str_to_nevra("2:crypto-utils-2.4.1-52.fc20.x86_64");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "crypto-utils");
+    g_assert_cmpstr(res->version, ==, "2.4.1");
+    g_assert_cmpstr(res->release, ==, "52.fc20");
+    g_assert_cmpstr(res->epoch, ==, "2");
     g_assert_cmpstr(res->arch, ==, "x86_64");
     cr_nevra_free(res);
+
+    res = cr_str_to_nevra("crypto-utils-2.4.1-52.fc20:3.x86_64");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "crypto-utils");
+    g_assert_cmpstr(res->version, ==, "2.4.1");
+    g_assert_cmpstr(res->release, ==, "52.fc20");
+    g_assert_cmpstr(res->epoch, ==, "3");
+    g_assert_cmpstr(res->arch, ==, "x86_64");
+    cr_nevra_free(res);
+
+    res = cr_str_to_nevra("crypto-utils-2.4.1-52.fc20.x86_64:4");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "crypto-utils");
+    g_assert_cmpstr(res->version, ==, "2.4.1");
+    g_assert_cmpstr(res->release, ==, "52.fc20");
+    g_assert_cmpstr(res->epoch, ==, "4");
+    g_assert_cmpstr(res->arch, ==, "x86_64");
+    cr_nevra_free(res);
+
+    res = cr_str_to_nevra("a");
+    g_assert(res);
+    g_assert_cmpstr(res->name, ==, "a");
+    g_assert(!res->version);
+    g_assert(!res->release);
+    g_assert(!res->epoch);
+    g_assert(!res->arch);
+    cr_nevra_free(res);
 }
 
 static void