Compare commits

...

195 Commits
v5 ... v8

Author SHA1 Message Date
Kenneth Reitz c5d7991468 v8 changelog 2012-05-30 16:01:38 -04:00
Kenneth Reitz c4404694e1 warn after injection 2012-05-30 15:59:55 -04:00
Kenneth Reitz e914736956 don't exit (yet) on collectstatic fail 2012-05-30 15:57:33 -04:00
Kenneth Reitz 23833dda9b comment out injection step 2012-05-30 15:53:49 -04:00
Kenneth Reitz 15573b9d3f simpler collectstatic 2012-05-30 15:47:39 -04:00
Kenneth Reitz 86661c1cda July 1 2012-05-30 15:23:14 -04:00
Kenneth Reitz 9cbace7f76 $DISABLE_COLLECTSTATIC 2012-05-30 15:15:10 -04:00
Kenneth Reitz 74cb870488 leave injection off for now 2012-05-30 15:14:36 -04:00
Kenneth Reitz ae9b83f07c fix error message for collectstatic 2012-05-30 13:55:22 -04:00
Kenneth Reitz d70c681c32 setting injection notice for users
#45
2012-05-30 13:52:08 -04:00
Kenneth Reitz c312d917a1 completely set DATABASES 2012-05-30 12:50:08 -04:00
Kenneth Reitz 5d2ecd2f1f echo "----->" 2012-05-30 04:21:22 -04:00
Kenneth Reitz a1e1dbd865 Merge remote-tracking branch 'origin/master' 2012-05-30 04:14:29 -04:00
Kenneth Reitz 12f28894ce collecting static files 2012-05-30 04:14:10 -04:00
Kenneth Reitz 538ef6e378 Update Readme.md 2012-05-30 05:07:37 -03:00
Kenneth Reitz 1588ea44b2 Update Readme.md 2012-05-30 05:05:55 -03:00
Kenneth Reitz 3cc9098e25 Update Readme.md 2012-05-30 05:05:41 -03:00
Kenneth Reitz 436e945a91 indents 2012-05-30 03:43:03 -04:00
Kenneth Reitz f9b83a4e95 chmod 2012-05-30 03:21:46 -04:00
Kenneth Reitz b1f8bf9f5e whitespace 2012-05-30 03:15:09 -04:00
Kenneth Reitz 7af5175942 hooks 2012-05-30 03:13:32 -04:00
Kenneth Reitz c24a9096de cleanup 2012-05-30 02:56:46 -04:00
Kenneth Reitz 36d27c46ed \n 2012-05-30 02:54:57 -04:00
Kenneth Reitz 713fa36bca debug 2012-05-30 02:53:33 -04:00
Kenneth Reitz 20249f9672 MANAGE_FILE 2012-05-30 02:50:50 -04:00
Kenneth Reitz 8b55e73f77 - 2012-05-30 02:43:08 -04:00
Kenneth Reitz 2058b3c5bf --verbosity=0 2012-05-30 02:42:46 -04:00
Kenneth Reitz 4eb17eb9a9 env 2012-05-30 02:17:48 -04:00
Kenneth Reitz 7138b7afb2 silence output of mkdir 2012-05-30 01:41:20 -04:00
Kenneth Reitz fe9b9401d3 syntax error 2012-05-30 01:39:04 -04:00
Kenneth Reitz 8c870cabfb proper path 2012-05-30 01:36:26 -04:00
Kenneth Reitz b8182c077a fix paths 2012-05-30 01:34:33 -04:00
Kenneth Reitz fbbdadd347 /s/Pip/pip 2012-05-30 01:34:28 -04:00
Kenneth Reitz b54faf36f5 move .heroku creation down 2012-05-30 01:28:44 -04:00
Kenneth Reitz a0dc2a6f33 additional notes 2012-05-30 01:20:58 -04:00
Kenneth Reitz f775fca31c v7 notes 2012-05-30 01:18:09 -04:00
Kenneth Reitz efebff4ce8 inverse test 2012-05-29 21:11:44 -04:00
Kenneth Reitz 94b2ab43a5 disable injection for new applications 2012-05-29 21:08:50 -04:00
Kenneth Reitz a21dbc2da1 run collectstatic 2012-05-29 21:08:34 -04:00
Kenneth Reitz cf5a9d26d1 .heroku/injection_disabled 2012-05-29 21:07:50 -04:00
Kenneth Reitz ef4772b87a export CACHE_DIR 2012-05-25 13:29:27 -04:00
Kenneth Reitz ffda318476 don't reject django apps packaged poorly 2012-05-25 13:29:16 -04:00
Kenneth Reitz 6aff0d0197 Merge branch 'master' into static 2012-05-23 13:25:41 -04:00
Kenneth Reitz b9ebd33703 prose 2012-05-23 13:25:40 -04:00
Kenneth Reitz 61e17df22d no travis email notification 2012-05-23 13:25:08 -04:00
Kenneth Reitz b88d0ad800 Don't fail fast. 2012-05-23 13:06:50 -04:00
Kenneth Reitz 7e24f94164 move DISABLE_INJECTION to lower level 2012-05-23 13:06:42 -04:00
Kenneth Reitz 3a239aa71a django dispatch 2012-05-15 15:01:09 -07:00
Kenneth Reitz 0e1ae7a798 collectstatic command 2012-05-15 15:00:56 -07:00
Kenneth Reitz 133c308796 shuffle a few things around 2012-05-15 14:41:02 -07:00
Kenneth Reitz 7ea8c861a2 Unset runtime-specific variables.
Fixes #37
2012-05-02 12:49:11 -04:00
Kenneth Reitz 20e0af2bf4 Don't pin version. 2012-05-02 12:48:43 -04:00
Kenneth Reitz 5d0ed4e7cd be specific 2012-04-30 14:35:44 -04:00
Kenneth Reitz 144629d7dc only configure one at a time 2012-04-30 14:27:19 -04:00
Kenneth Reitz cf36e8c7cb dj-database-url 2012-04-30 14:00:51 -04:00
Kenneth Reitz 233df5d59d fix tests 2012-04-30 13:53:05 -04:00
Kenneth Reitz 375796063b 2 directory levels, not 3 2012-04-30 13:48:02 -04:00
Kenneth Reitz d8a70de8a8 Merge remote-tracking branch 'origin/master' 2012-04-26 14:04:23 -04:00
Kenneth Reitz f1ee7fc04f comment updates 2012-04-26 14:04:17 -04:00
Kenneth Reitz e8585fb4a7 detect/changelog 2012-04-26 14:03:30 -04:00
Kenneth Reitz e10cc01f7e Update Readme.md 2012-04-26 15:01:50 -03:00
Kenneth Reitz 79d6db74b1 travis 2012-04-26 13:58:40 -04:00
Kenneth Reitz 69d607a76e Merge branch 'master' of https://github.com/andres-torres-marroquin/heroku-buildpack-python 2012-04-06 16:25:44 -04:00
Kenneth Reitz 2c03d89213 Merge branch 'master' of github.com:heroku/heroku-buildpack-python 2012-04-03 18:46:25 -04:00
Kenneth Reitz 11bf9833da heroku.py 2012-04-03 18:45:59 -04:00
Andrés Torres d2d37255d5 Multiple requirements support added 2012-04-03 14:49:56 -05:00
Andrés Torres bea5b4919e Added support for django 1.4 2012-04-03 11:14:39 -05:00
Kenneth Reitz b67a040474 changelog 2012-03-24 00:34:07 -04:00
Kenneth Reitz d40199ec00 update changelog 2012-03-24 00:32:58 -04:00
Kenneth Reitz 6f7390921c more final 2012-03-24 00:28:15 -04:00
Kenneth Reitz e5fa0473de that explains a lot 2012-03-24 00:26:35 -04:00
Kenneth Reitz 889b777eeb debugs 2012-03-24 00:24:30 -04:00
Kenneth Reitz 8d4626ef81 echo "copying $dir…" 2012-03-24 00:16:21 -04:00
Kenneth Reitz 7c7d2bc959 copy back CACHED_DIRS 2012-03-24 00:07:06 -04:00
Kenneth Reitz d76a7c5ea2 /s/f/d 2012-03-24 00:01:17 -04:00
Kenneth Reitz 3641a97b5f remove debug statement 2012-03-23 23:54:19 -04:00
Kenneth Reitz 5e818e85f3 echo debug 2012-03-23 23:49:18 -04:00
Kenneth Reitz c9d10077af source proper venv 2012-03-23 23:46:25 -04:00
Kenneth Reitz 6394214b55 fi 2012-03-23 23:45:06 -04:00
Kenneth Reitz bfa26b8b05 /s/do/then 2012-03-23 23:43:38 -04:00
Kenneth Reitz 15172c86b9 move django pre-exit to steps/django 2012-03-23 23:42:38 -04:00
Kenneth Reitz daa85630c7 bash foo weak 2012-03-23 23:37:33 -04:00
Kenneth Reitz 9914e50d8a PYTHONPATH 2012-03-23 23:36:20 -04:00
Kenneth Reitz ef59b5ad6b $CACHED_DIRS 2012-03-23 23:31:50 -04:00
Kenneth Reitz 98741a0606 $VIRTUALENV_LOC 2012-03-23 23:30:43 -04:00
Kenneth Reitz 6aadf1683a new style virtualenvs 2012-03-23 23:29:28 -04:00
Kenneth Reitz e10cb6bfb1 exit early for settings.py at root 2012-03-23 23:09:26 -04:00
Kenneth Reitz 2fd6d7e1f8 changelog 2012-03-23 23:08:52 -04:00
Kenneth Reitz 30c12d9c63 remote failing test (for not) 2012-03-23 22:57:33 -04:00
Kenneth Reitz 3313891205 move setup.py stuff up 2012-03-23 22:46:29 -04:00
Kenneth Reitz 1e914b8558 -f 2012-03-23 22:43:41 -04:00
Kenneth Reitz b9fc30f592 more careful pylibmc check 2012-03-23 22:42:40 -04:00
Kenneth Reitz e8e67fe093 better release defaults 2012-03-23 22:42:32 -04:00
Kenneth Reitz 66e49c764c manage_file scrub 2012-03-23 22:27:26 -04:00
Kenneth Reitz 322d19689f tr -d './' 2012-03-23 22:18:36 -04:00
Kenneth Reitz 07a6853585 -maxdepth 2 2012-03-23 21:06:39 -04:00
Kenneth Reitz f34599c5ad relative detect path 2012-03-23 20:59:15 -04:00
Kenneth Reitz 97c5f0944d project dir for release 2012-03-23 20:57:00 -04:00
Kenneth Reitz 1e598e2511 proper find usage 2012-03-23 20:54:02 -04:00
Kenneth Reitz 966a5e35db use find instead 2012-03-23 20:48:42 -04:00
Kenneth Reitz d760946828 skip manage for now 2012-03-23 20:40:58 -04:00
Kenneth Reitz 3dda7c3731 yaml 2012-03-23 20:30:37 -04:00
Kenneth Reitz 3441833521 manage.py detection 2012-03-23 20:27:56 -04:00
Kenneth Reitz 603950ca65 assert not python 2012-03-23 19:55:37 -04:00
Kenneth Reitz a946ce09c0 literate detect 2012-03-23 19:52:59 -04:00
Kenneth Reitz c196347e58 all kinds of awesome tests 2012-03-23 19:52:03 -04:00
Kenneth Reitz 979491a631 better language 2012-03-23 19:22:14 -04:00
Kenneth Reitz fef3581417 punctuation 2012-03-23 19:19:53 -04:00
Kenneth Reitz f6d948b0e0 log -e . 2012-03-23 19:19:24 -04:00
Kenneth Reitz 2f42fdb282 basic tests 2012-03-23 19:17:07 -04:00
Kenneth Reitz b16261c158 basic test runner 2012-03-23 19:17:00 -04:00
Kenneth Reitz 3e1d657888 be more specific with the assumptions 2012-03-23 16:45:02 -04:00
Kenneth Reitz 06946d3632 step/warn functions 2012-03-23 16:38:06 -04:00
Kenneth Reitz cd8530a5c2 reference pylibmc docs 2012-03-23 16:32:31 -04:00
Kenneth Reitz 91015bd2c1 pylibmc 2012-03-23 16:31:32 -04:00
Kenneth Reitz 907b66624b show django docs 2012-03-23 16:28:26 -04:00
Kenneth Reitz 193352c616 finalize 2012-03-23 16:22:26 -04:00
Kenneth Reitz 2e551e9c4e additional headings for docs 2012-03-23 16:21:17 -04:00
Kenneth Reitz 58c625affd message consistency 2012-03-23 16:19:14 -04:00
Kenneth Reitz b13702972d deploy the site 2012-03-23 16:13:51 -04:00
Kenneth Reitz 8c16776d72 documentation improvements 2012-03-23 16:13:43 -04:00
Kenneth Reitz 7e4405989a ignore site folder 2012-03-23 16:13:35 -04:00
Kenneth Reitz 15b819703a notes 2012-03-23 16:02:07 -04:00
Kenneth Reitz bf2372101f /s/src/vendor 2012-03-23 15:59:47 -04:00
Kenneth Reitz d87f88ee4d move VENDORED_MEMCACHED to steps/pylibmc 2012-03-23 15:59:15 -04:00
Kenneth Reitz 24266be8db literate programming
shocco
2012-03-23 15:58:57 -04:00
Kenneth Reitz 3187d73b64 shocco 2012-03-23 15:58:45 -04:00
Kenneth Reitz 48f52668be TODO: Bootstrap a Python 2012-03-23 14:19:55 -04:00
Kenneth Reitz f7ef15d7d0 restore cache 2012-03-23 14:15:16 -04:00
Kenneth Reitz d084ac8a58 remove python-build 2012-03-23 14:14:31 -04:00
Kenneth Reitz 077d93e283 your bash foo is weak 2012-03-06 06:44:58 -05:00
Kenneth Reitz 71409e7712 out 2012-03-06 06:37:57 -05:00
Kenneth Reitz 61a7ad7116 delete 2012-03-06 06:32:58 -05:00
Kenneth Reitz d1ab3939e9 pythonhome 2012-03-06 06:19:22 -05:00
Kenneth Reitz 0f2f10557c .. 2012-03-06 06:04:34 -05:00
Kenneth Reitz ad748743cd not needed 2012-03-06 05:58:18 -05:00
Kenneth Reitz 844a8daad6 source it 2012-03-06 05:49:37 -05:00
Kenneth Reitz 93cc65adfc hmmm 2012-03-06 05:47:31 -05:00
Kenneth Reitz 3a1aa3f6af BUILD DIR 2012-03-06 05:46:10 -05:00
Kenneth Reitz 5b5f124082 PWD? 2012-03-06 05:30:13 -05:00
Kenneth Reitz cd17d3948c relative? 2012-03-06 05:29:07 -05:00
Kenneth Reitz 7c49ceaf2c no cache 2012-03-06 05:25:02 -05:00
Kenneth Reitz a156996d61 proper paths 2012-03-06 05:18:52 -05:00
Kenneth Reitz 9438005891 prefix= 2012-03-06 04:56:22 -05:00
Kenneth Reitz aefde88d24 && 2012-03-06 04:50:44 -05:00
Kenneth Reitz 347bca0de4 cleaner pylibmc check 2012-03-06 04:46:26 -05:00
Kenneth Reitz a0f2073eb1 check for django in requirements.txt 2012-03-06 04:46:16 -05:00
Kenneth Reitz 1b0fd2e4b6 Merge branch 'develop' into decouple 2012-03-06 04:29:37 -05:00
Kenneth Reitz 4be3d87e04 If no requirements, assume 'setup.py install' 2012-03-06 04:24:54 -05:00
Kenneth Reitz 5ffe9203d3 check for setup.py too 2012-03-06 04:20:00 -05:00
Kenneth Reitz 24cd70dc95 remove it 2012-02-26 16:54:34 -05:00
Kenneth Reitz 6e9b241fb2 vendor dir 2012-02-26 16:54:11 -05:00
Kenneth Reitz 4cc660a3a7 bugs 2012-02-26 16:40:17 -05:00
Kenneth Reitz 7c48f6d17b $BIN_DIR 2012-02-26 16:23:08 -05:00
Kenneth Reitz c4d7ae49ba hacky compile 2012-02-26 16:19:07 -05:00
Kenneth Reitz 26dd3828df Start Decoupled Pythons 2012-02-26 15:46:57 -05:00
Kenneth Reitz ead7b1a04a PYTHONHASHSEED 2012-02-26 13:02:19 -05:00
Kenneth Reitz 1ddd5c2515 Merge branch 'develop' 2012-02-24 17:33:02 -05:00
Kenneth Reitz e1fcbc067a Revert "remove injection disabling (for now)"
This reverts commit 825d41695d.
2012-02-24 17:31:45 -05:00
Kenneth Reitz 9bf33597c3 plural 2012-02-17 22:59:47 -05:00
Kenneth Reitz 17a8e05a90 Merge branch 'develop' of github.com:heroku/heroku-buildpack-python into develop 2012-02-13 15:09:46 -05:00
Kenneth Reitz 7a01a6850c lawyer up 2012-02-13 15:08:44 -05:00
Kenneth Reitz 6fdcc392dd Merge pull request #29 from lstoll/develop
Set the LANG var to support non US-ASCII chars
2012-02-08 23:45:23 -08:00
Lincoln Stoll 3e5bea876d Set the LANG var to support non US-ASCII chars
This it the same as the ruby buildpack.
2012-02-09 20:41:45 +13:00
Kenneth Reitz 976089104b Merge branch 'master' into develop 2012-02-01 14:24:39 -05:00
Kenneth Reitz 7b1b24860a src directory in .heroku 2012-02-01 13:31:26 -05:00
Kenneth Reitz 2e192e79a6 no more trace 2012-02-01 13:00:36 -05:00
Kenneth Reitz 9662b9a2f0 sane virtualenv again 2012-02-01 12:54:25 -05:00
Kenneth Reitz 8f5385f9ca cleanup 2012-02-01 12:49:08 -05:00
Kenneth Reitz 0b46e1d807 unset GIT_DIR 2012-02-01 12:47:32 -05:00
Kenneth Reitz 35a1b8dd62 blah 2012-01-31 03:40:56 -05:00
Kenneth Reitz 760b17431a worth a shot 2012-01-31 03:36:13 -05:00
Kenneth Reitz 4d3a352889 ugh 2012-01-31 03:30:43 -05:00
Kenneth Reitz 3fa65989ea grr 2012-01-31 03:29:13 -05:00
Kenneth Reitz 1553d4dbc3 try again 2012-01-31 03:14:09 -05:00
Kenneth Reitz ac766e2615 try 2012-01-31 03:11:36 -05:00
Kenneth Reitz fee800cb21 blah 2012-01-31 03:08:20 -05:00
Kenneth Reitz 7fd0e8de3c update 2012-01-31 02:55:35 -05:00
Kenneth Reitz 1dd1afc972 GIT_TRACE 2012-01-31 02:29:40 -05:00
Kenneth Reitz c1e8b1d80c one last try 2012-01-31 00:47:55 -05:00
Kenneth Reitz fb19d5fec2 :trollface: 2012-01-31 00:44:32 -05:00
Kenneth Reitz b2f01679a5 NO_MSGFMT=yes 2012-01-31 00:40:25 -05:00
Kenneth Reitz c5703462c2 --without-tcltk 2012-01-31 00:35:54 -05:00
Kenneth Reitz deeea09e5d most ridiculous test ever 2012-01-31 00:32:02 -05:00
Kenneth Reitz b39ffa8fa3 when install fails, show the directory 2012-01-31 00:09:10 -05:00
Kenneth Reitz 0b1926f089 verbose git commands 2012-01-31 00:00:56 -05:00
Kenneth Reitz f05fc7b559 trying again 2012-01-30 23:56:15 -05:00
Kenneth Reitz 37590bf0e0 getting serious pip 2012-01-30 23:49:26 -05:00
Kenneth Reitz fd25ce1a0d further patched pip 2012-01-30 23:41:35 -05:00
Kenneth Reitz f581e1c685 debug version of pip 2012-01-30 23:37:34 -05:00
Kenneth Reitz 977c4816ed strip .git 2012-01-30 23:37:27 -05:00
Kenneth Reitz 7a022245d4 pip bootstrap 2012-01-30 23:25:00 -05:00
Kenneth Reitz 503377a00b verbose pip 2012-01-30 23:12:42 -05:00
Kenneth Reitz a624be1e20 env test 2012-01-30 23:08:16 -05:00
Kenneth Reitz 41ad52e495 no need for ./bin/ 2012-01-30 23:04:30 -05:00
80 changed files with 2448 additions and 117 deletions
+1
View File
@@ -1 +1,2 @@
*.pyc
site
+6
View File
@@ -0,0 +1,6 @@
language: python
python:
- 2.7
script: make tests
notifications:
email: false
+40
View File
@@ -1,3 +1,43 @@
## v8
Features:
* Disable Django collectstatic with `$DISABLE_COLLECTSTATIC` + [user_env_compile](http://devcenter.heroku.com/articles/labs-user-env-compile).
Bugfixes:
* Don't disbable injection for new Django apps.
* Inform user of July 1, 2012 deprecation of Django injection.
## v7
Features:
* Full removal of Django setting injection for new apps.
* Automatic execution of collectstatic.
* Suppress collectstatic errors via env SILENCE_COLLECTSTATIC.
* Increase settings.py search depth to 3.
* Search recursively from included requirements.txt files.
## v6 (03/23/2012)
Features:
* Dist packages (setup.py) support.
* Move new virtualenvs to `/app/.heroku/venv`.
* Heavily improved Django app detection, accounting for `Django` in `requirements.txt`.
* Literate [documentation](http://python-buildpack.herokuapp.com).
* Default `$PYTHONHOME`, `$PYTHONPATH`, and `$LANG` configurations.
* Disable Django setting injection with `$DISABLE_INJECTION` + [user_env_compile](http://devcenter.heroku.com/articles/labs-user-env-compile).
* General code refactor and improved messaging.
* Unit tests.
Bugfixes:
* Django 1.4 startproject template layout support.
* Django `manage.py` location can now be independent from `settings.py`.
## v5 (02/01/2012)
Bugfixes:
+9
View File
@@ -0,0 +1,9 @@
MIT License:
Copyright (C) 2012 Heroku, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+17 -2
View File
@@ -1,6 +1,21 @@
tests:
./bin/test
docs:
mkdir -p site
shocco -t 'Python Buildpack Compiler' ./bin/compile > site/index.html
shocco -t 'Django Buildpack Compiler' ./bin/steps/django > site/django.html
shocco -t 'Python Buildpack Detector' ./bin/detect > site/detect.html
shocco -t 'Pylibmc Buildpack Compiler' ./bin/steps/pylibmc > site/pylibmc.html
shocco -t 'Python Buildpack Changelog' ./Changelog.md > site/changelog.html
site: docs
cd site && git add -A && git commit -m 'update' && git push heroku master
pip:
git clone git@github.com:kennethreitz/pip.git --branch heroku --depth 1
rm -fr src/virtualenv-1.7/virtualenv_support/pip-1.0.2.tar.gz
rm -fr vendor/virtualenv-1.7/virtualenv_support/pip-1.0.2.tar.gz
rm -fr pip/.git
tar -pczf src/virtualenv-1.7/virtualenv_support/pip-1.0.2.tar.gz pip
tar -pczf vendor/virtualenv-1.7/virtualenv_support/pip-1.0.2.tar.gz pip
rm -fr pip
+7 -1
View File
@@ -1,9 +1,11 @@
Heroku buildpack: Python
========================
This is a [Heroku buildpack](http://devcenter.heroku.com/articles/buildpack) for Python apps.
This is a [Heroku buildpack](http://devcenter.heroku.com/articles/buildpacks) for Python apps.
It uses [virtualenv](http://www.virtualenv.org/) and [pip](http://www.pip-installer.org/).
[![Build Status](https://secure.travis-ci.org/heroku/heroku-buildpack-python.png?branch=master)](http://travis-ci.org/heroku/heroku-buildpack-python)
Usage
-----
@@ -31,6 +33,10 @@ Example usage:
Successfully installed Flask Werkzeug Jinja2
Cleaning up...
You can also add it to upcoming builds of an existing application:
$ heroku config:add BUILDPACK_URL=git@github.com:heroku/heroku-buildpack-python.git
The buildpack will detect your app as Python if it has the file `requirements.txt` in the root. It will detect your app as Python/Django if there is an additional `settings.py` in a project subdirectory.
It will use virtualenv and pip to install your dependencies, vendoring a copy of the Python runtime into your slug. The `bin/`, `include/` and `lib/` directories will be cached between builds to allow for faster pip install time.
+155 -42
View File
@@ -1,112 +1,225 @@
#!/usr/bin/env bash
# bin/compile <build-dir> <cache-dir>
# This script serves as the
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
# compiler.
#
# A [buildpack](http://devcenter.heroku.com/articles/buildpacks) is an
# adapter between a Python application and Heroku's runtime.
#
# You can intreract with the Heroku API directly with [heroku.py](https://github.com/heroku/heroku.py/).
#
# See also: [Release history](/changelog.html), [Detection](/detect.html).
#
# ## Usage
# Compiling an app into a slug is simple:
#
# $ bin/compile <build-dir> <cache-dir>
# ## Assumptions
#
# This buildpack makes the following assumptions:
#
# - The desired Python VM is available on the base system.
# - Library dependencies are available on the base system.
# - Django applications should not require any platform-specific configuration.
# <hr />
# ## Context
# Fail fast and fail hard.
set -eo pipefail
# Prepend proper path for virtualenv hackery. Will be deprecated soon.
# Prepend proper path for virtualenv hackery. This will be deprecated soon.
export PATH=:/usr/local/bin:$PATH
# Paths.
BIN_DIR=$(cd $(dirname $0); pwd) # absolute path
ROOT_DIR=$(dirname $BIN_DIR)
BUILD_DIR=$1
CACHE_DIR=$2
# The detected application type (`Python`|`Python/Django`).
NAME=$($BIN_DIR/detect $BUILD_DIR)
# Where to store the Pip download cache.
CACHED_DIRS=".heroku"
PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE:-$CACHE_DIR/pip_downloads}
VIRTUALENV_DIRS="bin include lib"
VENDORED_MEMCACHED="http://cl.ly/0a191R3K160t1w1P0N25/vendor-libmemcached.tar.gz"
# Static configurations for virtualenv caches.
LEGACY_VIRTUALENV_LOC="."
MODERN_VIRTUALENV_LOC=".heroku/venv"
LEGACY_VIRTUALENV_DIRS="bin include lib"
LEGACY_VIRTUALENV_TRIGGER="lib/python2.7"
# Python version. This will be used in the future to specify custom Pythons.
PYTHON_VERSION="2.7.2"
PYTHON_EXE="python2.7"
# Sanitizing environment variables.
unset GIT_DIR
export PIP_DOWNLOAD_CACHE
unset PYTHON_HOME
unset PYTHONPATH
# We'll need to send these statics to other scripts we `source`.
export PIP_DOWNLOAD_CACHE BUILD_DIR CACHE_DIR BIN_DIR
# Syntax sugar.
indent() {
RE="s/^/ /"
[ $(uname) == "Darwin" ] && sed -l "$RE" || sed -u "$RE"
}
function virtualenv (){
python "$ROOT_DIR/src/virtualenv-1.7/virtualenv.py" "$@"
python "$ROOT_DIR/vendor/virtualenv-1.7/virtualenv.py" "$@"
}
function puts-step (){
echo "-----> $@"
}
function puts-warn (){
echo " ! $@"
}
# ## Build Time
#
# Switch to the repo's context.
cd $BUILD_DIR
# Reject a non-packaged Django app.
if [ "$NAME" = "Python" ]; then
[ -f manage.py ] && [ -f settings.py ] && { echo " ! Django app must be in a package subdirectory"; exit 1; }
# Experimental pre_compile hook.
source $BIN_DIR/steps/hooks/pre_compile
# ### Sanity Checks
#
# Just a little peace of mind.
# If no requirements given, assume `setup.py develop`.
if [ ! -f requirements.txt ]; then
puts-step "No requirements.txt provided; assuming dist package."
echo "-e ." > requirements.txt
fi
# Warn a checked-in virtualenv.
if [ -d "lib" ] || [ -d "bin" ]; then
echo " ! You have a virtualenv checked in. You should ignore the appropriate paths in your repo. See http://devcenter.heroku.com/articles/gitignore for more info.";
fi
# Reject a conflicting checked-in virtualenv.
if [ -f "lib/python2.7" ]; then
echo " ! Checked-in virtualenv conflict."
exit 1;
fi
# Copy artifacts out of cache if exists.
# ### The Cache
mkdir -p $CACHE_DIR
for dir in $VIRTUALENV_DIRS; do
# Nice defaults.
LEGACY_VIRTUALENV=false
VIRTUALENV_LOC=$MODERN_VIRTUALENV_LOC
# Support "old-style" virtualenvs.
if [ -d $CACHE_DIR/$LEGACY_VIRTUALENV_TRIGGER ]; then
LEGACY_VIRTUALENV=true
VIRTUALENV_LOC=$LEGACY_VIRTUALENV_LOC
CACHED_DIRS=$LEGACY_VIRTUALENV_DIRS
# Warn for a checked-in virtualenv.
if [ -d "lib" ] || [ -d "bin" ]; then
puts-warn "You have a virtualenv checked in. You should ignore the appropriate paths in your repo. See http://devcenter.heroku.com/articles/gitignore for more info.";
fi
# Reject a conflicting checked-in virtualenv.
if [ -f "lib/python2.7" ]; then
puts-warn "Checked-in virtualenv conflict."
exit 1;
fi
fi
# Restore old artifacts from the cache.
for dir in $CACHED_DIRS; do
cp -R $CACHE_DIR/$dir . &> /dev/null || true
done
# Create virtualenv. Rebuild if corrupt.
set +e
echo "-----> Preparing virtualenv version $(virtualenv --version)"
# Create set-aside `.heroku` folder.
mkdir .heroku &> /dev/null
HEROKU_DIR_STATUS=$?
# TODO: This is a new app, disable injection.
# [ $HEROKU_DIR_STATUS -eq 0 ] && {
#TODO: touch .heroku/injection_disabled
# }
set -e
# ### Virtualenv Setup
#
# Create the virtualenv. Rebuild if corrupt.
# TODO: Bootstrap a bottled Python VM...
set +e
puts-step "Preparing Python interpreter ($PYTHON_VERSION)"
puts-step "Creating Virtualenv version $(virtualenv --version)"
# Try to create the virtualenv.
OUT=$(virtualenv --distribute --never-download --prompt=venv . 2>&1)
OUT=$(virtualenv --python $PYTHON_EXE --distribute --never-download --prompt='(venv) ' $VIRTUALENV_LOC 2>&1)
# If there's an error, purge and recreate.
[ $? -ne 0 ] && {
echo " ! Virtualenv corrupt, rebuilding."
puts-warn "Virtualenv corrupt, rebuilding."
for dir in $VIRTUALENV_DIRS; do
rm -fr $dir &> /dev/null || true
done
OUT=$(virtualenv --distribute --never-download --prompt=venv . )
OUT=$(virtualenv --python $PYTHON_EXE --distribute --never-download --prompt='(venv) ' $VIRTUALENV_LOC )
}
echo "$OUT" | indent
set -e
# Create set-aside .heroku folder.
mkdir -p .heroku
# Pylibmc support.
# See [`bin/steps/pylibmc`](pylibmc.html).
source $BIN_DIR/steps/pylibmc
# Activate the virtualenv.
echo "-----> Activating virtualenv"
source bin/activate
# Activate the Virtualenv.
puts-step "Activating virtualenv"
source $VIRTUALENV_LOC/bin/activate
# Install mercurial, if needed.
# Install Mercurial if it appears to be required.
if (grep -Fiq "hg+" requirements.txt) then
pip install --use-mirrors mercurial | indent
fi
# Install dependencies.
echo "-----> Installing dependencies using pip version $(pip --version | awk '{print $2}')"
# Install dependencies with Pip.
puts-step "Installing dependencies using pip version $(pip --version | awk '{print $2}')"
pip install --use-mirrors -r requirements.txt --src ./.heroku/src | indent
# Django support.
# Do additional application hackery if applications appears to be a Django app.
# Optionally, disable all Django-specific changes with `DISABLE_INJECTION` env.
#
# See [`bin/steps/django`](django.html).
if [ "$NAME" = "Python/Django" ]; then
source $BIN_DIR/steps/django
source $BIN_DIR/steps/django/init
fi
# Make virtualenv relocatable.
# Make Virtualenv's paths relative for portability.
set +e
OUT=$(virtualenv --relocatable .)
OUT=$(virtualenv --python $PYTHON_EXE --relocatable $VIRTUALENV_LOC)
[ $? -ne 0 ] && {
echo " ! Error making virtualenv relocatable"
puts-warn "Error making virtualenv relocatable"
echo "$OUT" | indent
exit 1
}
set -e
# ### Finalize
#
# Store new artifacts in cache.
for dir in $VIRTUALENV_DIRS; do
for dir in $CACHED_DIRS; do
rm -rf $CACHE_DIR/$dir
cp -R $dir $CACHE_DIR/
done
# ### Fin.
# Experimental post_compile hook.
source $BIN_DIR/steps/hooks/post_compile
# <a href="http://github.com/heroku/heroku-buildpack-python"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://d3nwyuy0nl342s.cloudfront.net/img/7afbc8b248c68eb468279e8c17986ad46549fb71/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub"></a>
+60 -4
View File
@@ -1,8 +1,64 @@
#!/usr/bin/env bash
# bin/detect <build-dir>
# This script serves as the
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
# detector.
#
# A [buildpack](http://devcenter.heroku.com/articles/buildpacks) is an
# adapter between a Python application and Heroku's runtime.
# ## Usage
# Compiling an app into a slug is simple:
#
# $ bin/detect <build-dir> <cache-dir>
BUILD_DIR=$1
[ -f $BUILD_DIR/requirements.txt ] || exit 1 # fail fast if no requirements.txt
# 'Python/Django' if there is a [mysite]/settings.py file present; otherwise 'Python'
ls $BUILD_DIR/**/settings.py &> /dev/null && echo Python/Django || echo Python
# Exit early if app is clearly not Python.
if [ ! -f $BUILD_DIR/requirements.txt ] && [ ! -f $BUILD_DIR/setup.py ]; then
exit 1
fi
# If only `setup.py`, assume that the app is not Django.
if [ ! -f $BUILD_DIR/requirements.txt ]; then
echo Python
exit 0
fi
# `Python/Django` if `**/settings.py` is present and `django` exists in
# `requirements.txt`.
#
# Otherwise, `Python`.
array=""
list_requirements() {
IFS_BAK=$IFS
IFS="
"
requirement_file=$1
reqs=$(cat $requirement_file)
for req in $reqs; do
if [[ $req == -r* ]]; then
new_req=$(echo $req | cut -d" " -f2)
if [[ $new_req == $1 ]]; then
continue
fi
directory=$(dirname $requirement_file)
if [[ ! $array == *$directory/$new_req* ]]; then
list_requirements "$directory/$new_req"
fi
array="$array $directory/$new_req"
else
echo $req;
fi
done
IFS=$IFS_BAK
IFS_BAK=
}
SETTINGS_FILE=$(find $BUILD_DIR/. -maxdepth 2 -type f -name 'settings.py' | head -1)
[ -n "$SETTINGS_FILE" ] && ( list_requirements $BUILD_DIR/requirements.txt | grep -Fiq "django" ) && echo Python/Django || echo Python
+10 -5
View File
@@ -8,17 +8,22 @@ NAME=$($BIN_DIR/detect $BUILD_DIR) || exit 1
cat <<EOF
---
config_vars:
PATH: bin:/usr/local/bin:/usr/bin:/bin
PATH: /app/.heroku/venv/bin:/bin:/usr/local/bin:/usr/bin
PYTHONUNBUFFERED: true
LIBRARY_PATH: .heroku/vendor/lib
LD_LIBRARY_PATH: .heroku/vendor/lib
LIBRARY_PATH: /app/.heroku/vendor/lib
LD_LIBRARY_PATH: /app/.heroku/vendor/lib
LANG: en_US.UTF-8
PYTHONHASHSEED: random
PYTHONHOME: /app/.heroku/venv/
PYTHONPATH: /app/
EOF
[ "$NAME" = "Python/Django" ] || exit 0
SETTINGS_FILE=$(cd $BUILD_DIR && ls **/settings.py | head -1)
PROJECT=$(dirname $SETTINGS_FILE)
MANAGE_FILE=$(cd $BUILD_DIR && find . -maxdepth 3 -type f -name 'manage.py' | head -1)
MANAGE_FILE=${MANAGE_FILE:2}
PROJECT=$(dirname $MANAGE_FILE)
cat <<EOF
-49
View File
@@ -1,49 +0,0 @@
#!/usr/bin/env bash
echo "-----> Injecting Django settings..."
SETTINGS_FILE=$(ls **/settings.py | head -1)
PROJECT=$(dirname $SETTINGS_FILE)
echo "Injecting code into $SETTINGS_FILE to read from DATABASE_URL" | indent
cat >>$SETTINGS_FILE <<EOF
import os
import sys
import urlparse
# Register database schemes in URLs.
urlparse.uses_netloc.append('postgres')
urlparse.uses_netloc.append('mysql')
try:
# Check to make sure DATABASES is set in settings.py file.
# If not default to {}
if 'DATABASES' not in locals():
DATABASES = {}
if 'DATABASE_URL' in os.environ:
url = urlparse.urlparse(os.environ['DATABASE_URL'])
# Ensure default database exists.
DATABASES['default'] = DATABASES.get('default', {})
# Update with environment configuration.
DATABASES['default'].update({
'NAME': url.path[1:],
'USER': url.username,
'PASSWORD': url.password,
'HOST': url.hostname,
'PORT': url.port,
})
if url.scheme == 'postgres':
DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
if url.scheme == 'mysql':
DATABASES['default']['ENGINE'] = 'django.db.backends.mysql'
except Exception:
print 'Unexpected error:', sys.exc_info()
EOF
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set +e
# Syntax sugar.
indent() {
RE="s/^/ /"
[ $(uname) == "Darwin" ] && sed -l "$RE" || sed -u "$RE"
}
# Check if collectstatic is configured.
python $MANAGE_FILE collectstatic --help &> /dev/null && RUN_COLLECTSTATIC=true
# Don't raise errors if SILENCE_COLLECTSTATIC is set.
echo "-----> Collecting static files"
set -e
# Compile assets if collectstatic appears to be kosher.
if [ "$RUN_COLLECTSTATIC" ]; then
python $MANAGE_FILE collectstatic --noinput | indent
[ $? -ne 0 ] && {
echo " ! Error running manage.py collectstatic. More info:"
echo " http://devcenter.heroku.com/articles/django-assets"
# exit 1
}
else
echo " ! Django collecstatic is not configured. Learn more:"
echo " http://devcenter.heroku.com/articles/django-assets"
fi
echo
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
SETTINGS_FILE=$(find . -maxdepth 3 -type f -name 'settings.py' | head -1)
PROJECT=$(dirname $SETTINGS_FILE)
MANAGE_FILE=$(find . -maxdepth 3 -type f -name 'manage.py' | head -1)
MANAGE_FILE=${MANAGE_FILE:2}
# Disable injection for new applications.
if [ -f .heroku/injection_disabled ]; then
DISABLE_INJECTION=1
fi
export SETTINGS_FILE MANAGE_FILE PROJECT DISABLE_INJECTION
if [ ! "$DISABLE_INJECTION" ]; then
source $BIN_DIR/steps/django/injection
echo " ! Notice: settings injection will be deprecated for all new Django "
echo " ! apps starting on July 1, 2012. Learn more:"
echo " ! https://devcenter.heroku.com/articles/django-injection"
fi
if [ ! "$DISABLE_COLLECTSTATIC" ]; then
source $BIN_DIR/steps/django/collectstatic
fi
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# This script serves as the Django injection build step of the
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
# compiler.
#
# A [buildpack](http://devcenter.heroku.com/articles/buildpacks) is an
# adapter between a Python application and Heroku's runtime.
#
# This script is invoked by [`bin/compile`](/).
# ## Sanity Checks
#
# Syntax sugar.
indent() {
RE="s/^/ /"
[ $(uname) == "Darwin" ] && sed -l "$RE" || sed -u "$RE"
}
echo "-----> Installing dj-database-url..."
pip install --use-mirrors dj-database-url>=0.2.0 | indent
echo "-----> Injecting Django settings..."
SETTINGS_FILE=$(find . -maxdepth 2 -type f -name 'settings.py' | head -1)
PROJECT=$(dirname $SETTINGS_FILE)
echo "Injecting code into $SETTINGS_FILE to read from DATABASE_URL" | indent
cat >>$SETTINGS_FILE <<EOF
import dj_database_url
DATABASES = {'default': dj_database_url.config(default='postgres://')}
EOF
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
if [ -f bin/post_compile ]; then
echo "-----> Running post-compile hook"
chmod +x bin/post_compile
bin/post_compile
fi
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
if [ -f bin/pre_compile ]; then
echo "-----> Running pre-compile hook"
chmod +x bin/pre_compile
bin/pre_compile
fi
Regular → Executable
+29 -14
View File
@@ -1,20 +1,35 @@
#!/usr/bin/env bash
# if pylibmc within requirements, use vendored libmemcached
if (grep -Fxiq "pylibmc" requirements.txt) || (grep -Fiq "pylibmc=" requirements.txt)
then
echo "-----> Noticed pylibmc. Bootstrapping libmemcached."
cd .heroku
# This script serves as the Pylibmc build step of the
# [**Python Buildpack**](https://github.com/heroku/heroku-buildpack-python)
# compiler.
#
# A [buildpack](http://devcenter.heroku.com/articles/buildpacks) is an
# adapter between a Python application and Heroku's runtime.
#
# This script is invoked by [`bin/compile`](/).
if [ -d "vendor/lib/sasl2" ]; then
export LIBMEMCACHED=$(pwd)/vendor
else
curl -s -L -o tmp-libmemcached.tar.gz $VENDORED_MEMCACHED
tar -zxvf tmp-libmemcached.tar.gz > /dev/null
rm tmp-libmemcached.tar.gz
export LIBMEMCACHED=$(pwd)/vendor
fi
# The location of the pre-compiled libmemcached binary.
VENDORED_MEMCACHED="http://cl.ly/0a191R3K160t1w1P0N25/vendor-libmemcached.tar.gz"
# If pylibmc exists within requirements, use vendored libmemcached.
if (grep -Fiq "pylibmc" requirements.txt) then
echo "-----> Noticed pylibmc. Bootstrapping libmemcached."
cd .heroku
if [ -d "vendor/lib/sasl2" ]; then
export LIBMEMCACHED=$(pwd)/vendor
cd ..
else
# Download and extract libmemcached into target vendor directory.
curl -s -L -o tmp-libmemcached.tar.gz $VENDORED_MEMCACHED
tar -zxvf tmp-libmemcached.tar.gz > /dev/null
rm tmp-libmemcached.tar.gz
export LIBMEMCACHED=$(pwd)/vendor
fi
export LIBMEMCACHED=$(pwd)/vendor
cd ..
fi
Executable
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env bash
#
# Create a Heroku app with the following buildpack:
# https://github.com/ddollar/buildpack-tet
#
# Push this Python buildpack to that Heroku app to
# run the tests.
#
testDetectWithReqs() {
detect "simple-requirements"
assertCapturedEquals "Python"
assertCapturedSuccess
}
testDetectWithEmptyReqs() {
detect "empty-requirements"
assertCapturedEquals "Python"
assertCapturedSuccess
}
testDetectDjango14() {
detect "django-1.4-skeleton"
assertCapturedEquals "Python/Django"
assertCapturedSuccess
}
testDetectDjango13() {
detect "django-1.3-skeleton"
assertCapturedEquals "Python/Django"
assertCapturedSuccess
}
testDetectNotDjangoWithSettings() {
detect "not-django"
assertCapturedEquals "Python"
assertCapturedSuccess
}
testDetectWithSetupPy() {
detect "distutils"
assertCapturedEquals "Python"
assertCapturedSuccess
}
testDetectWithSetupRequires() {
detect "no-requirements"
assertCapturedEquals "Python"
assertCapturedSuccess
}
testDetectNotPython() {
detect "not-python"
assertNotCaptured "Python"
assertEquals "1" "${RETURN}"
}
## utils ########################################
pushd $(dirname 0) >/dev/null
BASE=$(pwd)
popd >/dev/null
source ${BASE}/vendor/test-utils
detect() {
capture ${BASE}/bin/detect ${BASE}/test/$1
}
compile() {
capture ${BASE}/bin/compile ${BASE}/test/$1
}
source ${BASE}/vendor/shunit2
+210
View File
@@ -0,0 +1,210 @@
# -*- coding: utf-8 -*-
"""
envoy.core
~~~~~~~~~~
This module provides envoy awesomeness.
Copyright 2012, Kenneth Reitz.
MIT Licensed.
"""
import os
import shlex
import subprocess
import threading
__version__ = '0.0.2'
__license__ = 'MIT'
__author__ = 'Kenneth Reitz'
class Command(object):
def __init__(self, cmd):
self.cmd = cmd
self.process = None
self.out = None
self.err = None
self.returncode = None
self.data = None
def run(self, data, timeout, env):
self.data = data
environ = dict(os.environ).update(env or {})
def target():
self.process = subprocess.Popen(self.cmd,
universal_newlines=True,
shell=False,
env=environ,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0,
)
self.out, self.err = self.process.communicate(self.data)
thread = threading.Thread(target=target)
thread.start()
thread.join(timeout)
if thread.is_alive():
self.process.terminate()
thread.join()
self.returncode = self.process.returncode
return self.out, self.err
class ConnectedCommand(object):
def __init__(self,
process=None,
std_in=None,
std_out=None,
std_err=None):
self._process = process
self.std_in = std_in
self.std_out = std_out
self.std_err = std_out
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.kill()
@property
def status_code(self):
"""The status code of the process.
If the code is None, assume that it's still running.
"""
if self._status_code is not None:
return self._status_code
# investigate
return None
@property
def pid(self):
"""The process' PID."""
return self._process.pid
def kill(self):
"""Kills the process."""
return self._process.kill()
def expect(self, bytes, stream=None):
"""Block until given bytes appear in the stream."""
if stream is None:
stream = self.std_out
pass
def send(self, end='\n'):
"""Sends a line to std_in."""
#TODO: Y U LINE BUFFER
pass
def block(self):
"""Blocks until command finishes. Returns Response instance."""
self._status_code = self._process.wait()
class Response(object):
"""A command's response"""
def __init__(self, process=None):
super(Response, self).__init__()
self._process = process
self.command = None
self.std_err = None
self.std_out = None
self.status_code = None
self.history = []
def __repr__(self):
if len(self.command):
return '<Response [{0}]>'.format(self.command[0])
else:
return '<Response>'
def expand_args(command):
"""Parses command strings and returns a Popen-ready list."""
# Prepare arguments.
if isinstance(command, basestring):
splitter = shlex.shlex(command, posix=True)
splitter.whitespace = '|'
splitter.whitespace_split = True
command = []
while True:
token = splitter.get_token()
if token:
command.append(token)
else:
break
command = map(shlex.split, command)
return command
def run(command, data=None, timeout=None, env=None):
"""Executes a given commmand and returns Response.
Blocks until process is complete, or timeout is reached.
"""
command = expand_args(command)
history = []
for c in command:
if len(history):
# due to broken pipe problems pass only first 10MB
data = history[-1].std_out[0:10*1024]
cmd = Command(c)
out, err = cmd.run(data, timeout, env)
r = Response(process=cmd)
r.command = c
r.std_out = out
r.std_err = err
r.status_code = cmd.returncode
history.append(r)
r = history.pop()
r.history = history
return r
def connect(command, data=None, env=None):
"""Spawns a new process from the given command."""
# TODO: support piped commands
command_str = expand_args(command).pop()
environ = dict(os.environ).update(env or {})
process = subprocess.Popen(command_str,
universal_newlines=True,
shell=False,
env=environ,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0,
)
return ConnectedCommand(process=process)
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import envoy
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
if sys.argv[-1] == "publish":
os.system("python setup.py sdist upload")
sys.exit()
required = []
setup(
name='envoy',
version=envoy.__version__,
description='Simple API for running external processes.',
author='Kenneth Reitz',
author_email='me@kennethreitz.com',
url='https://github.com/kennethreitz/envoy',
py_modules= ['envoy'],
install_requires=required,
license='MIT',
classifiers=(
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Natural Language :: English',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
# 'Programming Language :: Python :: 3.0',
# 'Programming Language :: Python :: 3.1',
),
)
@@ -0,0 +1,14 @@
#!/usr/bin/env python
from django.core.management import execute_manager
import imp
try:
imp.find_module('settings') # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
sys.exit(1)
import settings
if __name__ == "__main__":
execute_manager(settings)
@@ -0,0 +1,145 @@
# Django settings for haystack project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@example.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# URL prefix for admin static files -- CSS, JavaScript and images.
# Make sure to use a trailing slash.
# Examples: "http://foo.com/static/admin/", "/static/admin/".
ADMIN_MEDIA_PREFIX = '/static/admin/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# Make this unique, and don't share it with anybody.
SECRET_KEY = '@$87s&royz$nvav^3*$4u6^htybq*o=ge504rqp7r2)@ec*g(3'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
ROOT_URLCONF = 'haystack.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
)
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
+17
View File
@@ -0,0 +1,17 @@
from django.conf.urls.defaults import patterns, include, url
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'haystack.views.home', name='home'),
# url(r'^haystack/', include('haystack.foo.urls')),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
# url(r'^admin/', include(admin.site.urls)),
)
@@ -0,0 +1 @@
django==1.3
Binary file not shown.
@@ -0,0 +1,154 @@
# Django settings for haystack project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@example.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale.
USE_L10N = True
# If you set this to False, Django will not use timezone-aware datetimes.
USE_TZ = True
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# Make this unique, and don't share it with anybody.
SECRET_KEY = '633$+yuh67kvt_v8gpi9zmkvqb*m5nts6&amp;a=q^dwhi+e#^j_ki'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'haystack.urls'
# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'haystack.wsgi.application'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
)
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
+17
View File
@@ -0,0 +1,17 @@
from django.conf.urls import patterns, include, url
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'haystack.views.home', name='home'),
# url(r'^haystack/', include('haystack.foo.urls')),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
# url(r'^admin/', include(admin.site.urls)),
)
+28
View File
@@ -0,0 +1,28 @@
"""
WSGI config for haystack project.
This module contains the WSGI application used by Django's development server
and any production WSGI deployments. It should expose a module-level variable
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
this application via the ``WSGI_APPLICATION`` setting.
Usually you will have the standard Django WSGI application here, but it also
might make sense to replace the whole Django WSGI application with a custom one
that later delegates to the Django one. For example, you could introduce WSGI
middleware here, or combine a Django application with an application of another
framework.
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "haystack.settings")
# This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
# Apply WSGI middleware here.
# from helloworld.wsgi import HelloWorldApplication
# application = HelloWorldApplication(application)
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "haystack.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
@@ -0,0 +1 @@
Django==1.4
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
required = ['httpbin']
setup(
name='haystack',
version='0.0.1',
description='Simple API for running external processes.',
author='Kenneth Reitz',
author_email='me@kennethreitz.com',
install_requires=required,
license='MIT',
classifiers=(
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Natural Language :: English',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
# 'Programming Language :: Python :: 3.0',
# 'Programming Language :: Python :: 3.1',
),
)
View File
+1
View File
@@ -0,0 +1 @@
flask==0.8
View File
@@ -0,0 +1 @@
httpbin
Vendored Executable
+1048
View File
File diff suppressed because it is too large Load Diff
+204
View File
@@ -0,0 +1,204 @@
#!/bin/sh
# taken from
# https://github.com/ryanbrainard/heroku-buildpack-testrunner/blob/master/lib/test_utils.sh
oneTimeSetUp()
{
TEST_SUITE_CACHE="$(mktemp -d ${SHUNIT_TMPDIR}/test_suite_cache.XXXX)"
}
oneTimeTearDown()
{
rm -rf ${TEST_SUITE_CACHE}
}
setUp()
{
OUTPUT_DIR="$(mktemp -d ${SHUNIT_TMPDIR}/output.XXXX)"
STD_OUT="${OUTPUT_DIR}/stdout"
STD_ERR="${OUTPUT_DIR}/stderr"
BUILD_DIR="${OUTPUT_DIR}/build"
CACHE_DIR="${OUTPUT_DIR}/cache"
mkdir -p ${OUTPUT_DIR}
mkdir -p ${BUILD_DIR}
mkdir -p ${CACHE_DIR}
}
tearDown()
{
rm -rf ${OUTPUT_DIR}
}
capture()
{
resetCapture
LAST_COMMAND="$@"
$@ >${STD_OUT} 2>${STD_ERR}
RETURN=$?
rtrn=${RETURN} # deprecated
}
resetCapture()
{
if [ -f ${STD_OUT} ]; then
rm ${STD_OUT}
fi
if [ -f ${STD_ERR} ]; then
rm ${STD_ERR}
fi
unset LAST_COMMAND
unset RETURN
unset rtrn # deprecated
}
detect()
{
capture ${BUILDPACK_HOME}/bin/detect ${BUILD_DIR}
}
compile()
{
capture ${BUILDPACK_HOME}/bin/compile ${BUILD_DIR} ${CACHE_DIR}
}
release()
{
capture ${BUILDPACK_HOME}/bin/release ${BUILD_DIR}
}
assertCapturedEquals()
{
assertEquals "$@" "$(cat ${STD_OUT})"
}
assertCapturedNotEquals()
{
assertNotEquals "$@" "$(cat ${STD_OUT})"
}
assertCaptured()
{
assertFileContains "$@" "${STD_OUT}"
}
assertNotCaptured()
{
assertFileNotContains "$@" "${STD_OUT}"
}
assertCapturedSuccess()
{
assertEquals "Expected captured exit code to be 0; was <${RETURN}>" "0" "${RETURN}"
assertEquals "Expected STD_ERR to be empty; was <$(cat ${STD_ERR})>" "" "$(cat ${STD_ERR})"
}
# assertCapturedError [[expectedErrorCode] expectedErrorMsg]
assertCapturedError()
{
if [ $# -gt 1 ]; then
expectedErrorCode=${1}
shift
fi
expectedErrorMsg=${1:-""}
if [ -z ${expectedErrorCode} ]; then
assertTrue "Expected captured exit code to be greater than 0; was <${RETURN}>" "[ ${RETURN} -gt 0 ]"
else
assertTrue "Expected captured exit code to be <${expectedErrorCode}>; was <${RETURN}>" "[ ${RETURN} -eq ${expectedErrorCode} ]"
fi
assertFileContains "Expected STD_OUT to contain error <${expectedErrorMsg}>" "${expectedErrorMsg}" "${STD_OUT}"
assertEquals "STD_ERR should always be empty" "" "$(cat ${STD_ERR})"
}
assertAppDetected()
{
expectedAppType=${1?"Must provide app type"}
assertCapturedSuccess
assertEquals "${expectedAppType}" "$(cat ${STD_OUT})"
}
assertNoAppDetected()
{
assertEquals "1" "${RETURN}"
assertEquals "no" "$(cat ${STD_OUT})"
assertEquals "" "$(cat ${STD_ERR})"
}
_assertContains()
{
if [ 5 -eq $# ]; then
msg=$1
shift
elif [ ! 4 -eq $# ]; then
fail "Expected 4 or 5 parameters; Receieved $# parameters"
fi
needle=$1
haystack=$2
expectation=$3
haystack_type=$4
case "${haystack_type}" in
"file") grep -q -F -e "${needle}" ${haystack} ;;
"text") echo "${haystack}" | grep -q -F -e "${needle}" ;;
esac
if [ "${expectation}" != "$?" ]; then
case "${expectation}" in
0) default_msg="Expected <${haystack}> to contain <${needle}>" ;;
1) default_msg="Did not expect <${haystack}> to contain <${needle}>" ;;
esac
fail "${msg:-${default_msg}}"
fi
}
assertContains()
{
_assertContains "$@" 0 "text"
}
assertNotContains()
{
_assertContains "$@" 1 "text"
}
assertFileContains()
{
_assertContains "$@" 0 "file"
}
assertFileNotContains()
{
_assertContains "$@" 1 "file"
}
command_exists () {
type "$1" > /dev/null 2>&1 ;
}
assertFileMD5()
{
expectedHash=$1
filename=$2
if command_exists "md5sum"; then
md5_cmd="md5sum ${filename}"
expected_md5_cmd_output="${expectedHash} ${filename}"
elif command_exists "md5"; then
md5_cmd="md5 ${filename}"
expected_md5_cmd_output="MD5 (${filename}) = ${expectedHash}"
else
fail "no suitable MD5 hashing command found on this system"
fi
assertEquals "${expected_md5_cmd_output}" "`${md5_cmd}`"
}
View File