lucy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nwelln...@apache.org
Subject [lucy-commits] [06/11] git commit: Verify prerequisite parcels
Date Mon, 17 Mar 2014 20:36:19 GMT
Verify prerequisite parcels

Recursively check that all prerequisite parcels were found and match the
required version. All visited parcels are marked with a 'required' flag.


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

Branch: refs/heads/master
Commit: 9abd6a8e555a233e92e0352ec89133bb38558ec7
Parents: ba21f48
Author: Nick Wellnhofer <wellnhofer@aevum.de>
Authored: Tue Mar 11 20:06:34 2014 +0100
Committer: Nick Wellnhofer <wellnhofer@aevum.de>
Committed: Mon Mar 17 18:25:30 2014 +0100

----------------------------------------------------------------------
 compiler/src/CFCHierarchy.c  | 24 ++++++++++++++++++++++
 compiler/src/CFCParcel.c     | 43 ++++++++++++++++++++++++++++++++++++++-
 compiler/src/CFCParcel.h     | 12 +++++++++++
 compiler/src/CFCTestParcel.c | 35 +++++++++++++++++++++++++++++--
 4 files changed, 111 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/9abd6a8e/compiler/src/CFCHierarchy.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCHierarchy.c b/compiler/src/CFCHierarchy.c
index c5ce5ec..af03016 100644
--- a/compiler/src/CFCHierarchy.c
+++ b/compiler/src/CFCHierarchy.c
@@ -67,6 +67,9 @@ static void
 S_parse_parcel_files(const char *path, void *context);
 
 static void
+S_check_prereqs(void);
+
+static void
 S_do_make_path(const char *path);
 
 static void
@@ -189,6 +192,7 @@ CFCHierarchy_add_include_dir(CFCHierarchy *self, const char *include_dir)
{
 
 void
 CFCHierarchy_build(CFCHierarchy *self) {
+    // Read .cfp files.
     CFCParseParcelFilesContext context;
     context.is_included = false;
     for (size_t i = 0; self->sources[i] != NULL; i++) {
@@ -198,15 +202,21 @@ CFCHierarchy_build(CFCHierarchy *self) {
     for (size_t i = 0; self->includes[i] != NULL; i++) {
         CFCUtil_walk(self->includes[i], S_parse_parcel_files, &context);
     }
+
+    S_check_prereqs();
+
+    // Read .cfh files.
     for (size_t i = 0; self->sources[i] != NULL; i++) {
         S_parse_cf_files(self, self->sources[i], 0);
     }
     for (size_t i = 0; self->includes[i] != NULL; i++) {
         S_parse_cf_files(self, self->includes[i], 1);
     }
+
     for (int i = 0; self->classes[i] != NULL; i++) {
         CFCClass_resolve_types(self->classes[i], self->classes);
     }
+
     S_connect_classes(self);
     for (size_t i = 0; self->trees[i] != NULL; i++) {
         CFCClass_grow_tree(self->trees[i]);
@@ -251,6 +261,20 @@ S_parse_parcel_files(const char *path, void *arg) {
 }
 
 static void
+S_check_prereqs() {
+    CFCParcel **parcels = CFCParcel_all_parcels();
+
+    for (int i = 0; parcels[i]; ++i) {
+        CFCParcel *parcel = parcels[i];
+        if (!CFCParcel_included(parcel)) {
+            CFCParcel_check_prereqs(parcel);
+        }
+    }
+
+    FREEMEM(parcels);
+}
+
+static void
 S_find_cfh(const char *path, void *context) {
     char ***cfh_ptr = (char***)context;
     char **cfh_list = *cfh_ptr;

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/9abd6a8e/compiler/src/CFCParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.c b/compiler/src/CFCParcel.c
index cfad49a..b54e014 100644
--- a/compiler/src/CFCParcel.c
+++ b/compiler/src/CFCParcel.c
@@ -39,6 +39,7 @@ struct CFCParcel {
     char *PREFIX;
     char *privacy_sym;
     int is_included;
+    int is_required;
     char **dependent_parcels;
     size_t num_dependent_parcels;
     char **inherited_parcels;
@@ -247,8 +248,9 @@ CFCParcel_init(CFCParcel *self, const char *name, const char *cnick,
     }
     self->privacy_sym[privacy_sym_len] = '\0';
 
-    // Set is_included.
+    // Initialize flags.
     self->is_included = is_included;
+    self->is_required = false;
 
     // Initialize dependencies.
     self->dependent_parcels = (char**)CALLOCATE(1, sizeof(char*));
@@ -461,6 +463,11 @@ CFCParcel_included(CFCParcel *self) {
     return self->is_included;
 }
 
+int
+CFCParcel_required(CFCParcel *self) {
+    return self->is_required;
+}
+
 void
 CFCParcel_add_dependent_parcel(CFCParcel *self, CFCParcel *dependent) {
     const char *name     = CFCParcel_get_name(self);
@@ -537,6 +544,40 @@ CFCParcel_get_prereqs(CFCParcel *self) {
     return self->prereqs;
 }
 
+void
+CFCParcel_check_prereqs(CFCParcel *self) {
+    // This is essentially a depth-first search of the dependency graph.
+
+    if (self->is_required) { return; }
+    self->is_required = true;
+
+    const char *name = CFCParcel_get_name(self);
+
+    for (int i = 0; self->prereqs[i]; ++i) {
+        CFCPrereq *prereq = self->prereqs[i];
+
+        const char *req_name   = CFCPrereq_get_name(prereq);
+        CFCParcel  *req_parcel = CFCParcel_fetch(req_name);
+        if (!req_parcel) {
+            // TODO: Add include path to error message.
+            CFCUtil_die("Parcel '%s' required by '%s' not found", req_name,
+                        name);
+        }
+
+        CFCVersion *version     = req_parcel->version;
+        CFCVersion *req_version = CFCPrereq_get_version(prereq);
+        if (CFCVersion_compare_to(version, req_version) < 0) {
+            const char *vstring     = CFCVersion_get_vstring(version);
+            const char *req_vstring = CFCVersion_get_vstring(req_version);
+            CFCUtil_die("Version %s of parcel '%s' required by '%s' is lower"
+                        " than required version %s",
+                        vstring, req_name, name, req_vstring);
+        }
+
+        CFCParcel_check_prereqs(req_parcel);
+    }
+}
+
 /**************************************************************************/
 
 struct CFCPrereq {

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/9abd6a8e/compiler/src/CFCParcel.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.h b/compiler/src/CFCParcel.h
index ad31c86..77e8d1b 100644
--- a/compiler/src/CFCParcel.h
+++ b/compiler/src/CFCParcel.h
@@ -121,6 +121,12 @@ CFCParcel_get_privacy_sym(CFCParcel *self);
 int
 CFCParcel_included(CFCParcel *self);
 
+/** Return true if the parcel is required. This is only valid after all
+ * prerequisites were checked.
+ */
+int
+CFCParcel_required(CFCParcel *self);
+
 /** Add another Parcel that the Parcel depends on.
  */
 void
@@ -149,6 +155,12 @@ CFCParcel_inherited_parcels(CFCParcel *self);
 CFCPrereq**
 CFCParcel_get_prereqs(CFCParcel *self);
 
+/** Recursively verify that all prerequisite parcels are present in the
+ * required version. Mark all needed parcels including 'self' as required.
+ */
+void
+CFCParcel_check_prereqs(CFCParcel *self);
+
 /**************************************************************************/
 
 CFCPrereq*

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/9abd6a8e/compiler/src/CFCTestParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestParcel.c b/compiler/src/CFCTestParcel.c
index 5d3e5d9..2abd7c0 100644
--- a/compiler/src/CFCTestParcel.c
+++ b/compiler/src/CFCTestParcel.c
@@ -39,7 +39,7 @@ S_run_parcel_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_PARCEL = {
     "Clownfish::CFC::Model::Parcel",
-    23,
+    26,
     S_run_tests
 };
 
@@ -136,6 +136,7 @@ S_run_parcel_tests(CFCTest *test) {
 
         CFCBase_decref((CFCBase*)thing);
         CFCBase_decref((CFCBase*)parcel);
+        CFCParcel_reap_singletons();
     }
 
     {
@@ -178,6 +179,36 @@ S_run_parcel_tests(CFCTest *test) {
         CFCBase_decref((CFCBase*)parcel);
     }
 
-    CFCParcel_reap_singletons();
+    {
+        CFCParcel *foo = CFCParcel_new("Foo", NULL, NULL, true);
+        CFCParcel_register(foo);
+
+        CFCVersion *cfish_version = CFCVersion_new("v0.8.7");
+        CFCParcel *cfish
+            = CFCParcel_new("Clownfish", NULL, cfish_version, true);
+        CFCParcel_register(cfish);
+
+        const char *crust_json =
+            "        {\n"
+            "            \"name\": \"Crustacean\",\n"
+            "            \"version\": \"v0.1.0\",\n"
+            "            \"prerequisites\": {\n"
+            "                \"Clownfish\": \"v0.8.5\",\n"
+            "            }\n"
+            "        }\n";
+        CFCParcel *crust = CFCParcel_new_from_json(crust_json, false);
+        CFCParcel_register(crust);
+
+        CFCParcel_check_prereqs(crust);
+        INT_EQ(test, CFCParcel_required(foo), false, "parcel not required");
+        INT_EQ(test, CFCParcel_required(cfish), true, "prereq required");
+        INT_EQ(test, CFCParcel_required(crust), true, "self required");
+
+        CFCBase_decref((CFCBase*)crust);
+        CFCBase_decref((CFCBase*)cfish_version);
+        CFCBase_decref((CFCBase*)cfish);
+        CFCBase_decref((CFCBase*)foo);
+        CFCParcel_reap_singletons();
+    }
 }
 


Mime
View raw message