lucy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nwelln...@apache.org
Subject [lucy-commits] [3/4] git commit: Verify prerequisite parcels
Date Wed, 12 Mar 2014 12:36:38 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/3e08f203
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/3e08f203
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/3e08f203

Branch: refs/heads/explicit-dependencies
Commit: 3e08f203a9d148c119122f8956b690a2e77a5338
Parents: 59ddf3e
Author: Nick Wellnhofer <wellnhofer@aevum.de>
Authored: Tue Mar 11 20:06:34 2014 +0100
Committer: Nick Wellnhofer <wellnhofer@aevum.de>
Committed: Wed Mar 12 13:31:55 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/3e08f203/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/3e08f203/compiler/src/CFCParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.c b/compiler/src/CFCParcel.c
index 5ca9500..5217ff0 100644
--- a/compiler/src/CFCParcel.c
+++ b/compiler/src/CFCParcel.c
@@ -44,6 +44,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;
@@ -252,8 +253,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*));
@@ -470,6 +472,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);
@@ -546,6 +553,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);
+    }
+}
+
 const char*
 CFCPrereq_get_name(CFCPrereq *self) {
     return self->name;

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3e08f203/compiler/src/CFCParcel.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParcel.h b/compiler/src/CFCParcel.h
index aed1b57..b64d8e2 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);
+
 const char*
 CFCPrereq_get_name(CFCPrereq *self);
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3e08f203/compiler/src/CFCTestParcel.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCTestParcel.c b/compiler/src/CFCTestParcel.c
index 7aa96cb..f160cc8 100644
--- a/compiler/src/CFCTestParcel.c
+++ b/compiler/src/CFCTestParcel.c
@@ -33,7 +33,7 @@ S_run_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_PARCEL = {
     "Clownfish::CFC::Model::Parcel",
-    20,
+    23,
     S_run_tests
 };
 
@@ -99,6 +99,7 @@ S_run_tests(CFCTest *test) {
 
         CFCBase_decref((CFCBase*)thing);
         CFCBase_decref((CFCBase*)parcel);
+        CFCParcel_reap_singletons();
     }
 
     {
@@ -141,6 +142,36 @@ S_run_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"
+            "            \"prereqs\": {\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