lucy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nwelln...@apache.org
Subject [lucy-commits] [02/10] git commit: Add field 'prerequisites' to .cfp parcel definition
Date Mon, 17 Mar 2014 17:27:49 GMT
Add field 'prerequisites' to .cfp parcel definition

The value is a hash where the keys are parcel names and the values are
version strings:

    "prereqs": {
        "ParcelA": "v1.2.1",
        "ParcelB": "v4.0.3"
    }


Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/98f6b71a
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/98f6b71a
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/98f6b71a

Branch: refs/heads/explicit-dependencies-wip2
Commit: 98f6b71a01eb37b66d75901e4bb9a3cbb090a3af
Parents: daab988
Author: Nick Wellnhofer <wellnhofer@aevum.de>
Authored: Tue Mar 11 18:25:44 2014 +0100
Committer: Nick Wellnhofer <wellnhofer@aevum.de>
Committed: Mon Mar 17 18:25:29 2014 +0100

----------------------------------------------------------------------
 compiler/src/CFCParcel.c     | 119 ++++++++++++++++++++++++++++++++++++++
 compiler/src/CFCParcel.h     |  23 ++++++++
 compiler/src/CFCTestParcel.c |  79 ++++++++++++++++++++++++-
 3 files changed, 220 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/98f6b71a/compiler/src/CFCParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.c b/compiler/src/CFCParcel.c
index 2b3bead..cfad49a 100644
--- a/compiler/src/CFCParcel.c
+++ b/compiler/src/CFCParcel.c
@@ -43,6 +43,8 @@ struct CFCParcel {
     size_t num_dependent_parcels;
     char **inherited_parcels;
     size_t num_inherited_parcels;
+    CFCPrereq **prereqs;
+    size_t num_prereqs;
 };
 
 static CFCParcel *default_parcel = NULL;
@@ -58,6 +60,9 @@ typedef struct JSONNode {
     size_t num_kids;
 } JSONNode;
 
+static void
+S_set_prereqs(CFCParcel *self, JSONNode *node, const char *path);
+
 static JSONNode*
 S_parse_json_for_parcel(const char *json);
 
@@ -251,6 +256,10 @@ CFCParcel_init(CFCParcel *self, const char *name, const char *cnick,
     self->inherited_parcels = (char**)CALLOCATE(1, sizeof(char*));
     self->num_inherited_parcels = 0;
 
+    // Initialize prereqs.
+    self->prereqs = (CFCPrereq**)CALLOCATE(1, sizeof(CFCPrereq*));
+    self->num_prereqs = 0;
+
     return self;
 }
 
@@ -266,6 +275,7 @@ S_new_from_json(const char *json, const char *path, int is_included) {
     const char *name     = NULL;
     const char *nickname = NULL;
     CFCVersion *version  = NULL;
+    JSONNode   *prereqs  = NULL;
     for (size_t i = 0, max = parsed->num_kids; i < max; i += 2) {
         JSONNode *key   = parsed->kids[i];
         JSONNode *value = parsed->kids[i + 1];
@@ -292,6 +302,13 @@ S_new_from_json(const char *json, const char *path, int is_included)
{
             }
             version = CFCVersion_new(value->string);
         }
+        else if (strcmp(key->string, "prerequisites") == 0) {
+            if (value->type != JSON_HASH) {
+                CFCUtil_die("'prerequisites' must be a hash (filepath %s)",
+                            path);
+            }
+            prereqs = value;
+        }
         else {
             CFCUtil_die("Unrecognized key: '%s' (filepath '%s')",
                         key->string, path);
@@ -304,12 +321,49 @@ S_new_from_json(const char *json, const char *path, int is_included)
{
         CFCUtil_die("Missing required key 'version' (filepath '%s')", path);
     }
     CFCParcel *self = CFCParcel_new(name, nickname, version, is_included);
+    if (prereqs) {
+        S_set_prereqs(self, prereqs, path);
+    }
     CFCBase_decref((CFCBase*)version);
 
     S_destroy_json(parsed);
     return self;
 }
 
+static void
+S_set_prereqs(CFCParcel *self, JSONNode *node, const char *path) {
+    size_t num_prereqs = node->num_kids / 2;
+    CFCPrereq **prereqs
+        = (CFCPrereq**)MALLOCATE((num_prereqs + 1) * sizeof(CFCPrereq*));
+
+    for (size_t i = 0; i < num_prereqs; ++i) {
+        JSONNode *key = node->kids[2*i];
+        if (key->type != JSON_STRING) {
+            CFCUtil_die("Prereq key must be a string (filepath '%s')", path);
+        }
+        const char *name = key->string;
+
+        JSONNode *value = node->kids[2*i+1];
+        CFCVersion *version = NULL;
+        if (value->type == JSON_STRING) {
+            version = CFCVersion_new(value->string);
+        }
+        else if (value->type != JSON_NULL) {
+            CFCUtil_die("Invalid prereq value (filepath '%s')", path);
+        }
+
+        prereqs[i] = CFCPrereq_new(name, version);
+
+        CFCBase_decref((CFCBase*)version);
+    }
+    prereqs[num_prereqs] = NULL;
+
+    // Assume that prereqs are empty.
+    FREEMEM(self->prereqs);
+    self->prereqs     = prereqs;
+    self->num_prereqs = num_prereqs;
+}
+
 CFCParcel*
 CFCParcel_new_from_json(const char *json, int is_included) {
     return S_new_from_json(json, "[NULL]", is_included);
@@ -341,6 +395,10 @@ CFCParcel_destroy(CFCParcel *self) {
         FREEMEM(self->inherited_parcels[i]);
     }
     FREEMEM(self->inherited_parcels);
+    for (size_t i = 0; self->prereqs[i]; ++i) {
+        CFCBase_decref((CFCBase*)self->prereqs[i]);
+    }
+    FREEMEM(self->prereqs);
     CFCBase_destroy((CFCBase*)self);
 }
 
@@ -474,6 +532,67 @@ CFCParcel_inherited_parcels(CFCParcel *self) {
     return parcels;
 }
 
+CFCPrereq**
+CFCParcel_get_prereqs(CFCParcel *self) {
+    return self->prereqs;
+}
+
+/**************************************************************************/
+
+struct CFCPrereq {
+    CFCBase base;
+    char *name;
+    CFCVersion *version;
+};
+
+static const CFCMeta CFCPREREQ_META = {
+    "Clownfish::CFC::Model::Prereq",
+    sizeof(CFCPrereq),
+    (CFCBase_destroy_t)CFCPrereq_destroy
+};
+
+CFCPrereq*
+CFCPrereq_new(const char *name, CFCVersion *version) {
+    CFCPrereq *self = (CFCPrereq*)CFCBase_allocate(&CFCPREREQ_META);
+    return CFCPrereq_init(self, name, version);
+}
+
+CFCPrereq*
+CFCPrereq_init(CFCPrereq *self, const char *name, CFCVersion *version) {
+    // Validate name.
+    if (!name || !S_validate_name_or_cnick(name)) {
+        CFCUtil_die("Invalid name: '%s'", name ? name : "[NULL]");
+    }
+    self->name = CFCUtil_strdup(name);
+
+    // Default to version v0.
+    if (version) {
+        self->version = (CFCVersion*)CFCBase_incref((CFCBase*)version);
+    }
+    else {
+        self->version = CFCVersion_new("v0");
+    }
+
+    return self;
+}
+
+void
+CFCPrereq_destroy(CFCPrereq *self) {
+    FREEMEM(self->name);
+    CFCBase_decref((CFCBase*)self->version);
+    CFCBase_destroy((CFCBase*)self);
+}
+
+const char*
+CFCPrereq_get_name(CFCPrereq *self) {
+    return self->name;
+}
+
+CFCVersion*
+CFCPrereq_get_version(CFCPrereq *self) {
+    return self->version;
+}
+
 /*****************************************************************************
  * The hack JSON parser coded up below is only meant to parse Clownfish parcel
  * file content.  It is limited in its capabilities because so little is legal

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/98f6b71a/compiler/src/CFCParcel.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.h b/compiler/src/CFCParcel.h
index d5cdb5f..ad31c86 100644
--- a/compiler/src/CFCParcel.h
+++ b/compiler/src/CFCParcel.h
@@ -37,6 +37,7 @@ extern "C" {
 #endif
 
 typedef struct CFCParcel CFCParcel;
+typedef struct CFCPrereq CFCPrereq;
 struct CFCVersion;
 
 /** Return the parcel which has been registered for <code>name</code>.
@@ -143,6 +144,28 @@ CFCParcel_dependent_parcels(CFCParcel *self);
 CFCParcel**
 CFCParcel_inherited_parcels(CFCParcel *self);
 
+/** Return a NULL-terminated array of all prerequisites.
+ */
+CFCPrereq**
+CFCParcel_get_prereqs(CFCParcel *self);
+
+/**************************************************************************/
+
+CFCPrereq*
+CFCPrereq_new(const char *name, struct CFCVersion *version);
+
+CFCPrereq*
+CFCPrereq_init(CFCPrereq *self, const char *name, struct CFCVersion *version);
+
+void
+CFCPrereq_destroy(CFCPrereq *self);
+
+const char*
+CFCPrereq_get_name(CFCPrereq *self);
+
+struct CFCVersion*
+CFCPrereq_get_version(CFCPrereq *self);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/98f6b71a/compiler/src/CFCTestParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestParcel.c b/compiler/src/CFCTestParcel.c
index d91a271..5d3e5d9 100644
--- a/compiler/src/CFCTestParcel.c
+++ b/compiler/src/CFCTestParcel.c
@@ -31,14 +31,51 @@
 static void
 S_run_tests(CFCTest *test);
 
+static void
+S_run_prereq_tests(CFCTest *test);
+
+static void
+S_run_parcel_tests(CFCTest *test);
+
 const CFCTestBatch CFCTEST_BATCH_PARCEL = {
     "Clownfish::CFC::Model::Parcel",
-    12,
+    23,
     S_run_tests
 };
 
 static void
 S_run_tests(CFCTest *test) {
+    S_run_prereq_tests(test);
+    S_run_parcel_tests(test);
+}
+
+static void
+S_run_prereq_tests(CFCTest *test) {
+    {
+        CFCVersion *v77_66_55 = CFCVersion_new("v77.66.55");
+        CFCPrereq *prereq = CFCPrereq_new("Flour", v77_66_55);
+        const char *name = CFCPrereq_get_name(prereq);
+        STR_EQ(test, name, "Flour", "prereq get_name");
+        CFCVersion *version = CFCPrereq_get_version(prereq);
+        INT_EQ(test, CFCVersion_compare_to(version, v77_66_55), 0,
+               "prereq get_version");
+        CFCBase_decref((CFCBase*)prereq);
+        CFCBase_decref((CFCBase*)v77_66_55);
+    }
+
+    {
+        CFCVersion *v0 = CFCVersion_new("v0");
+        CFCPrereq *prereq = CFCPrereq_new("Sugar", NULL);
+        CFCVersion *version = CFCPrereq_get_version(prereq);
+        INT_EQ(test, CFCVersion_compare_to(version, v0), 0,
+               "prereq with default version");
+        CFCBase_decref((CFCBase*)prereq);
+        CFCBase_decref((CFCBase*)v0);
+    }
+}
+
+static void
+S_run_parcel_tests(CFCTest *test) {
     {
         CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL, false);
         OK(test, parcel != NULL, "new");
@@ -101,6 +138,46 @@ S_run_tests(CFCTest *test) {
         CFCBase_decref((CFCBase*)parcel);
     }
 
+    {
+        const char *json =
+            "        {\n"
+            "            \"name\": \"Crustacean\",\n"
+            "            \"version\": \"v0.1.0\",\n"
+            "            \"prerequisites\": {\n"
+            "                \"Clownfish\": null,\n"
+            "                \"Arthropod\": \"v30.104.5\"\n"
+            "            }\n"
+            "        }\n";
+        CFCParcel *parcel = CFCParcel_new_from_json(json, false);
+
+        CFCPrereq **prereqs = CFCParcel_get_prereqs(parcel);
+        OK(test, prereqs != NULL, "prereqs");
+
+        CFCPrereq *cfish = prereqs[0];
+        OK(test, cfish != NULL, "prereqs[0]");
+        const char *cfish_name = CFCPrereq_get_name(cfish);
+        STR_EQ(test, cfish_name, "Clownfish", "prereqs[0] name");
+        CFCVersion *v0            = CFCVersion_new("v0");
+        CFCVersion *cfish_version = CFCPrereq_get_version(cfish);
+        INT_EQ(test, CFCVersion_compare_to(cfish_version, v0), 0,
+               "prereqs[0] version");
+
+        CFCPrereq *apod = prereqs[1];
+        OK(test, apod != NULL, "prereqs[1]");
+        const char *apod_name = CFCPrereq_get_name(apod);
+        STR_EQ(test, apod_name, "Arthropod", "prereqs[1] name");
+        CFCVersion *v30_104_5    = CFCVersion_new("v30.104.5");
+        CFCVersion *apod_version = CFCPrereq_get_version(apod);
+        INT_EQ(test, CFCVersion_compare_to(apod_version, v30_104_5), 0,
+               "prereqs[1] version");
+
+        OK(test, prereqs[2] == NULL, "prereqs[2]");
+
+        CFCBase_decref((CFCBase*)v30_104_5);
+        CFCBase_decref((CFCBase*)v0);
+        CFCBase_decref((CFCBase*)parcel);
+    }
+
     CFCParcel_reap_singletons();
 }
 


Mime
View raw message