Permalink
Browse files

update the readme to point to the official repo

  • Loading branch information...
1 parent f9e623e commit 03d94fdaf3da19ed3891cd3b4939c65c527dbfc1 @jchris committed Feb 20, 2010
Showing with 7 additions and 3,317 deletions.
  1. +0 −24 INSTALLING.md
  2. +0 −176 LICENSE
  3. +0 −11 LICENSE_YUI
  4. +0 −8 MANIFEST.in
  5. +7 −201 README.md
  6. +0 −19 Rakefile
  7. +0 −9 THANKS.txt
  8. +0 −26 app-template/_attachments/index.html
  9. +0 −1 app-template/_attachments/style/main.css
  10. +0 −9 app-template/foo/bar.txt
  11. +0 −2 app-template/lib/helpers/math.js
  12. +0 −32 app-template/lib/helpers/template.js
  13. +0 −26 app-template/lib/templates/example.html
  14. +0 −30 app-template/lists/feed.js
  15. +0 −16 app-template/shows/example-show.js
  16. +0 −9 app-template/views/example/map.js
  17. +0 −10 app-template/views/example/reduce.js
  18. +0 −276 ez_setup.py
  19. +0 −14 python/couchapp/__init__.py
  20. +0 −38 python/couchapp/_external/git.sh
  21. 0 python/couchapp/bin/__init__.py
  22. +0 −198 python/couchapp/bin/couchapp_cli.py
  23. +0 −964 python/couchapp/file_manager.py
  24. +0 −136 python/couchapp/utils/__init__.py
  25. +0 −89 python/couchapp/utils/css_parser.py
  26. +0 −272 python/couchapp/utils/jsmin.c
  27. +0 −219 python/couchapp/utils/jsmin.py
  28. BIN python/couchapp/utils/yuicompressor-2.4.1.jar
  29. +0 −37 python/couchapp/utils/yuicompressor.py
  30. 0 python/test/in_couchapp/installed/.couchapprc
  31. 0 python/test/in_couchapp/no_install/.gitignore
  32. +0 −30 python/test/test.py
  33. +0 −1 ruby/spec/.gitignore
  34. +0 −181 ruby/spec/couchapp_spec.rb
  35. +0 −6 ruby/spec/spec.opts
  36. +0 −19 ruby/spec/spec_helper.rb
  37. +0 −101 setup.py
  38. +0 −3 vendor/couchapp/README.md
  39. +0 −1 vendor/couchapp/couchapp.js
  40. +0 −23 vendor/couchapp/date.js
  41. +0 −67 vendor/couchapp/path.js
  42. +0 −33 vendor/couchapp/template.js
View
24 INSTALLING.md
@@ -1,24 +0,0 @@
-# Installing
-
-## Python
-
-If `sudo easy_install couchapp` doesn't work for you, you can install from source.
-
- git clone git://github.com/couchapp/couchapp.git
- cd couchapp
- sudo python setup.py install
-
-You may need to satisfy some dependencies. We hope this will happen automatically but... you never know.
-
-
-## Simplejson Dependency
-
-If you are on stock Mac OS X 10.5 Leopard, your version of setuptools is out of date. If your installation of couchapp fails with "error: Could not find required distribution simplejson", try running
-
- sudo easy_install -U couchapp
-
-## Questions and Comments
-
-If you can improve this documentation, please send pull requests using Github or hit the [CouchApp mailing list](http://groups.google.com/group/couchapp).
-
-We want the install experience to go smoothly for **everyone**, so please send feedback and let us help you make this documentation cover troubleshooting problems.
View
176 LICENSE
@@ -1,176 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
View
11 LICENSE_YUI
@@ -1,11 +0,0 @@
-Copyright (c) 2009, Yahoo! Inc.
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this list of conditions and the
- following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- * Neither the name of Yahoo! Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Yahoo! Inc.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
8 MANIFEST.in
@@ -1,8 +0,0 @@
-include INSTALLING.md
-include LICENSE
-include README.md
-include THANKS.txt
-include ez_setup.py
-recursive-include app-template *
-recursive-include vendor *
-recursive-include python/couchapp/_external *
View
208 README.md 100755 → 100644
@@ -1,206 +1,12 @@
-# CouchApp: Standalone CouchDB Application Development Made Simple
+## These are not the codes you are looking for.
-CouchApp is designed to structure standalone CouchDB application development for maximum application portability.
+CouchApp development has moved to an official project repository.
-CouchApp is a set of scripts and a [jQuery](http://jquery.com) plugin designed to bring clarity and order to the freedom of [CouchDB](http://couchdb.org)'s document-based approach.
+[http://github.com/couchapp/couchapp](http://github.com/couchapp/couchapp)
-### Write apps using just JavaScript and HTML
+Please ignore jchris/couchapp and look to couchapp/couchapp for the real code.
-Render HTML documents using JavaScript templates run by CouchDB. You'll get parallelism and cacheability, **using only HTML and JS.** Building standalone CouchDB applications according to correct principles affords you options not found on other platforms.
+You might try just installing via `sudo easy_install couchapp` if you aren't interested in writing patches to CouchApp itself.
-### Deploy your apps to the client
-
-CouchDB's replication means that programs running locally, can still be social. Applications control replication data-flows, so publishing messages and subscribing to other people is easy. Your users will see the benefits of the web without the hassle of requiring always-on connectivity.
-
-## Installation
-
- sudo easy_install couchapp
-
-If this gives you trouble, see the INSTALLING file for more options.
-
-### Begin Here
-
-Once you run `couchapp generate relax && cd relax`, you're ready to get started. Views are found in the `views` directory, attachments are stored in the `_attachments` directory, forms functions are stored in `list` and `show`, and the generation script drops in additional explantory files.
-
-
-## There's more to Couch than this
-
-CouchApp *is by no means the only way to use CouchDB*. CouchDB's technical roots make it well suited for **very large installations**. CouchDB excels at document management, archived stream processing (like logs or messaging), and other applications with voluminous data.
-
-CouchApp concentrates instead on a more personal use case: **developing and deploying standalone applications to CouchDB instances around the web.**
-
-### It's the portability
-
-There are apps you can build with server-side components that you can't build with just CouchApp. But by the same token, there are apps you can build on CouchApp alone that you can't build any other way. The flexibility of replication means that there are yet-undiscovered ways to mix datacenter level clusters with end-user installations.
-
-# Usage
-
-To upload your application to a CouchDB database, run this command from within you application directory. In this example we assume you have a copy of CouchDB running on your local machine.
-
-## Push
-
- couchapp push http://localhost:5984/mydb
-
-You can use this URL-form to send credentials data if you need to:
-
-`http://login:password@my.couchapp.com:5984/myapp`
-
-At the bottom of this readme there is information about the `.couchapprc` file. You want to read this and use it. It will make you happy because you won't need to specify the database URL to push.
-
-### Push Helper Macros
-
-CouchApp provides some neat helpers for getting code into your view and render functions. Look in the view files created by a generated app to see the usage for the `!code` and `!json` preprocessor macros. They are basically just two different ways to get more code into your functions.
-
-### !code for code
-
-The `!code path/to/code.js` macro inserts the content of the named file, into the current file, at the position of the macro. Here's an example:
-
- function(doc) {
- // !code lib/parsers/parse_html.js
- var parsed = new parseHTML(doc.html);
- emit(doc.key, parsed);
- }
-
-When you run `couchapp push` the `!code` line will be replaced with the contents of the file found at `lib/parsers/parse_html.js`. Simple as that.
-
-As we begin to see more apps built using CouchApp, we plan to include helpful functions in the standard library (as supplied by `couchapp generate`). Thank you for helping us expand this section! :)
-
-### !json for data
-
-After all the `!code` includes have been processed (insuring that included code may also use the `!json` macro), `couchapp push` does another pass through the function, running the `!json path.to.json` macros. This accumulates the data found in the JSON design doc at `path.to.json` into a single object for inclusion. After all the `!json` macros have been processed, the accumlated object is serialized to json and stored in variable names corresponding to their path's roots.
-
-The JSON paths use JavaScript style dot notation. Address the nodes as though you are running inside a `with(designDoc){ ... }` block. See the examples below.
-
-Here's an example. It's a lot of code to look at, but the principles are simple. Also, if you think you can explain it better than I have, please send a patch.
-
-#### A Subset of the Design Doc Fields (for context)
-
- {
- "lib" : {
- "templates" : {
- "post" : "<html> ... </html>",
- "comment" : "<html> ... </html>"
- },
- "render" : {
- "html" : "function(template, object){...}"
- }
- },
- "blog" : {
- "title" : "My Rad Blog"
- }
- }
-
-#### The Function
-
- function(doc) {
- // !json lib.templates.post
- // !json blog.title
- ...
- doSomething(lib.templates.post, blog.title);
- }
-
-#### The Result
-
- function(doc) {
- var lib = {
- "templates" : {
- "post" : "<html> ... </html>"
- }
- };
- var blog = {
- "title" : "My Rad Blog"
- };
- ...
- doSomething(lib.templates.post, blog.title);
- }
-
-The upshot is that only the requested fields are included in the function. This allows you to put as many templates and libraries in your design doc as you wish, without creating overlong functions.
-
-#### Silly Counter-example
-
- function(doc) {
- // !json lib
- // !json lib.templates.post
- }
-
-In this example, the second usage of the macro is redundant, as the first usage will include the entire `lib` field as a JSON macro.
-
-#### Sharing Code From Attachments into Views, Lists, and Shows
-
-!json and !code now work agains _attachments/ .
-
- // !json _attachments/file.ext
-
-will create the variable _attachments['file.ext'].
-
- // !code _attachments/file.ext
-
-will include content of the file.
-
-For anything but _attachments, the include should use ".", so this change don't break the current behaviour. Duplicate property name (two files with same name but different extension) now print an error in verbose level = 2.
-
-### Deployment preferences in `.couchapprc`
-
-You can set up application level helpers in the `.couchapprc` file
-
-The format is like this:
-
- {
- "env": {
- "default": {
- "db": "http://user:pass@localhost:5984/myapp-dev"
- },
- "production": {
- "db": "http:///user:pass@example.com/myapp"
- }
- }
- }
-
-When you've setup `.couchapprc` you can push your app with just `couchapp push` or for non-default environments `couchapp push production`. This also has the advantage of not requiring password use on the command line. The `.couchapprc` file is not pushed with the rest of the design doc, but please be careful not to accidentally check your `.couchapprc` file into Git!
-
-## Clone
-
-Clone downloads apps from other databases around the internet, all you have to do is point to the design doc url. Usage instructions will be here soon.
-
-## Vendor
-
-Handle vendor update and install from a git repository. Each vendor app should be in a vendor folder:
-
- vendor/appname
-
-To update a vendor folder in your couchapp:
-
- couchapp vendor update <app dir>
-
-Or from within the app dir:
-
- couchapp vendor update
-
-To install a vendor app:
-
- couchapp vendor install git://somerepo [app dir]
-
-Example:
-
- couchapp vendor install git://github.com/jchris/couchapp.git
-
-CouchApp's JavaScript library is a vendor (the one right above this line) and it is installed by default in new generators.
-
-# Community
-
-There is a mailing list here: [http://groups.google.com/group/couchapp](http://groups.google.com/group/couchapp)
-
-Also, join us on [irc.freenode.net in the #couchapp room](irc://irc.freenode.net/couchapp).
-
-### Apps Using CouchApp
-
-There are a few apps out there already using CouchApp. Please send a pull request adding yours to the list if you're using it too.
-
-* [Sofa](http://github.com/jchris/sofa)
-* [Couch-Wiki](http://github.com/janl/couch-wiki)
-* [CouchDB Twitter Client](http://github.com/jchris/couchdb-twitter-client)
-
-
-## License
-
-CouchApp is licensed under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0)
+Cheers,
+Chris
View
19 Rakefile
@@ -1,19 +0,0 @@
-require 'rake'
-
-begin
- require 'spec/rake/spectask'
-rescue LoadError
- puts <<-EOS
-To use rspec for testing you must install rspec gem:
- gem install rspec
-EOS
- exit(0)
-end
-
-desc "Run Ruby specs on the Python version"
-task :python do
- system "ruby ruby/spec/couchapp_spec.rb -- python"
-end
-
-desc "Run the rspec"
-task :default => :python
View
9 THANKS.txt
@@ -1,9 +0,0 @@
-CouchApp THANKS
-=====================
-
-A number of people have contributed to CouchApp by reporting problems,
-suggesting improvements, submitting changes or asking hard question
-
-Some of these people are:
-
-* Andy Wenk <andy.wenk@googlemail.com>
View
26 app-template/_attachments/index.html
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Generated CouchApp</title>
- <link rel="stylesheet" href="style/main.css" type="text/css">
- </head>
- <body>
- <h1>Generated CouchApp</h1>
- <ul id="view"></ul>
- </body>
- <script src="/_utils/script/json2.js"></script>
- <script src="/_utils/script/jquery.js?1.2.6"></script>
- <script src="/_utils/script/jquery.couch.js?0.8.0"></script>
- <script type="text/javascript" charset="utf-8">
- $(function() {
- var dbname = document.location.href.split('/')[3];
- var design = unescape(document.location.href).split('/')[5];
- var DB = $.couch.db(dbname);
- DB.view(design+"/example",{success: function(json) {
- $("#view").html(json.rows.map(function(row) {
- return '<li>'+row.key+'</li>';
- }).join(''));
- }});
- });
- </script>
-</html>
View
1 app-template/_attachments/style/main.css
@@ -1 +0,0 @@
-/* add styles here */
View
9 app-template/foo/bar.txt
@@ -1,9 +0,0 @@
-Couchapp will create a field on your document corresponding to any directories you make within the application directory, with the text of any files found as key/value pairs.
-
-Also, any files that end in .json will be treated as json rather than text, and put in the corresponding field. Also note that file.json, file.js, or file.txt will be stored under the "file" key, so don't make collisions in the filesystem unless you want unpredictable results.
-
-Of course you know that the views, shows, and lists directories will be treated specially, as those files are processed with the !code and !json macros.
-
-ps: each design document only has one language key: CouchDB defaults to Javascript, so that's what you'll get if you don't express otherwise. The way to switch to a different langauge is to edit the file in the approot called "language", changing "javascript" for instance into "python".
-
-Oh yeah it's recommended that you delete this file.
View
2 app-template/lib/helpers/math.js
@@ -1,2 +0,0 @@
-// this is just a placeholder for example purposes
-function stddev() {};
View
32 app-template/lib/helpers/template.js
@@ -1,32 +0,0 @@
-// Simple JavaScript Templating
-// John Resig - http://ejohn.org/ - MIT Licensed
-var cache = {};
-
-function template(str, data){
- // Figure out if we're getting a template, or if we need to
- // load the template - and be sure to cache the result.
- var fn = cache[str] ||
-
- // Generate a reusable function that will serve as a template
- // generator (and which will be cached).
- new Function("obj",
- "var p=[],print=function(){p.push.apply(p,arguments);};" +
-
- // Introduce the data as local variables using with(){}
- "with(obj){p.push('" +
-
- // Convert the template into pure JavaScript
- str
- .replace(/[\r\t\n]/g, " ")
- .replace(/'(?=[^%]*%>)/g,"\t")
- .split("'").join("\\'")
- .split("\t").join("'")
- .replace(/<%=(.+?)%>/g, "',$1,'")
- .split("<%").join("');")
- .split("%>").join("p.push('")
- + "');}return p.join('');");
- cache[str] = fn;
-
- // Provide some basic currying to the user
- return data ? fn( data ) : fn;
-};
View
26 app-template/lib/templates/example.html
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Generated CouchApp Form Template</title>
- </head>
- <body>
- <div id="header">
- <h2><a href="index.html">Back to index</a></h2>
- </div>
- <div id="content">
- <h1><% doc.title %></h1>
- </div>
- </body>
- <script src="/_utils/script/json2.js"></script>
- <script src="/_utils/script/jquery.js?1.2.6"></script>
- <script src="/_utils/script/jquery.couch.js?0.8.0"></script>
- <script src="<% attachPath %>/jquery.couchapp.js"></script>
- <script src="blog.js"></script>
- <script type="text/javascript" charset="utf-8">
- $.CouchApp(function(app) {
- var docid = document.location.pathname.split('/').pop();
- // hey you could run a query to load more information from views
- });
- </script>
- <script src="showdown.js"></script>
-</html>
View
30 app-template/lists/feed.js
@@ -1,30 +0,0 @@
-function(head, row, req) {
- respondWith(req, {
- html : function() {
- if (head) {
- return '<html><h1>Listing</h1> total rows: '+head.row_count+'<ul/>';
- } else if (row) {
- return '\n<li>Id:' + row.id + '</li>';
- } else {
- return '</ul></html>';
- }
- },
- xml : function() {
- if (head) {
- return {body:'<feed xmlns="http://www.w3.org/2005/Atom">'
- +'<title>Test XML Feed</title>'};
- } else if (row) {
- // Becase Safari can't stand to see that dastardly
- // E4X outside of a string. Outside of tests you
- // can just use E4X literals.
- var entry = new XML('<entry/>');
- entry.id = row.id;
- entry.title = row.key;
- entry.content = row.value;
- return {body:entry};
- } else {
- return {body : "</feed>"};
- }
- }
- })
-};
View
16 app-template/shows/example-show.js
@@ -1,16 +0,0 @@
-function(doc, req) {
- // !code lib/helpers/template.js
- // !json lib.templates
-
- respondWith(req, {
- html : function() {
- var html = template(lib.templates.example, doc);
- return {body:html}
- },
- xml : function() {
- return {
- body : <xml><node value={doc.title}/></xml>
- }
- }
- })
-};
View
9 app-template/views/example/map.js
@@ -1,9 +0,0 @@
-// an example map function, emits the doc id
-// and the list of keys it contains
-// !code lib/helpers/math.js
-
-function(doc) {
- var k, keys = []
- for (k in doc) keys.push(k);
- emit(doc._id, keys);
-};
View
10 app-template/views/example/reduce.js
@@ -1,10 +0,0 @@
-// example reduce function to count the
-// number of rows in a given key range.
-
-function(keys, values, rereduce) {
- if (rereduce) {
- return sum(values);
- } else {
- return values.length;
- }
-};
View
276 ez_setup.py
@@ -1,276 +0,0 @@
-#!python
-"""Bootstrap setuptools installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
- from ez_setup import use_setuptools
- use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import sys
-DEFAULT_VERSION = "0.6c7"
-DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
-
-md5_data = {
- 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
- 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
- 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
- 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
- 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
- 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
- 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
- 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
- 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
- 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
- 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
- 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
- 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
- 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
- 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
- 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
- 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
- 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
- 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
- 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
- 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
- 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
- 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
- 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
- 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
- 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
- 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
- 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
- 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
- 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
- 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
- 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
- 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
- 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
-}
-
-import sys, os
-try: from hashlib import md5
-except ImportError: from md5 import md5
-
-def _validate_md5(egg_name, data):
- if egg_name in md5_data:
- digest = md5(data).hexdigest()
- if digest != md5_data[egg_name]:
- print >>sys.stderr, (
- "md5 validation of %s failed! (Possible download problem?)"
- % egg_name
- )
- sys.exit(2)
- return data
-
-def use_setuptools(
- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
- download_delay=15
-):
- """Automatically find/download setuptools and make it available on sys.path
-
- `version` should be a valid setuptools version number that is available
- as an egg for download under the `download_base` URL (which should end with
- a '/'). `to_dir` is the directory where setuptools will be downloaded, if
- it is not already available. If `download_delay` is specified, it should
- be the number of seconds that will be paused before initiating a download,
- should one be required. If an older version of setuptools is installed,
- this routine will print a message to ``sys.stderr`` and raise SystemExit in
- an attempt to abort the calling script.
- """
- was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
- def do_download():
- egg = download_setuptools(version, download_base, to_dir, download_delay)
- sys.path.insert(0, egg)
- import setuptools; setuptools.bootstrap_install_from = egg
- try:
- import pkg_resources
- except ImportError:
- return do_download()
- try:
- pkg_resources.require("setuptools>="+version); return
- except pkg_resources.VersionConflict, e:
- if was_imported:
- print >>sys.stderr, (
- "The required version of setuptools (>=%s) is not available, and\n"
- "can't be installed while this script is running. Please install\n"
- " a more recent version first, using 'easy_install -U setuptools'."
- "\n\n(Currently using %r)"
- ) % (version, e.args[0])
- sys.exit(2)
- else:
- del pkg_resources, sys.modules['pkg_resources'] # reload ok
- return do_download()
- except pkg_resources.DistributionNotFound:
- return do_download()
-
-def download_setuptools(
- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
- delay = 15
-):
- """Download setuptools from a specified location and return its filename
-
- `version` should be a valid setuptools version number that is available
- as an egg for download under the `download_base` URL (which should end
- with a '/'). `to_dir` is the directory where the egg will be downloaded.
- `delay` is the number of seconds to pause before an actual download attempt.
- """
- import urllib2, shutil
- egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
- url = download_base + egg_name
- saveto = os.path.join(to_dir, egg_name)
- src = dst = None
- if not os.path.exists(saveto): # Avoid repeated downloads
- try:
- from distutils import log
- if delay:
- log.warn("""
----------------------------------------------------------------------------
-This script requires setuptools version %s to run (even to display
-help). I will attempt to download it for you (from
-%s), but
-you may need to enable firewall access for this script first.
-I will start the download in %d seconds.
-
-(Note: if this machine does not have network access, please obtain the file
-
- %s
-
-and place it in this directory before rerunning this script.)
----------------------------------------------------------------------------""",
- version, download_base, delay, url
- ); from time import sleep; sleep(delay)
- log.warn("Downloading %s", url)
- src = urllib2.urlopen(url)
- # Read/write all in one block, so we don't create a corrupt file
- # if the download is interrupted.
- data = _validate_md5(egg_name, src.read())
- dst = open(saveto,"wb"); dst.write(data)
- finally:
- if src: src.close()
- if dst: dst.close()
- return os.path.realpath(saveto)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-def main(argv, version=DEFAULT_VERSION):
- """Install or upgrade setuptools and EasyInstall"""
- try:
- import setuptools
- except ImportError:
- egg = None
- try:
- egg = download_setuptools(version, delay=0)
- sys.path.insert(0,egg)
- from setuptools.command.easy_install import main
- return main(list(argv)+[egg]) # we're done here
- finally:
- if egg and os.path.exists(egg):
- os.unlink(egg)
- else:
- if setuptools.__version__ == '0.0.1':
- print >>sys.stderr, (
- "You have an obsolete version of setuptools installed. Please\n"
- "remove it from your system entirely before rerunning this script."
- )
- sys.exit(2)
-
- req = "setuptools>="+version
- import pkg_resources
- try:
- pkg_resources.require(req)
- except pkg_resources.VersionConflict:
- try:
- from setuptools.command.easy_install import main
- except ImportError:
- from easy_install import main
- main(list(argv)+[download_setuptools(delay=0)])
- sys.exit(0) # try to force an exit
- else:
- if argv:
- from setuptools.command.easy_install import main
- main(argv)
- else:
- print "Setuptools version",version,"or greater has been installed."
- print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
-
-def update_md5(filenames):
- """Update our built-in md5 registry"""
-
- import re
-
- for name in filenames:
- base = os.path.basename(name)
- f = open(name,'rb')
- md5_data[base] = md5(f.read()).hexdigest()
- f.close()
-
- data = [" %r: %r,\n" % it for it in md5_data.items()]
- data.sort()
- repl = "".join(data)
-
- import inspect
- srcfile = inspect.getsourcefile(sys.modules[__name__])
- f = open(srcfile, 'rb'); src = f.read(); f.close()
-
- match = re.search("\nmd5_data = {\n([^}]+)}", src)
- if not match:
- print >>sys.stderr, "Internal error!"
- sys.exit(2)
-
- src = src[:match.start(1)] + repl + src[match.end(1):]
- f = open(srcfile,'w')
- f.write(src)
- f.close()
-
-
-if __name__=='__main__':
- if len(sys.argv)>2 and sys.argv[1]=='--md5update':
- update_md5(sys.argv[2:])
- else:
- main(sys.argv[1:])
-
-
-
-
-
-
View
14 python/couchapp/__init__.py
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2009 Benoit Chesneau <benoitc@e-engura.org>
-#
-# This software is licensed as described in the file LICENSE, which
-# you should have received as part of this distribution.
-
-try:
- __version__ = __import__('pkg_resources').get_distribution('Couchapp').version
-except:
- __version__ = '?'
-
-from couchapp.file_manager import FileManager
View
38 python/couchapp/_external/git.sh
@@ -1,38 +0,0 @@
-#!/bin/sh
-
-GIT=`which git`
-tempfile=`mktemp /tmp/couchappXXXXXXX`
-
-
-rm $tempfile
-
-# get vendor files
-$GIT clone --depth=1 $2 $tempfile
-
-
-# delete existing files
-if [ $1 = "update" ]; then
- if [ -r $3 ]; then
- rm -rvf $3
- fi
-
- if [ -r $tempfile/vendor ]; then
- for f in $(find $tempfile/vendor -type d -depth 1); do
- if [ $f != "$tempfile/vendor" ]; then
- cp -vr $f $4
- fi
- done
-
- fi
-else
- if [ -r $tempfile/vendor ]; then
- ls $tempfile/vendor
- for f in $(find $tempfile/vendor -type d -depth 1); do
- if [ $f != "$tempfile/vendor" ]; then
- echo "$2" > $f/.new
- cp -rv $f $3
-
- fi
- done
- fi
-fi
View
0 python/couchapp/bin/__init__.py
No changes.
View
198 python/couchapp/bin/couchapp_cli.py
@@ -1,198 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2008 Jan Lehnardt <jan@apache.org>
-# Copyright 2009 Benoit Chesneau <benoitc@e-engura.org>
-#
-# This software is licensed as described in the file LICENSE, which
-# you should have received as part of this distribution.
-
-"""
-Script that pushes a file system hierarchy into a CouchDB design document.
-
-Good for pure Couch application development.
-
-A port of couchapp from Ruby (http://github.com/jchris/couchapp)
-"""
-
-import os
-import sys
-from optparse import OptionParser, OptionGroup
-
-
-import couchapp
-from couchapp.utils import in_couchapp
-
-
-def generate(appname, verbose=False):
- appdir = os.path.normpath(os.path.join(os.getcwd(), appname))
- if verbose >= 1:
- print "Generating a new CouchApp in %s" % appdir
- couchapp.FileManager.generate_app(appdir)
-
-def init(appdir, dburl, verbose=False):
- if verbose >= 1:
- print "Initializing a new CouchApp in %s" % appdir
- couchapp.FileManager.init(appdir, dburl)
-
-def push(appdir, appname, dbstring, verbose=False,
- options=None):
- try:
- fm = couchapp.FileManager(dbstring, appdir)
- except ValueError, e:
- print>>sys.stderr, e
- return
-
- fm.push_app(appdir, appname, verbose=verbose,
- nocss=options.css, nojs=options.js)
-
-def clone(app_uri, app_dir, verbose=False):
- couchapp.FileManager.clone(app_uri, app_dir, verbose=verbose)
-
-def vendor_update(app_dir, verbose=False):
- couchapp.FileManager.vendor_update(app_dir, verbose=verbose)
-
-def vendor_install(app_dir, url, scm='git', verbose=False):
- couchapp.FileManager.vendor_install(app_dir, url, scm=scm,
- verbose=verbose)
-
-def main():
- parser = OptionParser(usage='%prog [options] cmd', version="%prog " + couchapp.__version__)
- parser.add_option('-v', dest='verbose', default=1, help='print message to stdout')
- parser.add_option('-q', dest='verbose', action='store_const', const=0, help="don't print any message")
-
- # generate options
- parser.add_option_group(OptionGroup(parser, "Generate a new CouchApp! (start here)",
- "couchapp generate <appname> [appdir]"))
-
- # push options
- group_push = OptionGroup(parser, "Pushes a CouchApp to CouchDB",
- "couchapp push [options] [appdir] [appname] [dburl]")
- group_push.add_option("--disable-css", action="store_true",
- dest="css", help="disable css compression")
- group_push.add_option("--disable-js", action="store_true",
- dest="js", help="disable js compression")
- parser.add_option_group(group_push)
-
- # clone options
- parser.add_option_group(OptionGroup(parser,
- "Clones/Pulls a CouchApp from a url (like http://host/db/_design/CA_name)",
- "couchapp clone/pull <dburl> [dir]"))
-
- # init options
- group_init = OptionGroup(parser, "Initialize CouchApp .couchapprc", "couchapp init [options] <appdir>")
- group_init.add_option("--db", action="store", help="full url of default database")
- parser.add_option_group(group_init)
-
- group_vendor = OptionGroup(parser, "Install a vendor", "couchapp vendor install vendor_url [option][appdir]")
- group_vendor.add_option("--scm", action="store", default='git',
- help="scm used to install the vendor, by default git")
- parser.add_option_group(group_vendor)
-
- options, args = parser.parse_args()
-
-
- if len(args) < 1:
- return parser.error('incorrect number of arguments')
-
- if args[0] == 'generate':
- if len(args) < 2:
- return parser.error('cmd: "generate appname"'+
- '\n\nIncorrect number of arguments, appname is'+
- ' missing')
- appname = args[1]
- generate(appname, options.verbose)
- elif args[0] == 'push':
- appname = ''
- rel_path = '.'
- dbstring = ''
- # generate [dir] [appname] [url] case
- if len(args) == 4:
- if in_couchapp():
- return parser.error('Incorrect number of arguments, you\'re in an app.')
- rel_path = args[1]
- appname = args[2]
- dbstring = args[3]
-
- # generate [dir/appname] [url] case
- elif len(args) == 3:
- rel_path = in_couchapp()
- if rel_path:
- if args[1] != '.':
- appname = args[1]
- dbstring = args[2]
- else:
- rel_path = args[1]
- dbstring = args[2]
-
- # generate [dir/url] case
- elif len(args) == 2:
- rel_path = in_couchapp()
- if rel_path:
- if args[1] != '.':
- dbstring = args[1]
- else:
- rel_path = args[1]
-
- # just generate
- elif len(args) == 1:
- rel_path = in_couchapp()
- if not rel_path:
- rel_path = '.'
-
- appdir = os.path.normpath(os.path.join(os.getcwd(), rel_path))
- # Derive appname from the directory name (/home/foo/sofa => sofa)
- if not appname:
- appname = ''.join(appdir.split('/')[-1:])
- # PUSH IT!
- push(appdir, appname, dbstring, options.verbose, options=options)
-
- elif args[0] == 'clone' or args[0] == 'pull':
- if len(args) < 2:
- return parser.error('Incorrect number of arguments (at least two)')
- # clone/pull <url> [dir] case
- if len(args) == 3:
- app_dir = args[2]
- # clone/pull <url>
- else:
- app_dir = ''
- # CLONE IT!
- clone(args[1], app_dir, options.verbose)
-
- elif args[0] == 'init':
- dburl = options.db or ''
- try:
- appdir = args[1]
- except IndexError:
- appdir = '.'
- init(appdir, dburl, options.verbose)
- elif args[0] == 'vendor':
- if len(args) < 2:
- return parser.error('Incorrect number of arguments (at least two)')
-
-
- action = args[1]
- if action == 'update':
- try:
- appdir = args[2]
- except IndexError:
- appdir = '.'
- vendor_update(appdir, options.verbose)
- elif action == 'install':
- if len(args) < 3:
- return parser.error('Incorrect number of arguments')
-
- try:
- appdir = args[3]
- except IndexError:
- appdir = '.'
- vendor_install(appdir, args[2], options.scm, options.verbose)
- else:
- print >>sys.stderr, "%s is an unknown vendor action, sorry." % action
-
-
- else:
- print "%s is an unknown command, sorry." % args[0]
-
-if __name__ == '__main__':
- main()
View
964 python/couchapp/file_manager.py
@@ -1,964 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2009 Benoit Chesneau <benoitc@e-engura.org>
-#
-# This software is licensed as described in the file LICENSE, which
-# you should have received as part of this distribution.
-#
-
-import glob
-import httplib
-import os
-import re
-import shutil
-import socket
-import sys
-import time
-import urllib
-
-# python 2.6
-try:
- import json
-except ImportError:
- import simplejson as json
-
-# backport os.path.relpath if python < 2.6
-try:
- import os.path.relpath as _relpath
-except ImportError:
- def _relpath(path, start=os.curdir):
- if not path:
- raise ValueError("no path specified")
-
- start_list = os.path.abspath(start).split("/")
- path_list = os.path.abspath(path).split("/")
-
- # Work out how much of the filepath is shared by start and path.
- i = len(os.path.commonprefix([start_list, path_list]))
-
- rel_list = ['..'] * (len(start_list)-i) + path_list[i:]
- if not rel_list:
- return os.curdir
- return os.path.join(*rel_list)
-
-try:#python 2.6, use subprocess
- from subprocess import *
- def _popen3(cmd, mode='t', bufsize=0):
- p = Popen(cmd, shell=True, bufsize=bufsize,
- stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
- return (p.stdin, p.stdout, p.stderr)
-except ImportError:
- def _popen3(cmd, mode='t', bufsize=0):
- return os.popen3(cmd, mode, bufsize)
-
-
-
-import httplib2
-from couchdb import Server, ResourceNotFound
-
-from couchapp.utils import _md5, to_bytestring
-from couchapp.utils import *
-from couchapp.utils.css_parser import CSSParser
-
-__all__ = ['DEFAULT_SERVER_URI', 'FileManager']
-
-DEFAULT_SERVER_URI = 'http://127.0.0.1:5984/'
-
-COUCHAPP_VENDOR_URL = 'git://github.com/jchris/couchapp.git'
-COUCHAPP_VENDOR_SCM = 'git'
-
-external_dir = os.path.join(os.path.dirname(__file__), '_external')
-VENDOR_HANDLERS = {
- 'git': os.path.join(external_dir, 'git.sh')
-}
-
-def _server(server_uri):
- if "@" in server_uri:
- http = httplib2.Http()
- username, password, server_uri = parse_auth(server_uri)
- couchdb_server = Server(server_uri)
- http.add_credentials(username, password)
- couchdb_server.resource.http = http
- else:
- couchdb_server = Server(server_uri)
- return couchdb_server
-
-def get_userconf():
- """ return user conf """
-
- # this should work on windows too
- homedir = os.path.expanduser('~')
- user_conffile = os.path.join(homedir, ".couchapprc")
- if os.path.isfile(user_conffile):
- try:
- return read_json(user_conffile)
- except:
- pass
- return {}
-
-def _vendor_handlers():
- user_conf = get_userconf()
- vendor_handlers = VENDOR_HANDLERS
- if "vendor_handlers" in user_conf:
- try:
- vendor_handler.update(user_conf['vendor_handlers'])
- except ValueError:
- pass
- return vendor_handlers
-
-class FileManager(object):
-
- def __init__(self, dbstring, app_dir='.'):
- self.app_dir = app_dir
-
- # load conf
- self.load_metadata(app_dir)
-
- if not dbstring or not "/" in dbstring:
- env = self.conf.get('env', {})
- if dbstring:
- if dbstring in env:
- db_env = env[dbstring]['db']
- else:
- db_env = "%s/%s" % (DEFAULT_SERVER_URI, dbstring)
- else:
- if 'default' in env:
- db_env = env['default']['db']
- else:
- raise ValueError("database isn't specified")
-
- if isinstance(db_env, basestring):
- self.db_url = [db_env]
- else:
- self.db_url = db_env
- else:
- self.db_url = [dbstring]
-
- db = []
- for s in self.db_url:
- server_uri, db_name, docid = parse_uri(s)
-
- couchdb_server = _server(server_uri)
-
- # create dbs if it don't exist
- try:
- _db = couchdb_server.create(db_name)
- except: # db already exist
- _db = couchdb_server[db_name]
- db.append(_db)
- self.db = db
-
- self.conf = get_userconf()
-
-
- @classmethod
- def generate_app(cls, app_dir):
- """Generates a CouchApp in app_dir"""
- template_paths = ['app-template', '../../app-template']
- vendor_paths = ['vendor', '../../vendor']
-
- for path in template_paths:
- template_dir = os.path.normpath(os.path.join(
- os.path.dirname(__file__), path))
- if os.path.isdir(template_dir): break
-
- for path in vendor_paths:
- vendor_dir = os.path.normpath(os.path.join(
- os.path.dirname(__file__), path))
- if os.path.isdir(vendor_dir): break
-
- try:
- shutil.copytree(template_dir, app_dir)
- except OSError, e:
- errno, message = e
- print >>sys.stderr, "Can't create a CouchApp in %s: %s" % (
- app_dir, message)
- return
-
- if vendor_dir:
- vendor_path = os.path.join(app_dir, 'vendor')
- try:
- shutil.copytree(vendor_dir, vendor_path)
- except OSError, e:
- errno, message = e
- print >>sys.stderr, "Can't create a CouchApp, bad vendor dir: %s" % message
- return
-
- cls.init(app_dir)
-
- @classmethod
- def init(cls, app_dir, db_url=''):
- """Initializes the .couchapprc, usually called after generate"""
- if not os.path.isdir(app_dir):
- print>>sys.stderr, "%s directory doesn't exist." % app_dir
- return
-
- userconf = get_userconf()
- if 'default' in userconf:
- conf = {
- "env": {
- "default": userconf['env']['default']
- }
- }
- else:
- conf = {}
-
- rc_file = '%s/.couchapprc' % app_dir
- if not os.path.isfile(rc_file):
- if db_url:
- conf.update({ "env": {
- "default": {
- "db": db_url
- }
- }})
-
- write_json(rc_file, conf)
- else:
- print>>sys.stderr, "CouchApp already initialized in %s." % app_dir
-
- def load_metadata(self, app_dir):
- """Reads the .couchapprc to get configuration data"""
- rc_file = os.path.join(app_dir, '.couchapprc')
- conf = get_userconf()
- if os.path.isfile(rc_file):
- conf.update(read_json(rc_file, use_environment=True))
- self.conf = conf
-
- def push_app(self, app_dir, app_name, verbose=False, **kwargs):
- """Pushes the app specified to the CouchDB instance"""
- docid = '_design/%s' % app_name
-
- attach_dir = os.path.join(app_dir, '_attachments')
-
- manifest = []
- self.doc = doc = self.dir_to_fields(app_dir, manifest=manifest,
- verbose=verbose)
-
- self.objects = {}
- if 'shows' in doc:
- self.package_shows(doc['shows'], app_dir, verbose=verbose)
-
- if 'lists' in doc:
- self.package_shows(doc['lists'], app_dir, verbose=verbose)
-
- if 'validate_doc_update' in doc:
- tmp_dict = dict(validate_doc_update=doc["validate_doc_update"])
- self.package_shows(tmp_dict, app_dir, verbose=verbose)
- doc.update(tmp_dict)
-
- if 'views' in doc:
- self.package_views(doc["views"], app_dir, verbose=verbose)
-
-
- for db in self.db:
- if verbose >= 1:
- print "Pushing CouchApp in %s to design doc:\n%s/_design/%s" % (app_dir,
- db.resource.uri, app_name)
- couchapp = doc.get('couchapp', False)
- if couchapp:
- index = couchapp.get('index', False)
- else:
- index = False
- index_url = self.make_index_url(db.resource.uri, app_name, attach_dir, index)
- if index_url:
- print "Visit your CouchApp here:\n%s" % index_url
-
- new_doc = doc.copy()
-
- if docid in db:
- design = db[docid]
-
- _app_meta = design.get('couchapp', {})
-
- app_meta = {
- 'manifest': manifest,
- 'signatures': _app_meta.get('signatures', {}),
- 'objects': self.objects
- }
-
- new_doc.update({
- '_id': docid,
- '_rev': design['_rev'],
- 'couchapp': app_meta,
- '_attachments': design.get('_attachments', {})
- })
- else:
- new_doc.update({
- 'couchapp': {
- 'manifest': manifest,
- 'objects': self.objects
- }
- })
-
- if 'couchapp' in doc:
- new_doc['couchapp'].update(doc['couchapp'])
-
- db[docid] = new_doc
-
- if 'css' in new_doc['couchapp']:
- if not kwargs.get('nocss', False):
- # merge and compress css
- self.merge_css(attach_dir, doc['couchapp']['css'],
- docid, verbose=verbose)
-
- if 'js' in new_doc['couchapp']:
- if not kwargs.get('nojs', False):
- # merge and compress js
- self.merge_js(attach_dir, doc['couchapp']['js'],
- docid, verbose=verbose)
-
-
- self.push_directory(attach_dir, docid, verbose=verbose)
- self.vendor_attachments(app_dir, docid, verbose=verbose)
-
-
- @classmethod
- def clone(cls, app_uri, app_dir, verbose=False):
- """Clone a CouchApp from app_uri into app_dir"""
- server_uri, db_name, docid = parse_uri(app_uri)
- couchdb_server = _server(server_uri)
-
- try:
- db = couchdb_server.create(db_name)
- except: # db already exist
- db = couchdb_server[db_name]
-
- app_name = get_appname(docid)
- if verbose >= 1:
- print "Cloning %s to %s..." % (app_name, app_dir)
- if not app_dir:
- app_dir = os.path.normpath(os.path.join(os.getcwd(), app_name))
-
- rc_file = os.path.join(app_dir, '.couchapprc')
-
- if not os.path.isdir(app_dir):
- os.makedirs(app_dir)
- else:
- # delete only if there is .couchapp folder
- if os.path.isfile(rc_file):
- for root, dirs, files in os.walk(app_dir,
- topdown=False):
- if root == app_dir:
- if '_attachments' in dirs:
- dirs.remove('_attachments')
- if '.couchapprc' in files:
- files.remove('.couchapprc')
- for name in files:
- os.remove(os.path.join(root, name))
-
- for name in dirs:
- os.rmdir(os.path.join(root, name))
-
- try:
- design = db[docid]
- except ResourceNotFound:
- print >>sys.stderr, "%s don't exist" % app_name
- return
-
- metadata = design.get('couchapp', {})
-
- # get manifest
- manifest = metadata.get('manifest', {})
-
- # get signatures
- signatures = metadata.get('signatures', {})
-
- # get objects refs
- objects = metadata.get('objects', {})
-
- conf = read_json(rc_file)
- if not 'env' in conf:
- conf['env'] = {}
- conf['env'].update({
- 'origin': {
- 'db': db.resource.uri
- }
- })
-
- write_json(rc_file, conf)
-
- # create files from manifest
- if manifest:
- for filename in manifest:
- if verbose >=2:
- print "clone property: %s" % filename
- file_path = os.path.join(app_dir, filename)
- if filename.endswith('/'):
- if not os.path.isdir(file_path):
- os.makedirs(file_path)
- elif filename == "couchapp.json":
- continue
- else:
- parts = filename.split('/')
- fname = parts.pop()
- v = design
- while 1:
- try:
- for key in parts:
- v = v[key]
- except KeyError:
- break
-
- # remove extension
- last_key, ext = os.path.splitext(fname)
-
- # make sure key exist
- try:
- content = v[last_key]
- except KeyError:
- break
-
- if isinstance(content, basestring):
- _ref = _md5(to_bytestring(content)).hexdigest()
- if objects and _ref in objects:
- content = objects[_ref]
-
- if fname.endswith('.json'):
- content = json.dumps(content)
-
- del v[last_key]
-
- # make sure file dir have been created
- file_dir = os.path.dirname(file_path)
- if not os.path.isdir(file_dir):
- os.makedirs(file_dir)
-
- write_content(file_path, content)
-
- # remove the key from design doc
- temp = design
- for key2 in parts:
- if key2 == key:
- if not temp[key2]:
- del temp[key2]
- break
- temp = temp[key2]
-
- # second pass for missing key or in case
- # manifest isn't in app
- for key in design.iterkeys():
- if key.startswith('_'):
- continue
- elif key in ('couchapp'):
- app_meta = design['couchapp'].copy()
- if 'signatures' in app_meta:
- del app_meta['signatures']
- if 'manifest' in app_meta:
- del app_meta['manifest']
- if 'objects' in app_meta:
- del app_meta['objects']
- if app_meta:
- couchapp_file = os.path.join(app_dir, 'couchapp.json')
- write_json(couchapp_file, app_meta)
- elif key in ('views'):
- vs_dir = os.path.join(app_dir, key)
- if not os.path.isdir(vs_dir):
- os.makedirs(vs_dir)
- for vsname, vs_item in design[key].iteritems():
- vs_item_dir = os.path.join(vs_dir, vsname)
- if not os.path.isdir(vs_item_dir):
- os.makedirs(vs_item_dir)
- for func_name, func in vs_item.iteritems():
- filename = os.path.join(vs_item_dir, '%s.js' %
- func_name)
- open(filename, 'w').write(func)
- if verbose >=2:
- print "clone view not in manifest: %s" % filename
- elif key in ('shows', 'lists'):
- dir = os.path.join(app_dir, key)
- if not os.path.isdir(dir):
- os.makedirs(dir)
- for func_name, func in design[key].iteritems():
- filename = os.path.join(dir, '%s.js' %
- func_name)
- open(filename, 'w').write(func)
- if verbose >=2:
- print "clone show or list not in manifest: %s" % filename
- else:
- file_dir = os.path.join(app_dir, key)
- if verbose >=2:
- print "clone property not in manifest: %s" % key
- if isinstance(design[key], (list, tuple,)):
- write_json(file_dir + ".json", design[key])
- elif isinstance(design[key], dict):
- if not os.path.isdir(file_dir):
- os.makedirs(file_dir)
- for field, value in design[key].iteritems():
- field_path = os.path.join(file_dir, field)
- if isinstance(value, basestring):
- write_content(field_path, value)
- else:
- write_json(field_path + '.json', value)
- else:
- value = design[key]
- if not isinstance(value, basestring):
- value = str(value)
- write_content(file_dir, value)
-
-
- # get attachments
- if '_attachments' in design:
- attach_dir = os.path.join(app_dir, '_attachments')
- if not os.path.isdir(attach_dir):
- os.makedirs(attach_dir)
- for filename in design['_attachments'].iterkeys():
- if filename.startswith('vendor'):
- attach_parts = filename.split('/')
- vendor_attach_dir = os.path.join(app_dir, attach_parts.pop(0),
- attach_parts.pop(0), '_attachments')
- file_path = os.path.join(vendor_attach_dir, '/'.join(attach_parts))
- else:
- file_path = os.path.join(attach_dir, filename)
- current_dir = os.path.dirname(file_path)
- if not os.path.isdir(current_dir):
- os.makedirs(current_dir)
-
- if signatures.get(filename) != sign_file(file_path):
- content = db.get_attachment(docid, filename)
- write_content(file_path, content)
- if verbose>=2:
- print "clone attachment: %s" % filename
-
- def dir_to_fields(self, app_dir, current_dir='', depth=0,
- manifest=[], verbose=False):
- fields={}
- if not current_dir:
- current_dir = app_dir
- for name in os.listdir(current_dir):
- current_path = os.path.join(current_dir, name)
- rel_path = current_path.split("%s/" % app_dir)[1]
- if name.startswith('.'):
- continue
- elif name.startswith('_'):
- # files starting with "_" are always "special"
- continue
- elif depth == 0 and name in ('couchapp', 'couchapp.json'):
- # we are in app_meta
- if name == "couchapp":
- manifest.append('%s/' % rel_path)
- content = self.dir_to_fields(app_dir, current_path,
- depth=depth+1, manifest=manifest)
- else:
- manifest.append(rel_path)
- content = read_json(current_path)
- if not isinstance(content, dict):
- content = { "meta": content }
- if 'signatures' in content:
- del content['signatures']
-
- if 'manifest' in content:
- del content['manifest']
-
- if 'objects' in content:
- del content['objects']
-
- if 'couchapp' in fields:
- fields['couchapp'].update(content)
- else:
- fields['couchapp'] = content
- elif os.path.isdir(current_path):
- manifest.append('%s/' % rel_path)
- fields[name] = self.dir_to_fields(app_dir, current_path,
- depth=depth+1, manifest=manifest,
- verbose=verbose)
- else:
- if verbose >= 2:
- print >>sys.stderr, "push %s" % rel_path
- content = ''
- try:
- content = read_file(current_path)
- except UnicodeDecodeError, e:
- print >>sys.stderr, str(e)
- if name.endswith('.json'):
- try:
- content = json.loads(content)
- except ValueError:
- if verbose >= 2:
- print >>sys.stderr, "Json invalid in %s" % current_path
-
- # remove extension
- name, ext = os.path.splitext(name)
- if name in fields:
- if verbose >= 2:
- print >>sys.stderr, "%(name)s is already in properties. Can't add (%(name)s%(ext)s)" % {
- "name": name,
- "ext": ext
- }
- else:
- manifest.append(rel_path)
- fields[name] = content
- return fields
-
- def _put_attachment(self, db, doc, content, filename):
- nb_try = 0
- while True:
- error = False
- try:
- db.put_attachment(doc, content, filename)
- except (socket.error, httplib.BadStatusLine):
- time.sleep(0.4)
- error = True
-
- nb_try = nb_try +1
- if not error:
- break
-
- if nb_try > 3:
- if verbose >= 2:
- print >>sys.stderr, "%s file not uploaded, sorry." % filename
- break
-
- def vendor_attachments(self, app_dir, docid, verbose):
- vendor_dir = os.path.join(app_dir, 'vendor')
- if not os.path.isdir(vendor_dir):
- return
-
- for name in os.listdir(vendor_dir):
- current_path = os.path.join(vendor_dir, name)
- if os.path.isdir(current_path):
- attach_dir = os.path.join(current_path, '_attachments')
- if os.path.isdir(attach_dir):
- self.push_directory(attach_dir, docid, verbose,
- vendor=name)
-
- def push_directory(self, attach_dir, docid, verbose=False, vendor=None):
- # get attachments
- _signatures = {}
- _attachments = {}
- all_signatures = {}
- for root, dirs, files in os.walk(attach_dir):
- if files:
- for filename in files:
- if filename.startswith('.'):
- continue
- else:
- file_path = os.path.join(root, filename)
- name = file_path.split('%s/' % attach_dir)[1]
- if vendor is not None:
- name = os.path.join('vendor/%s' % vendor, name)
- signature = sign_file(file_path)
- _signatures[name] = signature
- _attachments[name] = open(file_path, 'rb')
-
- # detect attachments to be removed and keep
- # only new version attachments to update.
- for db in self.db:
- design = db[docid]
- metadata = design.get('couchapp', {})
- attachments = _attachments.copy()
- if 'signatures' in metadata:
- all_signatures = metadata['signatures'].copy()
- for filename in metadata['signatures'].iterkeys():
- if vendor is not None:
- if filename.startswith('vendor/%s' % vendor):
- del all_signatures[filename]
- if filename not in _signatures:
- db.delete_attachment(design, filename)
- elif _signatures[filename] == metadata['signatures'][filename]:
- del attachments[filename]
-
- else:
- if not filename.startswith('vendor'):
- del all_signatures[filename]
- if filename not in _signatures:
- db.delete_attachment(design, filename)
- else:
- if _signatures[filename] == metadata['signatures'][filename]:
- del attachments[filename]
-
- for filename, value in attachments.iteritems():
- if verbose >= 2:
- print "Attaching %s" % filename
-
- # fix issue with httplib that raises BadStatusLine
- # error because it didn't close the connection
- self._put_attachment(db, design, value, filename)
-
- # update signatures
- design = db[docid]
- if not 'couchapp' in design:
- design['couchapp'] = {}
-
- all_signatures.update(_signatures)
-
- design['couchapp'].update({'signatures': all_signatures})
- db[docid] = design
-
- def package_shows(self, funcs, app_dir, verbose=False):
- self.apply_lib(funcs, app_dir, verbose=verbose)
-
- def package_views(self, views, app_dir, verbose=False):
- for view, funcs in views.iteritems():
- self.apply_lib(funcs, app_dir, verbose=verbose)
-
-
- def apply_lib(self, funcs, app_dir, verbose=False):
- if not hasattr(self, "objects"):
- self.objects = {}
- for k, v in funcs.iteritems():
- if not isinstance(v, basestring):
- continue
- old_v = v
- try:
- funcs[k] = self.run_json_macros(
- self.run_code_macros(v, app_dir, verbose=verbose),
- app_dir, verbose=verbose)
- except ValueError, e:
- print >>sys.stderr, "Error running !code or !json on function \"%s\": %s" % (k, e)
- sys.exit(-1)
- if old_v != funcs[k]:
- self.objects[_md5(to_bytestring(funcs[k])).hexdigest()] = old_v
-
- def run_code_macros(self, f_string, app_dir, verbose=False):
- def rreq(mo):
- # just read the file and return it
- path = os.path.join(app_dir, mo.group(2).strip(' '))
- library = ''
- filenum = 0
- for filename in glob.iglob(path):
- if verbose>=2:
- print "process code macro: %s" % filename
- try:
- library += read_file(filename)
- except IOError, e:
- print >>sys.stderr, e
- sys.exit(-1)
- filenum += 1
-
- if not filenum:
- print >>sys.stderr, "Processing code: No file matching '%s'" % mo.group(2)
- sys.exit(-1)
-
- return library
-
- re_code = re.compile('(\/\/|#)\ ?!code (.*)')
- return re_code.sub(rreq, f_string)
-
- def run_json_macros(self, f_string, app_dir, verbose=False):
- included = {}
- varstrings = []
-
- def rjson(mo):
- if mo.group(2).startswith('_attachments'):
- # someone want to include from attachments
- path = os.path.join(app_dir, mo.group(2).strip(' '))
- filenum = 0
- for filename in glob.iglob(path):
- library = ''
- try:
- if filename.endswith('.json'):
- library = read_json(filename)
- else:
- library = read_file(filename)
- except IOError, e:
- print >>sys.stderr, e
- sys.exit(1)
- filenum += 1
- current_file = filename.split(app_dir)[1]
- fields = current_file.split('/')
- count = len(fields)
- include_to = included
- for i, field in enumerate(fields):
- if i+1 < count:
- include_to[field] = {}
- include_to = include_to[field]
- else:
- include_to[field] = library
- if not filenum:
- print >>sys.stderr, "Processing code: No file matching '%s'" % mo.group(2)
- sys.exit(-1)
- else:
- fields = mo.group(2).split('.')
- library = self.doc
- count = len(fields)
- include_to = included
- for i, field in enumerate(fields):
- if not field in library: break
- library = library[field]
- if i+1 < count:
- include_to[field] = include_to.get(field, {})
- include_to = include_to[field]
- else:
- include_to[field] = library
-
- return f_string
-
- def rjson2(mo):
- return '\n'.join(varstrings)
-
- re_json = re.compile('(\/\/|#)\ ?!json (.*)')
- re_json.sub(rjson, f_string)
-
- if not included:
- return f_string
-
- for k, v in included.iteritems():
- varstrings.append("var %s = %s;" % (k, json.dumps(v)))
-
- return re_json.sub(rjson2, f_string)
-
- def merge_css(self, attach_dir, css_conf, docid, verbose=False):
- re_url = re.compile('url\s*\(([^\s"].*)\)')
-
- src_fpath = ''
- fname_dir = ''
-
- def replace_url(mo):
- """ make sure urls are relative to css path """
- css_url = mo.group(0)[4:].strip(")").replace("'", "").replace('"','')
- css_path = os.path.join(os.path.dirname(src_fpath),
- css_url)
-
- rel_path = _relpath(css_path, fname_dir)
- return "url(%s)" % rel_path
-
- for fname, src_files in css_conf.iteritems():
- output_css = ''
-
- dest_path = os.path.join(attach_dir, fname)
- fname_dir = os.path.dirname(dest_path)
-
- for src_fname in src_files:
- src_fpath = os.path.join(attach_dir, src_fname)
-
- if os.path.exists(src_fpath):
- content_css = str(CSSParser(read_file(src_fpath)))
- content_css = re_url.sub(replace_url, content_css)
- output_css += content_css
- if verbose >= 2:
- print "Merging %s in %s" % (src_fname, fname)
-
- if not os.path.isdir(fname_dir):
- os.makedirs(fname_dir)
-
- write_content(dest_path, output_css)
-
- def make_index_url(self, uri, app_name, attach_dir, index):
- if index:
- return "%s/%s/%s/%s" % (uri, '_design', app_name, index)
- else:
- index_fpath = os.path.join(attach_dir, 'index.html')
- if os.path.isfile(index_fpath):
- return "%s/%s/%s/%s" % (uri, '_design', app_name, 'index.html')
- else:
- return False
-
- @classmethod
- def vendor_update(cls, app_dir, verbose=False):
- vendor_dir = os.path.join(app_dir, "vendor")
- if not os.path.isdir(vendor_dir):
- return
-
- vendor_handlers = _vendor_handlers()
-
- for name in os.listdir(vendor_dir):
- current_path = os.path.join(vendor_dir, name)
- if os.path.isdir(current_path):
- mfile = os.path.join(current_path, 'metadata.json')
- metadata = read_json(mfile)
- update_url = False
- if not metadata and name == 'couchapp':
- update_url = COUCHAPP_VENDOR_URL
- scm = COUCHAPP_VENDOR_SCM
- elif metadata:
- update_url = metadata['update_url']
- scm = metadata['scm']
- if not scm in VENDOR_HANDLERS:
- scm = False
-
- if update_url and scm:
- # for now we manage only internal handlers
- handler = vendor_handlers[scm]
- if verbose >= 1:
- print "Updating %s from %s" % (current_path, update_url)
- cmd = "%s update %s %s %s" % (handler, update_url,
- current_path, vendor_dir)
- (child_stdin, child_stdout, child_stderr) = _popen3(cmd)
- if verbose >=2:
- print child_stdout.read()
- err = child_stderr.read()
- if err:
- print >>sys.stderr, err
-
- @classmethod
- def vendor_install(cls, app_dir, url, scm="git", verbose=False):
- if not scm in VENDOR_HANDLERS:
- print >>sys.stderr, "%s scm isn't supported yet." % scm
- sys.exit(-1)
- vendor_dir = os.path.join(app_dir, "vendor")
- if not os.path.isdir(vendor_dir):
- os.makedirs(vendor_dir)
-
- vendor_handlers = _vendor_handlers()
-
- # get list of installed applications
- installed_apps = []
- for name in os.listdir(vendor_dir):
- current_path = os.path.join(vendor_dir, name)
- if os.path.isdir(current_path):
- installed_apps.append(name)
-
-
- handler = vendor_handlers[scm]
- cmd = "%s install %s %s" % (handler, url, vendor_dir)
- (child_stdin, child_stdout, child_stderr) = _popen3(cmd)
- err = child_stderr.read()
- if verbose >=2:
- print child_stdout.read()
- if err:
- print >>sys.stderr, err
-
- # detect new vendor application and add url so we could update later
- for name in os.listdir(vendor_dir):
- current_path = os.path.join(vendor_dir, name)
- if os.path.isdir(current_path) and name not in installed_apps:
- new_file = os.path.join(current_path, '.new')
- if os.path.isfile(new_file):
- new_url = read_file(new_file).strip()
- if new_url == url:
- mfile = os.path.join(current_path, 'metadata.json')
- write_json(mfile, {
- "scm": scm,
- "update_url": url
- })
- os.unlink(new_file)
- return
-
- def merge_js(self, attach_dir, js_conf, docid, verbose=False):
- if "js_compressor" in self.conf:
- if not isinstance(self.conf["js_compressor"], basestring):
- print >>sys.stderr, "Warning: js_compressor settings should be a string"
- print >>sys.stderr, " Selecting default backend (jsmin)"
- import couchapp.utils.jsmin as backend
- else:
- try:
- backend = __import__(self.conf['js_compressor'], {}, {}, [''])
- except ImportError:
- import couchapp.utils.jsmin as backend
- else:
- import couchapp.utils.jsmin as backend
-
- if verbose:
- backend.about()
-
- for fname, src_files in js_conf.iteritems():
- output_js = ''
-
- dest_path = os.path.join(attach_dir, fname)
- fname_dir = os.path.dirname(dest_path)
-
- for src_fname in src_files:
- src_fpath = os.path.join(attach_dir, src_fname)
- if os.path.isfile(src_fpath):
- output_js += "/* %s */\n" % src_fpath
- output_js += read_file(src_fpath)
- if verbose >= 2:
- print "merging %s in %s" % (src_fname, fname)
-
- if not os.path.isdir(fname_dir):
- os.makedirs(fname_dir)
-
- output_js = backend.compress(output_js)
- write_content(dest_path, output_js)
-
View
136 python/couchapp/utils/__init__.py
@@ -1,136 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2009 Benoit Chesneau <benoitc@e-engura.org>
-#
-# This software is licensed as described in the file LICENSE, which
-# you should have received as part of this distribution.
-#
-
-import codecs
-import os
-import string
-import sys
-import urlparse
-import urllib
-
-# compatibility with python 2.4
-try:
- from hashlib import md5 as _md5
-except ImportError:
- import md5
- _md5 = md5.new
-
-try:
- import json
-except ImportError:
- import simplejson as json
-
-
-def in_couchapp():
- current_path = os.getcwd()
- old_dirs = []
- while 1:
- dirs = os.listdir(current_path)
- if dirs == old_dirs:
- return False
- if '.couchapprc' in dirs: break
- current_path = os.path.normpath(os.path.join(current_path, '../'))
- old_dirs = dirs
- return current_path
-
-def parse_uri(string):
- parts = urlparse.urlsplit(urllib.unquote(string))
- if parts[0] != 'http' and parts[0] != 'https':
- raise ValueError('Invalid dbstring')
-
- path = parts[2].strip('/').split('/')
-
- dbname = ''
- docid = ''
- if len(path) >= 1:
- db_parts=[]
- i = 0
- while 1:
- try:
- p = path[i]
- except IndexError:
- break
-
- if p == '_design': break
- db_parts.append(p)
- i = i + 1
- dbname = '/'.join(db_parts)
-
- if i < len(path) - 1:
- docid = '/'.join(path[i:])
-
- server_uri = '%s://%s' % (parts[0], parts[1])
- return server_uri, dbname, docid
-
-
-def parse_auth(string):
- parts = urlparse.urlsplit(urllib.unquote(string))
-
- server_parts = parts[1].split('@')
- if ":" in server_parts[0]:
- username, password = server_parts[0].split(":")
- else:
- username = server_parts[0]
- password = ''
-
- server_uri = "%s://%s" % (parts[0], server_parts[1])
-
- return username, password, server_uri
-
-def get_appname(docid):
- return docid.split('_design/')[1]
-
-
-def to_bytestring(s):
- if not isinstance(s, basestring):
- return s
- if isinstance(s, unicode):
- return s.encode('utf-8')
- else:
- return s
-
-def read_file(fname):
- f = codecs.open(fname, 'rb', "utf-8")
- data = f.read()
- f.close()
- return data
-
-def sign_file(file_path):
- if os.path.isfile(file_path):
- f = open(file_path, 'rb')
- content = f.read()
- f.close()
- return _md5(content).hexdigest()
- return ''
-
-def write_content(fname, content):
- f