You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2011/05/11 20:50:41 UTC

svn commit: r1102017 - in /couchdb/branches/1.1.x: ./ THANKS etc/default/couchdb share/server/util.js share/www/script/test/design_docs.js

Author: davisp
Date: Wed May 11 18:50:41 2011
New Revision: 1102017

URL: http://svn.apache.org/viewvc?rev=1102017&view=rev
Log:
Fix circular imports in CommonJS modules.

Backport of 1102006 from trunk.


Modified:
    couchdb/branches/1.1.x/   (props changed)
    couchdb/branches/1.1.x/THANKS
    couchdb/branches/1.1.x/etc/default/couchdb   (props changed)
    couchdb/branches/1.1.x/share/server/util.js
    couchdb/branches/1.1.x/share/www/script/test/design_docs.js

Propchange: couchdb/branches/1.1.x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed May 11 18:50:41 2011
@@ -6,4 +6,4 @@
 /couchdb/branches/list-iterator:782292-784593
 /couchdb/branches/tail_header:775760-778477
 /couchdb/tags/0.10.0:825400
-/couchdb/trunk:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479
+/couchdb/trunk:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479,1102006

Modified: couchdb/branches/1.1.x/THANKS
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/THANKS?rev=1102017&r1=1102016&r2=1102017&view=diff
==============================================================================
--- couchdb/branches/1.1.x/THANKS (original)
+++ couchdb/branches/1.1.x/THANKS Wed May 11 18:50:41 2011
@@ -79,5 +79,7 @@ suggesting improvements or submitting ch
  * Tim Smith <ti...@couchbase.com>
  * Sam Bisbee <sa...@sbisbee.com>
  * Nathan Vander Wilt <na...@yahoo.com>
+ * Caolan McMahon <ca...@googlemail.com>
+ 
 
 For a list of authors see the `AUTHORS` file.

Propchange: couchdb/branches/1.1.x/etc/default/couchdb
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed May 11 18:50:41 2011
@@ -6,5 +6,5 @@
 /couchdb/branches/list-iterator/etc/default/couchdb:782292-784593
 /couchdb/branches/tail_header/etc/default/couchdb:775760-778477
 /couchdb/tags/0.10.0/etc/default/couchdb:825400
-/couchdb/trunk/etc/default/couchdb:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479
+/couchdb/trunk/etc/default/couchdb:1045203,1064417,1081107-1083320,1083714,1095523,1095557,1095569,1095581,1096098,1097300,1099479,1102006
 /incubator/couchdb/trunk/etc/default/couchdb:642419-694440

Modified: couchdb/branches/1.1.x/share/server/util.js
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/share/server/util.js?rev=1102017&r1=1102016&r2=1102017&view=diff
==============================================================================
--- couchdb/branches/1.1.x/share/server/util.js (original)
+++ couchdb/branches/1.1.x/share/server/util.js Wed May 11 18:50:41 2011
@@ -31,16 +31,16 @@ var resolveModule = function(names, mod,
     }
     return resolveModule(names, {
       id : mod.id.slice(0, mod.id.lastIndexOf('/')),
-      parent : mod.parent.parent.parent,
-      current : mod.parent.parent.current
+      parent : mod.parent.parent,
+      current : mod.parent.current
     });
   } else if (n == '.') {
     if (!mod.parent) {
       throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
     }
     return resolveModule(names, {
-      parent : mod.parent.parent,
-      current : mod.parent.current,
+      parent : mod.parent,
+      current : mod.current,
       id : mod.id
     });
   } else if (root) {
@@ -66,17 +66,28 @@ var Couch = {
     try {
       if (sandbox) {
         if (ddoc) {
+          if (!ddoc._module_cache) {
+            ddoc._module_cache = {};
+          }
           var require = function(name, module) {
             module = module || {};
-            var newModule = resolveModule(name.split('/'), module, ddoc);
-            var s = "function (module, exports, require) { " + newModule.current + " }";
-            try {
-              var func = sandbox ? evalcx(s, sandbox) : eval(s);
-              func.apply(sandbox, [newModule, newModule.exports, function(name) {return require(name, newModule)}]);
-            } catch(e) { 
-              throw ["error","compilation_error","Module require('"+name+"') raised error "+e.toSource()]; 
+            var newModule = resolveModule(name.split('/'), module.parent, ddoc);
+            if (!ddoc._module_cache.hasOwnProperty(newModule.id)) {
+              // create empty exports object before executing the module,
+              // stops circular requires from filling the stack
+              ddoc._module_cache[newModule.id] = {};
+              var s = "function (module, exports, require) { " + newModule.current + " }";
+              try {
+                var func = sandbox ? evalcx(s, sandbox) : eval(s);
+                func.apply(sandbox, [newModule, newModule.exports, function(name) {
+                  return require(name, newModule);
+                }]);
+              } catch(e) { 
+                throw ["error","compilation_error","Module require('"+name+"') raised error "+e.toSource()]; 
+              }
+              ddoc._module_cache[newModule.id] = newModule.exports;
             }
-            return newModule.exports;
+            return ddoc._module_cache[newModule.id];
           }
           sandbox.require = require;
         }

Modified: couchdb/branches/1.1.x/share/www/script/test/design_docs.js
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/share/www/script/test/design_docs.js?rev=1102017&r1=1102016&r2=1102017&view=diff
==============================================================================
--- couchdb/branches/1.1.x/share/www/script/test/design_docs.js (original)
+++ couchdb/branches/1.1.x/share/www/script/test/design_docs.js Wed May 11 18:50:41 2011
@@ -49,7 +49,48 @@ couchTests.design_docs = function(debug)
           whynot : "exports.test = require('../stringzone'); " +
             "exports.foo = require('whatever/stringzone');",
           upper : "exports.testing = require('./whynot').test.string.toUpperCase()+" +
-            "module.id+require('./whynot').foo.string"
+            "module.id+require('./whynot').foo.string",
+          circular_one: "require('./circular_two'); exports.name = 'One';",
+          circular_two: "require('./circular_one'); exports.name = 'Two';"
+        },
+        // paths relative to parent
+        idtest1: {
+          a: {
+            b: {d: "module.exports = require('../c/e').id;"},
+            c: {e: "exports.id = module.id;"}
+          }
+        },
+        // multiple paths relative to parent
+        idtest2: {
+          a: {
+            b: {d: "module.exports = require('../../a/c/e').id;"},
+            c: {e: "exports.id = module.id;"}
+          }
+        },
+        // paths relative to module
+        idtest3: {
+          a: {
+            b: "module.exports = require('./c/d').id;",
+            c: {
+              d: "module.exports = require('./e');",
+              e: "exports.id = module.id;"
+            }
+          }
+        },
+        // paths relative to module and parent
+        idtest4: {
+          a: {
+            b: "module.exports = require('../a/./c/d').id;",
+            c: {
+              d: "module.exports = require('./e');",
+              e: "exports.id = module.id;"
+            }
+          }
+        },
+        // paths relative to root
+        idtest5: {
+          a: "module.exports = require('whatever/idtest5/b').id;",
+          b: "exports.id = module.id;"
         }
       },
       views: {
@@ -134,6 +175,25 @@ couchTests.design_docs = function(debug)
           (function() {
             var lib = require('whatever/commonjs/upper');
             return JSON.stringify(this);
+          }).toString(),
+        circular_require:
+          (function() {
+            return require('whatever/commonjs/circular_one').name;
+          }).toString(),
+        idtest1: (function() {
+            return require('whatever/idtest1/a/b/d');
+          }).toString(),
+        idtest2: (function() {
+            return require('whatever/idtest2/a/b/d');
+          }).toString(),
+        idtest3: (function() {
+            return require('whatever/idtest3/a/b');
+          }).toString(),
+        idtest4: (function() {
+            return require('whatever/idtest4/a/b');
+          }).toString(),
+        idtest5: (function() {
+            return require('whatever/idtest5/a');
           }).toString()
       }
     }; // designDoc
@@ -174,6 +234,52 @@ couchTests.design_docs = function(debug)
     T(xhr.status == 200);
     TEquals("javascript", JSON.parse(xhr.responseText).language);
 
+    // test circular commonjs dependencies
+    xhr = CouchDB.request(
+      "GET",
+      "/test_suite_db/_design/test/_show/circular_require"
+    );
+    TEquals(200, xhr.status);
+    TEquals("One", xhr.responseText);
+
+    // Test that changes to the design doc properly invalidate cached modules:
+
+    // update the designDoc and replace
+    designDoc.whatever.commonjs.circular_one = "exports.name = 'Updated';"
+    T(db.save(designDoc).ok);
+
+    // request circular_require show function again and check the response has
+    // changed
+    xhr = CouchDB.request(
+      "GET",
+      "/test_suite_db/_design/test/_show/circular_require"
+    );
+    TEquals(200, xhr.status);
+    TEquals("Updated", xhr.responseText);
+
+
+    // test module id values are as expected:
+    xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest1");
+    TEquals(200, xhr.status);
+    TEquals("whatever/idtest1/a/c/e", xhr.responseText);
+
+    xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest2");
+    TEquals(200, xhr.status);
+    TEquals("whatever/idtest2/a/c/e", xhr.responseText);
+
+    xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest3");
+    TEquals(200, xhr.status);
+    TEquals("whatever/idtest3/a/c/e", xhr.responseText);
+
+    xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest4");
+    TEquals(200, xhr.status);
+    TEquals("whatever/idtest4/a/c/e", xhr.responseText);
+
+    xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest5");
+    TEquals(200, xhr.status);
+    TEquals("whatever/idtest5/b", xhr.responseText);
+
+
     var prev_view_sig = db.designInfo("_design/test").view_index.signature;
     var prev_view_size = db.designInfo("_design/test").view_index.disk_size;