mirror of
https://github.com/kennethreitz/heroku-buildpack-python.git
synced 2026-06-05 23:10:16 +00:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8740fcdbad | |||
| fb18948243 | |||
| e104d36785 | |||
| 1786231a49 | |||
| fa8e09ae9c | |||
| 2dd212d020 | |||
| 15acd305d1 | |||
| 5a65a39c5e | |||
| f18754f8f0 | |||
| e860234d05 | |||
| 50d61d2935 | |||
| 47c40ce086 | |||
| 2032942b61 | |||
| 0076fe4f53 | |||
| 9b18412ecc | |||
| 5f0ba6a371 | |||
| 1e2953b22e | |||
| e27ad6f919 | |||
| bfa7180b7b | |||
| 24ae4f9bda | |||
| cbb7512c9a | |||
| 869576e8ab | |||
| 9187dccb54 | |||
| eb6193d13e | |||
| a43eaaaf81 | |||
| c31574d7d6 | |||
| 3a42f565cb | |||
| 8f1942a9a5 | |||
| ab05b61638 | |||
| 5c4a414cb7 | |||
| 0e11dbadbf | |||
| 96cf5718b2 | |||
| d3f8351744 | |||
| 9d903fd92f | |||
| f77d8aaec3 | |||
| 4c2b867172 | |||
| 1bdf4a0c64 | |||
| c2b1465548 | |||
| f4471062a9 | |||
| f843a95343 | |||
| 1605422808 | |||
| 5ee2bdbd10 | |||
| f4c7160763 | |||
| 3e81740517 | |||
| a8e065969f | |||
| 688d167190 | |||
| 4553dafeca | |||
| 8aeceb00e4 | |||
| 022aa736ec | |||
| 2cad413958 | |||
| f5fb42e535 | |||
| 4995eeec41 | |||
| 0961b59420 | |||
| 1fdeedf112 |
@@ -1,6 +0,0 @@
|
|||||||
language: python
|
|
||||||
python:
|
|
||||||
- 2.7
|
|
||||||
script: make tests
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
@@ -17,11 +17,8 @@ Example usage:
|
|||||||
$ git push heroku master
|
$ git push heroku master
|
||||||
...
|
...
|
||||||
-----> Python app detected
|
-----> Python app detected
|
||||||
-----> No runtime.txt provided; assuming python-2.7.8.
|
-----> Installing runtime (python-2.7.8)
|
||||||
-----> Preparing Python runtime (python-2.7.8)
|
-----> Installing dependencies using pip
|
||||||
-----> Installing Setuptools (3.6)
|
|
||||||
-----> Installing Pip (1.5.6)
|
|
||||||
-----> Installing dependencies using Pip (1.5.6)
|
|
||||||
Downloading/unpacking requests (from -r requirements.txt (line 1))
|
Downloading/unpacking requests (from -r requirements.txt (line 1))
|
||||||
Installing collected packages: requests
|
Installing collected packages: requests
|
||||||
Successfully installed requests
|
Successfully installed requests
|
||||||
|
|||||||
+22
-95
@@ -26,9 +26,10 @@ LEGACY_TRIGGER="lib/python2.7"
|
|||||||
PROFILE_PATH="$BUILD_DIR/.profile.d/python.sh"
|
PROFILE_PATH="$BUILD_DIR/.profile.d/python.sh"
|
||||||
|
|
||||||
DEFAULT_PYTHON_VERSION="python-2.7.8"
|
DEFAULT_PYTHON_VERSION="python-2.7.8"
|
||||||
|
DEFAULT_PYTHON_STACK="cedar"
|
||||||
PYTHON_EXE="/app/.heroku/python/bin/python"
|
PYTHON_EXE="/app/.heroku/python/bin/python"
|
||||||
PIP_VERSION="1.5.6"
|
PIP_VERSION="1.5.6"
|
||||||
SETUPTOOLS_VERSION="3.6"
|
SETUPTOOLS_VERSION="5.4.1"
|
||||||
|
|
||||||
# Setup bpwatch
|
# Setup bpwatch
|
||||||
export PATH=$PATH:$ROOT_DIR/vendor/bpwatch
|
export PATH=$PATH:$ROOT_DIR/vendor/bpwatch
|
||||||
@@ -36,9 +37,13 @@ LOGPLEX_KEY="t.b90d9d29-5388-4908-9737-b4576af1d4ce"
|
|||||||
export BPWATCH_STORE_PATH=$CACHE_DIR/bpwatch.json
|
export BPWATCH_STORE_PATH=$CACHE_DIR/bpwatch.json
|
||||||
BUILDPACK_VERSION=v28
|
BUILDPACK_VERSION=v28
|
||||||
|
|
||||||
|
# Setup pip-pop (pip-diff)
|
||||||
|
export PATH=$PATH:$ROOT_DIR/vendor/pip-pop
|
||||||
|
|
||||||
# Support Anvil Build_IDs
|
# Support Anvil Build_IDs
|
||||||
[ ! "$SLUG_ID" ] && SLUG_ID="defaultslug"
|
[ ! "$SLUG_ID" ] && SLUG_ID="defaultslug"
|
||||||
[ ! "$REQUEST_ID" ] && REQUEST_ID=$SLUG_ID
|
[ ! "$REQUEST_ID" ] && REQUEST_ID=$SLUG_ID
|
||||||
|
[ ! "$STACK" ] && STACK=$DEFAULT_PYTHON_STACK
|
||||||
|
|
||||||
# Sanitizing environment variables.
|
# Sanitizing environment variables.
|
||||||
unset GIT_DIR PYTHONHOME PYTHONPATH LD_LIBRARY_PATH LIBRARY_PATH
|
unset GIT_DIR PYTHONHOME PYTHONPATH LD_LIBRARY_PATH LIBRARY_PATH
|
||||||
@@ -99,7 +104,6 @@ bpwatch stop pre_compile
|
|||||||
|
|
||||||
# If no requirements given, assume `setup.py develop`.
|
# If no requirements given, assume `setup.py develop`.
|
||||||
if [ ! -f requirements.txt ]; then
|
if [ ! -f requirements.txt ]; then
|
||||||
puts-step "No requirements.txt provided; assuming dist package."
|
|
||||||
echo "-e ." > requirements.txt
|
echo "-e ." > requirements.txt
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -108,6 +112,13 @@ if [ -f $CACHE_DIR/.heroku/python-version ]; then
|
|||||||
DEFAULT_PYTHON_VERSION=$(cat $CACHE_DIR/.heroku/python-version)
|
DEFAULT_PYTHON_VERSION=$(cat $CACHE_DIR/.heroku/python-version)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Stack fallback for non-declared caches.
|
||||||
|
if [ -f $CACHE_DIR/.heroku/python-stack ]; then
|
||||||
|
CACHED_PYTHON_STACK=$(cat $CACHE_DIR/.heroku/python-stack)
|
||||||
|
else
|
||||||
|
CACHED_PYTHON_STACK=$DEFAULT_PYTHON_STACK
|
||||||
|
fi
|
||||||
|
|
||||||
# If no runtime given, assume default version.
|
# If no runtime given, assume default version.
|
||||||
if [ ! -f runtime.txt ]; then
|
if [ ! -f runtime.txt ]; then
|
||||||
echo $DEFAULT_PYTHON_VERSION > runtime.txt
|
echo $DEFAULT_PYTHON_VERSION > runtime.txt
|
||||||
@@ -136,108 +147,24 @@ set -e
|
|||||||
|
|
||||||
mkdir -p $(dirname $PROFILE_PATH)
|
mkdir -p $(dirname $PROFILE_PATH)
|
||||||
|
|
||||||
set +e
|
|
||||||
PYTHON_VERSION=$(cat runtime.txt)
|
|
||||||
|
|
||||||
# Install Python.
|
# Install Python.
|
||||||
if [ -f .heroku/python-version ]; then
|
source $BIN_DIR/steps/python
|
||||||
if [ ! $(cat .heroku/python-version) = $PYTHON_VERSION ]; then
|
|
||||||
bpwatch start uninstall_python
|
|
||||||
puts-step "Found $(cat .heroku/python-version), removing."
|
|
||||||
rm -fr .heroku/python
|
|
||||||
bpwatch stop uninstall_python
|
|
||||||
else
|
|
||||||
SKIP_INSTALL=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
# Uninstall removed dependencies with Pip.
|
||||||
|
source $BIN_DIR/steps/pip-uninstall
|
||||||
|
|
||||||
if [ ! "$SKIP_INSTALL" ]; then
|
# Mercurial support.
|
||||||
bpwatch start install_python
|
source $BIN_DIR/steps/mercurial
|
||||||
puts-step "Preparing Python runtime ($PYTHON_VERSION)"
|
|
||||||
|
|
||||||
# Prepare destination directory.
|
|
||||||
mkdir -p .heroku/python
|
|
||||||
|
|
||||||
curl http://lang-python.s3.amazonaws.com/runtimes/$PYTHON_VERSION.tar.gz -s | tar zxv -C .heroku/python &> /dev/null
|
|
||||||
if [[ $? != 0 ]] ; then
|
|
||||||
puts-warn "Requested runtime ($PYTHON_VERSION) was not found."
|
|
||||||
puts-warn "Aborting. More info: https://devcenter.heroku.com/articles/python-support"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
bpwatch stop install_python
|
|
||||||
|
|
||||||
# Record for future reference.
|
|
||||||
echo $PYTHON_VERSION > .heroku/python-version
|
|
||||||
FRESH_PYTHON=true
|
|
||||||
|
|
||||||
hash -r
|
|
||||||
else
|
|
||||||
puts-step "Using Python runtime ($PYTHON_VERSION)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If Pip isn't up to date:
|
|
||||||
if [ "$FRESH_PYTHON" ] || [[ ! $(pip --version) == *$PIP_VERSION* ]]; then
|
|
||||||
WORKING_DIR=$(pwd)
|
|
||||||
|
|
||||||
bpwatch start prepare_environment
|
|
||||||
|
|
||||||
bpwatch start install_setuptools
|
|
||||||
# Prepare it for the real world
|
|
||||||
puts-step "Installing Setuptools ($SETUPTOOLS_VERSION)"
|
|
||||||
cd $ROOT_DIR/vendor/
|
|
||||||
tar zxf setuptools-$SETUPTOOLS_VERSION.tar.gz
|
|
||||||
cd $ROOT_DIR/vendor/setuptools-$SETUPTOOLS_VERSION/
|
|
||||||
python setup.py install &> /dev/null
|
|
||||||
cd $WORKING_DIR
|
|
||||||
bpwatch stop install_setuptoools
|
|
||||||
|
|
||||||
bpwatch start install_pip
|
|
||||||
puts-step "Installing Pip ($PIP_VERSION)"
|
|
||||||
|
|
||||||
cd $ROOT_DIR/vendor/
|
|
||||||
tar zxf pip-$PIP_VERSION.tar.gz
|
|
||||||
cd $ROOT_DIR/vendor/pip-$PIP_VERSION/
|
|
||||||
python setup.py install &> /dev/null
|
|
||||||
cd $WORKING_DIR
|
|
||||||
|
|
||||||
bpwatch stop install_pip
|
|
||||||
bpwatch stop prepare_environment
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -e
|
|
||||||
hash -r
|
|
||||||
|
|
||||||
# Pylibmc support.
|
# Pylibmc support.
|
||||||
# See [`bin/steps/pylibmc`](pylibmc.html).
|
source $BIN_DIR/steps/pylibmc
|
||||||
bpwatch start pylibmc_install
|
|
||||||
source $BIN_DIR/steps/pylibmc
|
|
||||||
bpwatch stop pylibmc_install
|
|
||||||
|
|
||||||
# Install Mercurial if it appears to be required.
|
|
||||||
if (grep -Fiq "hg+" requirements.txt) then
|
|
||||||
bpwatch start mercurial_install
|
|
||||||
/app/.heroku/python/bin/pip install mercurial | cleanup | indent
|
|
||||||
bpwatch stop mercurial_install
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install dependencies with Pip.
|
# Install dependencies with Pip.
|
||||||
puts-step "Installing dependencies using Pip ($PIP_VERSION)"
|
source $BIN_DIR/steps/pip-install
|
||||||
|
|
||||||
|
|
||||||
[ ! "$FRESH_PYTHON" ] && bpwatch start pip_install
|
|
||||||
[ "$FRESH_PYTHON" ] && bpwatch start pip_install_first
|
|
||||||
|
|
||||||
/app/.heroku/python/bin/pip install -r requirements.txt --exists-action=w --src=./.heroku/src --allow-all-external | cleanup | indent
|
|
||||||
|
|
||||||
[ ! "$FRESH_PYTHON" ] && bpwatch stop pip_install
|
|
||||||
[ "$FRESH_PYTHON" ] && bpwatch stop pip_install_first
|
|
||||||
|
|
||||||
# Django collectstatic support.
|
# Django collectstatic support.
|
||||||
bpwatch start collectstatic
|
sub-env $BIN_DIR/steps/collectstatic
|
||||||
sub-env $BIN_DIR/steps/collectstatic
|
|
||||||
bpwatch stop collectstatic
|
|
||||||
|
|
||||||
# ### Finalize
|
# ### Finalize
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ MANAGE_FILE=${MANAGE_FILE:-fakepath}
|
|||||||
|
|
||||||
[ -f .heroku/collectstatic_disabled ] && DISABLE_COLLECTSTATIC=1
|
[ -f .heroku/collectstatic_disabled ] && DISABLE_COLLECTSTATIC=1
|
||||||
|
|
||||||
|
bpwatch start collectstatic
|
||||||
|
|
||||||
if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ]; then
|
if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ]; then
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
@@ -28,9 +30,7 @@ if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ]; then
|
|||||||
echo " Collectstatic configuration error. To debug, run:"
|
echo " Collectstatic configuration error. To debug, run:"
|
||||||
echo " $ heroku run python $MANAGE_FILE collectstatic --noinput"
|
echo " $ heroku run python $MANAGE_FILE collectstatic --noinput"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
bpwatch stop collectstatic
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
# Install Mercurial if it appears to be required.
|
||||||
|
if (grep -Fiq "hg+" requirements.txt) then
|
||||||
|
bpwatch start mercurial_install
|
||||||
|
/app/.heroku/python/bin/pip install mercurial | cleanup | indent
|
||||||
|
bpwatch stop mercurial_install
|
||||||
|
fi
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# Install dependencies with Pip.
|
||||||
|
puts-step "Installing dependencies with pip"
|
||||||
|
|
||||||
|
[ ! "$FRESH_PYTHON" ] && bpwatch start pip_install
|
||||||
|
[ "$FRESH_PYTHON" ] && bpwatch start pip_install_first
|
||||||
|
|
||||||
|
/app/.heroku/python/bin/pip install -r requirements.txt --exists-action=w --src=./.heroku/src --allow-all-external | cleanup | indent
|
||||||
|
|
||||||
|
# Smart Requirements handling
|
||||||
|
cp requirements.txt .heroku/python/requirements-declared.txt
|
||||||
|
/app/.heroku/python/bin/pip freeze > .heroku/python/requirements-installed.txt
|
||||||
|
|
||||||
|
[ ! "$FRESH_PYTHON" ] && bpwatch stop pip_install
|
||||||
|
[ "$FRESH_PYTHON" ] && bpwatch stop pip_install_first
|
||||||
|
|
||||||
|
echo
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
set +e
|
||||||
|
# Install dependencies with Pip.
|
||||||
|
bpwatch start pip_uninstall
|
||||||
|
if [[ -f .heroku/python/requirements-declared.txt ]]; then
|
||||||
|
|
||||||
|
cp .heroku/python/requirements-declared.txt requirements-declared.txt
|
||||||
|
|
||||||
|
pip-diff --stale requirements-declared.txt requirements.txt > .heroku/python/requirements-stale.txt
|
||||||
|
|
||||||
|
rm -fr requirements-declared.txt
|
||||||
|
|
||||||
|
if [[ -s .heroku/python/requirements-stale.txt ]]; then
|
||||||
|
puts-step "Uninstalling stale dependencies"
|
||||||
|
/app/.heroku/python/bin/pip uninstall -r .heroku/python/requirements-stale.txt -y --exists-action=w | cleanup | indent
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
bpwatch stop pip_uninstall
|
||||||
|
set -e
|
||||||
+9
-12
@@ -10,29 +10,26 @@
|
|||||||
# This script is invoked by [`bin/compile`](/).
|
# This script is invoked by [`bin/compile`](/).
|
||||||
|
|
||||||
# The location of the pre-compiled libmemcached binary.
|
# The location of the pre-compiled libmemcached binary.
|
||||||
VENDORED_MEMCACHED="http://cl.ly/0a191R3K160t1w1P0N25/vendor-libmemcached.tar.gz"
|
VENDORED_MEMCACHED="http://lang-python.s3.amazonaws.com/$STACK/libraries/vendor/libmemcache.tar.gz"
|
||||||
|
|
||||||
# Syntax sugar.
|
# Syntax sugar.
|
||||||
source $BIN_DIR/utils
|
source $BIN_DIR/utils
|
||||||
|
|
||||||
|
bpwatch start pylibmc_install
|
||||||
|
|
||||||
# If pylibmc exists within requirements, use vendored libmemcached.
|
# If pylibmc exists within requirements, use vendored libmemcached.
|
||||||
if (grep -Eiq "\s*pylibmc" requirements.txt) then
|
if (pip-grep -s requirements.txt pylibmc) then
|
||||||
echo "-----> Noticed pylibmc. Bootstrapping libmemcached."
|
|
||||||
cd .heroku
|
|
||||||
|
|
||||||
if [ -d "vendor/lib/sasl2" ]; then
|
if [ -d "vendor/lib/sasl2" ]; then
|
||||||
export LIBMEMCACHED=$(pwd)/vendor
|
export LIBMEMCACHED=$(pwd)/vendor
|
||||||
else
|
else
|
||||||
|
echo "-----> Noticed pylibmc. Bootstrapping libmemcached."
|
||||||
|
mkdir -p .heroku/vendor
|
||||||
# Download and extract libmemcached into target vendor directory.
|
# Download and extract libmemcached into target vendor directory.
|
||||||
curl -s -L -o tmp-libmemcached.tar.gz $VENDORED_MEMCACHED
|
curl $VENDORED_MEMCACHED -s | tar zxv -C .heroku/vendor &> /dev/null
|
||||||
tar -zxvf tmp-libmemcached.tar.gz > /dev/null
|
|
||||||
rm tmp-libmemcached.tar.gz
|
|
||||||
export LIBMEMCACHED=$(pwd)/vendor
|
export LIBMEMCACHED=$(pwd)/vendor
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export LIBMEMCACHED=$(pwd)/vendor
|
|
||||||
cd ..
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
bpwatch stop pylibmc_install
|
||||||
|
|
||||||
|
|||||||
Executable
+79
@@ -0,0 +1,79 @@
|
|||||||
|
set +e
|
||||||
|
PYTHON_VERSION=$(cat runtime.txt)
|
||||||
|
|
||||||
|
# Install Python.
|
||||||
|
if [ -f .heroku/python-version ]; then
|
||||||
|
if [ ! $(cat .heroku/python-version) = $PYTHON_VERSION ]; then
|
||||||
|
bpwatch start uninstall_python
|
||||||
|
puts-step "Found runtime $(cat .heroku/python-version), removing"
|
||||||
|
rm -fr .heroku/python
|
||||||
|
bpwatch stop uninstall_python
|
||||||
|
else
|
||||||
|
SKIP_INSTALL=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! $STACK = $CACHED_PYTHON_STACK ]; then
|
||||||
|
bpwatch start uninstall_python
|
||||||
|
puts-step "Stack changed, re-installing runtime"
|
||||||
|
rm -fr .heroku/python
|
||||||
|
unset SKIP_INSTALL
|
||||||
|
bpwatch stop uninstall_python
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ ! "$SKIP_INSTALL" ]; then
|
||||||
|
bpwatch start install_python
|
||||||
|
puts-step "Installing runtime ($PYTHON_VERSION)"
|
||||||
|
|
||||||
|
# Prepare destination directory.
|
||||||
|
mkdir -p .heroku/python
|
||||||
|
|
||||||
|
curl http://lang-python.s3.amazonaws.com/$STACK/runtimes/$PYTHON_VERSION.tar.gz -s | tar zxv -C .heroku/python &> /dev/null
|
||||||
|
if [[ $? != 0 ]] ; then
|
||||||
|
puts-warn "Requested runtime ($PYTHON_VERSION) is not available for this stack ($STACK)."
|
||||||
|
puts-warn "Aborting. More info: https://devcenter.heroku.com/articles/python-support"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
bpwatch stop install_python
|
||||||
|
|
||||||
|
# Record for future reference.
|
||||||
|
echo $PYTHON_VERSION > .heroku/python-version
|
||||||
|
echo $STACK > .heroku/python-stack
|
||||||
|
FRESH_PYTHON=true
|
||||||
|
|
||||||
|
hash -r
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If Pip isn't up to date:
|
||||||
|
if [ "$FRESH_PYTHON" ] || [[ ! $(pip --version) == *$PIP_VERSION* ]]; then
|
||||||
|
WORKING_DIR=$(pwd)
|
||||||
|
|
||||||
|
bpwatch start prepare_environment
|
||||||
|
|
||||||
|
bpwatch start install_setuptools
|
||||||
|
# Prepare it for the real world
|
||||||
|
# puts-step "Installing Setuptools ($SETUPTOOLS_VERSION)"
|
||||||
|
cd $ROOT_DIR/vendor/
|
||||||
|
tar zxf setuptools-$SETUPTOOLS_VERSION.tar.gz
|
||||||
|
cd $ROOT_DIR/vendor/setuptools-$SETUPTOOLS_VERSION/
|
||||||
|
python setup.py install &> /dev/null
|
||||||
|
cd $WORKING_DIR
|
||||||
|
bpwatch stop install_setuptoools
|
||||||
|
|
||||||
|
bpwatch start install_pip
|
||||||
|
# puts-step "Installing Pip ($PIP_VERSION)"
|
||||||
|
|
||||||
|
cd $ROOT_DIR/vendor/
|
||||||
|
tar zxf pip-$PIP_VERSION.tar.gz
|
||||||
|
cd $ROOT_DIR/vendor/pip-$PIP_VERSION/
|
||||||
|
python setup.py install &> /dev/null
|
||||||
|
cd $WORKING_DIR
|
||||||
|
|
||||||
|
bpwatch stop install_pip
|
||||||
|
bpwatch stop prepare_environment
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
hash -r
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building autoconf..."
|
||||||
|
|
||||||
|
|
||||||
|
SOURCE_TARBALL='http://ftp.gnu.org/gnu/autoconf/autoconf-2.68.tar.gz'
|
||||||
|
curl -L $SOURCE_TARBALL | tar xz
|
||||||
|
|
||||||
|
cd autoconf-2.68
|
||||||
|
./configure --prefix=$OUT_PREFIX
|
||||||
|
make
|
||||||
|
make install
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/autoconf
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
# Use new path, containing autoconf.
|
||||||
|
export PATH="/app/.heroku/python/bin/:$PATH"
|
||||||
|
hash -r
|
||||||
|
|
||||||
|
|
||||||
|
echo "Building libffi..."
|
||||||
|
|
||||||
|
SOURCE_TARBALL='https://github.com/atgreen/libffi/archive/master.tar.gz'
|
||||||
|
|
||||||
|
curl -L $SOURCE_TARBALL | tar xz
|
||||||
|
mv libffi-master libffi
|
||||||
|
|
||||||
|
cd libffi
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix=$OUT_PREFIX --enable-shared
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
cd ..
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/vendor/
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
# fail hard
|
||||||
|
set -o pipefail
|
||||||
|
# fail harder
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
DEFAULT_VERSION="1.0.18"
|
||||||
|
dep_version=${VERSION:-$DEFAULT_VERSION}
|
||||||
|
dep_dirname=libmemcached-${dep_version}
|
||||||
|
dep_archive_name=${dep_dirname}.tar.gz
|
||||||
|
dep_url=https://launchpad.net/libmemcached/1.0/${dep_version}/+download/${dep_archive_name}
|
||||||
|
|
||||||
|
# SASL Support.
|
||||||
|
echo "-----> Building cyrus-sasl 2.1.26..."
|
||||||
|
|
||||||
|
curl -LO ftp://ftp.cyrusimap.org/cyrus-sasl/cyrus-sasl-2.1.26.tar.gz
|
||||||
|
# FTP doesn't play well with piping into tar xz
|
||||||
|
tar xzf cyrus-sasl-2.1.26.tar.gz
|
||||||
|
|
||||||
|
pushd cyrus-sasl-2.1.26
|
||||||
|
./configure --prefix=${OUT_PREFIX}
|
||||||
|
make -s -j 9
|
||||||
|
make install -s
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo "-----> Building libmemcached ${dep_version}..."
|
||||||
|
|
||||||
|
curl -L ${dep_url} | tar xz
|
||||||
|
pushd ${dep_dirname}
|
||||||
|
CPPFLAGS=-I${OUT_PREFIX}/include LDFLAGS=-L${OUT_PREFIX}/lib ./configure --prefix=${OUT_PREFIX} --without-memcached
|
||||||
|
make -s -j 9
|
||||||
|
make install -s
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo "-----> Done."
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.0/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.0.1/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.0.2/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.1-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.1/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.2-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.2-linux64/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.2.1-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.2.1-linux64/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.3-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.3-linux64/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy-2.3.1-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy-2.3.1-linux64/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar-14 stack, not cedar.
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building PyPy..."
|
||||||
|
SOURCE_TARBALL='https://bitbucket.org/pypy/pypy/downloads/pypy3-2.3.1-linux64.tar.bz2'
|
||||||
|
curl -L $SOURCE_TARBALL | tar jx
|
||||||
|
cp -R pypy3-2.3.1-linux64/* $OUT_PREFIX
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/pypy $OUT_PREFIX/bin/python
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
# Build Path: /app/.heroku/python/
|
# Build Path: /app/.heroku/python/
|
||||||
# Build Deps: libraries/sqlite
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar stack, not cedar-14.
|
||||||
|
|
||||||
OUT_PREFIX=$1
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
# Protect 2.6 builds from parent Python (causes segfault during build).
|
# Protect 2.6 builds from parent Python (causes segfault during build).
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
# Build Path: /app/.heroku/python/
|
# Build Path: /app/.heroku/python/
|
||||||
# Build Deps: libraries/sqlite
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
# NOTICE: This formula only works for the cedar stack, not cedar-14.
|
||||||
|
|
||||||
OUT_PREFIX=$1
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
# Protect 2.6 builds from parent Python (causes segfault during build).
|
# Protect 2.6 builds from parent Python (causes segfault during build).
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ curl -L $SOURCE_TARBALL | tar xz
|
|||||||
mv Python-2.7.8 src
|
mv Python-2.7.8 src
|
||||||
cd src
|
cd src
|
||||||
|
|
||||||
./configure --prefix=$OUT_PREFIX --enable-shared
|
./configure --prefix=$OUT_PREFIX
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
|
|||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Path: /app/.heroku/python/
|
||||||
|
# Build Deps: libraries/sqlite
|
||||||
|
|
||||||
|
OUT_PREFIX=$1
|
||||||
|
|
||||||
|
echo "Building Python..."
|
||||||
|
SOURCE_TARBALL='http://python.org/ftp/python/3.3.5/Python-3.3.5.tgz'
|
||||||
|
curl -L $SOURCE_TARBALL | tar xz
|
||||||
|
mv Python-3.3.5 src
|
||||||
|
cd src
|
||||||
|
|
||||||
|
./configure --prefix=$OUT_PREFIX --enable-shared
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
|
||||||
|
ln $OUT_PREFIX/bin/python3 $OUT_PREFIX/bin/python
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
bob-builder==0.0.5
|
bob-builder==0.0.5
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
# -*- 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 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)
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#!/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',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/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)
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
# 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,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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)),
|
|
||||||
)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
django==1.3
|
|
||||||
BIN
Binary file not shown.
@@ -1,154 +0,0 @@
|
|||||||
# 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&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,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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)),
|
|
||||||
)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
"""
|
|
||||||
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)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/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)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Django==1.4
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
# 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.
|
|
||||||
# The following settings are not used with sqlite3:
|
|
||||||
'USER': '',
|
|
||||||
'PASSWORD': '',
|
|
||||||
'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
|
|
||||||
'PORT': '', # Set to empty string for default.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Hosts/domain names that are valid for this site; required if DEBUG is False
|
|
||||||
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
|
|
||||||
ALLOWED_HOSTS = []
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
# In a Windows environment this must be set to 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: "/var/www/example.com/media/"
|
|
||||||
MEDIA_ROOT = ''
|
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
|
||||||
# trailing slash.
|
|
||||||
# Examples: "http://example.com/media/", "http://media.example.com/"
|
|
||||||
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: "/var/www/example.com/static/"
|
|
||||||
STATIC_ROOT = ''
|
|
||||||
|
|
||||||
# URL prefix for static files.
|
|
||||||
# Example: "http://example.com/static/", "http://static.example.com/"
|
|
||||||
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 = '@w-1$9#jh05!qvbh#1k)c4=w9llcq116f$5(4&s_c)n4@%n=pc'
|
|
||||||
|
|
||||||
# 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,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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)),
|
|
||||||
)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
"""
|
|
||||||
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
|
|
||||||
|
|
||||||
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
|
|
||||||
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
|
||||||
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
|
||||||
# os.environ["DJANGO_SETTINGS_MODULE"] = "haystack.settings"
|
|
||||||
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)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/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)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
django==1.5
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
# 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.
|
|
||||||
# The following settings are not used with sqlite3:
|
|
||||||
'USER': '',
|
|
||||||
'PASSWORD': '',
|
|
||||||
'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
|
|
||||||
'PORT': '', # Set to empty string for default.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Hosts/domain names that are valid for this site; required if DEBUG is False
|
|
||||||
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
|
|
||||||
ALLOWED_HOSTS = []
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
# In a Windows environment this must be set to 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: "/var/www/example.com/media/"
|
|
||||||
MEDIA_ROOT = ''
|
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
|
||||||
# trailing slash.
|
|
||||||
# Examples: "http://example.com/media/", "http://media.example.com/"
|
|
||||||
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: "/var/www/example.com/static/"
|
|
||||||
STATIC_ROOT = ''
|
|
||||||
|
|
||||||
# URL prefix for static files.
|
|
||||||
# Example: "http://example.com/static/", "http://static.example.com/"
|
|
||||||
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 = '@w-1$9#jh05!qvbh#1k)c4=w9llcq116f$5(4&s_c)n4@%n=pc'
|
|
||||||
|
|
||||||
# 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,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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)),
|
|
||||||
)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
"""
|
|
||||||
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
|
|
||||||
|
|
||||||
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
|
|
||||||
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
|
||||||
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
|
||||||
# os.environ["DJANGO_SETTINGS_MODULE"] = "haystack.settings"
|
|
||||||
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)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/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)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
django==1.6
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#!/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',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
flask==0.8
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
pylibmc
|
|
||||||
psycopg2
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
requests
|
|
||||||
distribute==0.6.49
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
requests==2.2.1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pypy-2.3
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
requests==2.2.1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
python-2.7.6
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
requests==2.2.1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
python-3.4.0
|
|
||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|||||||
Vendored
+581
@@ -0,0 +1,581 @@
|
|||||||
|
"""Pythonic command-line interface parser that will make you smile.
|
||||||
|
|
||||||
|
* http://docopt.org
|
||||||
|
* Repository and issue-tracker: https://github.com/docopt/docopt
|
||||||
|
* Licensed under terms of MIT license (see LICENSE-MIT)
|
||||||
|
* Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['docopt']
|
||||||
|
__version__ = '0.6.1'
|
||||||
|
|
||||||
|
|
||||||
|
class DocoptLanguageError(Exception):
|
||||||
|
|
||||||
|
"""Error in construction of usage-message by developer."""
|
||||||
|
|
||||||
|
|
||||||
|
class DocoptExit(SystemExit):
|
||||||
|
|
||||||
|
"""Exit in case user invoked program with incorrect arguments."""
|
||||||
|
|
||||||
|
usage = ''
|
||||||
|
|
||||||
|
def __init__(self, message=''):
|
||||||
|
SystemExit.__init__(self, (message + '\n' + self.usage).strip())
|
||||||
|
|
||||||
|
|
||||||
|
class Pattern(object):
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return repr(self) == repr(other)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(repr(self))
|
||||||
|
|
||||||
|
def fix(self):
|
||||||
|
self.fix_identities()
|
||||||
|
self.fix_repeating_arguments()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def fix_identities(self, uniq=None):
|
||||||
|
"""Make pattern-tree tips point to same object if they are equal."""
|
||||||
|
if not hasattr(self, 'children'):
|
||||||
|
return self
|
||||||
|
uniq = list(set(self.flat())) if uniq is None else uniq
|
||||||
|
for i, child in enumerate(self.children):
|
||||||
|
if not hasattr(child, 'children'):
|
||||||
|
assert child in uniq
|
||||||
|
self.children[i] = uniq[uniq.index(child)]
|
||||||
|
else:
|
||||||
|
child.fix_identities(uniq)
|
||||||
|
|
||||||
|
def fix_repeating_arguments(self):
|
||||||
|
"""Fix elements that should accumulate/increment values."""
|
||||||
|
either = [list(child.children) for child in transform(self).children]
|
||||||
|
for case in either:
|
||||||
|
for e in [child for child in case if case.count(child) > 1]:
|
||||||
|
if type(e) is Argument or type(e) is Option and e.argcount:
|
||||||
|
if e.value is None:
|
||||||
|
e.value = []
|
||||||
|
elif type(e.value) is not list:
|
||||||
|
e.value = e.value.split()
|
||||||
|
if type(e) is Command or type(e) is Option and e.argcount == 0:
|
||||||
|
e.value = 0
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def transform(pattern):
|
||||||
|
"""Expand pattern into an (almost) equivalent one, but with single Either.
|
||||||
|
|
||||||
|
Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
|
||||||
|
Quirks: [-a] => (-a), (-a...) => (-a -a)
|
||||||
|
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
groups = [[pattern]]
|
||||||
|
while groups:
|
||||||
|
children = groups.pop(0)
|
||||||
|
parents = [Required, Optional, OptionsShortcut, Either, OneOrMore]
|
||||||
|
if any(t in map(type, children) for t in parents):
|
||||||
|
child = [c for c in children if type(c) in parents][0]
|
||||||
|
children.remove(child)
|
||||||
|
if type(child) is Either:
|
||||||
|
for c in child.children:
|
||||||
|
groups.append([c] + children)
|
||||||
|
elif type(child) is OneOrMore:
|
||||||
|
groups.append(child.children * 2 + children)
|
||||||
|
else:
|
||||||
|
groups.append(child.children + children)
|
||||||
|
else:
|
||||||
|
result.append(children)
|
||||||
|
return Either(*[Required(*e) for e in result])
|
||||||
|
|
||||||
|
|
||||||
|
class LeafPattern(Pattern):
|
||||||
|
|
||||||
|
"""Leaf/terminal node of a pattern tree."""
|
||||||
|
|
||||||
|
def __init__(self, name, value=None):
|
||||||
|
self.name, self.value = name, value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
|
||||||
|
|
||||||
|
def flat(self, *types):
|
||||||
|
return [self] if not types or type(self) in types else []
|
||||||
|
|
||||||
|
def match(self, left, collected=None):
|
||||||
|
collected = [] if collected is None else collected
|
||||||
|
pos, match = self.single_match(left)
|
||||||
|
if match is None:
|
||||||
|
return False, left, collected
|
||||||
|
left_ = left[:pos] + left[pos + 1:]
|
||||||
|
same_name = [a for a in collected if a.name == self.name]
|
||||||
|
if type(self.value) in (int, list):
|
||||||
|
if type(self.value) is int:
|
||||||
|
increment = 1
|
||||||
|
else:
|
||||||
|
increment = ([match.value] if type(match.value) is str
|
||||||
|
else match.value)
|
||||||
|
if not same_name:
|
||||||
|
match.value = increment
|
||||||
|
return True, left_, collected + [match]
|
||||||
|
same_name[0].value += increment
|
||||||
|
return True, left_, collected
|
||||||
|
return True, left_, collected + [match]
|
||||||
|
|
||||||
|
|
||||||
|
class BranchPattern(Pattern):
|
||||||
|
|
||||||
|
"""Branch/inner node of a pattern tree."""
|
||||||
|
|
||||||
|
def __init__(self, *children):
|
||||||
|
self.children = list(children)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%s)' % (self.__class__.__name__,
|
||||||
|
', '.join(repr(a) for a in self.children))
|
||||||
|
|
||||||
|
def flat(self, *types):
|
||||||
|
if type(self) in types:
|
||||||
|
return [self]
|
||||||
|
return sum([child.flat(*types) for child in self.children], [])
|
||||||
|
|
||||||
|
|
||||||
|
class Argument(LeafPattern):
|
||||||
|
|
||||||
|
def single_match(self, left):
|
||||||
|
for n, pattern in enumerate(left):
|
||||||
|
if type(pattern) is Argument:
|
||||||
|
return n, Argument(self.name, pattern.value)
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse(class_, source):
|
||||||
|
name = re.findall('(<\S*?>)', source)[0]
|
||||||
|
value = re.findall('\[default: (.*)\]', source, flags=re.I)
|
||||||
|
return class_(name, value[0] if value else None)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(Argument):
|
||||||
|
|
||||||
|
def __init__(self, name, value=False):
|
||||||
|
self.name, self.value = name, value
|
||||||
|
|
||||||
|
def single_match(self, left):
|
||||||
|
for n, pattern in enumerate(left):
|
||||||
|
if type(pattern) is Argument:
|
||||||
|
if pattern.value == self.name:
|
||||||
|
return n, Command(self.name, True)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
class Option(LeafPattern):
|
||||||
|
|
||||||
|
def __init__(self, short=None, long=None, argcount=0, value=False):
|
||||||
|
assert argcount in (0, 1)
|
||||||
|
self.short, self.long, self.argcount = short, long, argcount
|
||||||
|
self.value = None if value is False and argcount else value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse(class_, option_description):
|
||||||
|
short, long, argcount, value = None, None, 0, False
|
||||||
|
options, _, description = option_description.strip().partition(' ')
|
||||||
|
options = options.replace(',', ' ').replace('=', ' ')
|
||||||
|
for s in options.split():
|
||||||
|
if s.startswith('--'):
|
||||||
|
long = s
|
||||||
|
elif s.startswith('-'):
|
||||||
|
short = s
|
||||||
|
else:
|
||||||
|
argcount = 1
|
||||||
|
if argcount:
|
||||||
|
matched = re.findall('\[default: (.*)\]', description, flags=re.I)
|
||||||
|
value = matched[0] if matched else None
|
||||||
|
return class_(short, long, argcount, value)
|
||||||
|
|
||||||
|
def single_match(self, left):
|
||||||
|
for n, pattern in enumerate(left):
|
||||||
|
if self.name == pattern.name:
|
||||||
|
return n, pattern
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.long or self.short
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
|
||||||
|
self.argcount, self.value)
|
||||||
|
|
||||||
|
|
||||||
|
class Required(BranchPattern):
|
||||||
|
|
||||||
|
def match(self, left, collected=None):
|
||||||
|
collected = [] if collected is None else collected
|
||||||
|
l = left
|
||||||
|
c = collected
|
||||||
|
for pattern in self.children:
|
||||||
|
matched, l, c = pattern.match(l, c)
|
||||||
|
if not matched:
|
||||||
|
return False, left, collected
|
||||||
|
return True, l, c
|
||||||
|
|
||||||
|
|
||||||
|
class Optional(BranchPattern):
|
||||||
|
|
||||||
|
def match(self, left, collected=None):
|
||||||
|
collected = [] if collected is None else collected
|
||||||
|
for pattern in self.children:
|
||||||
|
m, left, collected = pattern.match(left, collected)
|
||||||
|
return True, left, collected
|
||||||
|
|
||||||
|
|
||||||
|
class OptionsShortcut(Optional):
|
||||||
|
|
||||||
|
"""Marker/placeholder for [options] shortcut."""
|
||||||
|
|
||||||
|
|
||||||
|
class OneOrMore(BranchPattern):
|
||||||
|
|
||||||
|
def match(self, left, collected=None):
|
||||||
|
assert len(self.children) == 1
|
||||||
|
collected = [] if collected is None else collected
|
||||||
|
l = left
|
||||||
|
c = collected
|
||||||
|
l_ = None
|
||||||
|
matched = True
|
||||||
|
times = 0
|
||||||
|
while matched:
|
||||||
|
# could it be that something didn't match but changed l or c?
|
||||||
|
matched, l, c = self.children[0].match(l, c)
|
||||||
|
times += 1 if matched else 0
|
||||||
|
if l_ == l:
|
||||||
|
break
|
||||||
|
l_ = l
|
||||||
|
if times >= 1:
|
||||||
|
return True, l, c
|
||||||
|
return False, left, collected
|
||||||
|
|
||||||
|
|
||||||
|
class Either(BranchPattern):
|
||||||
|
|
||||||
|
def match(self, left, collected=None):
|
||||||
|
collected = [] if collected is None else collected
|
||||||
|
outcomes = []
|
||||||
|
for pattern in self.children:
|
||||||
|
matched, _, _ = outcome = pattern.match(left, collected)
|
||||||
|
if matched:
|
||||||
|
outcomes.append(outcome)
|
||||||
|
if outcomes:
|
||||||
|
return min(outcomes, key=lambda outcome: len(outcome[1]))
|
||||||
|
return False, left, collected
|
||||||
|
|
||||||
|
|
||||||
|
class Tokens(list):
|
||||||
|
|
||||||
|
def __init__(self, source, error=DocoptExit):
|
||||||
|
self += source.split() if hasattr(source, 'split') else source
|
||||||
|
self.error = error
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_pattern(source):
|
||||||
|
source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source)
|
||||||
|
source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s]
|
||||||
|
return Tokens(source, error=DocoptLanguageError)
|
||||||
|
|
||||||
|
def move(self):
|
||||||
|
return self.pop(0) if len(self) else None
|
||||||
|
|
||||||
|
def current(self):
|
||||||
|
return self[0] if len(self) else None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_long(tokens, options):
|
||||||
|
"""long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
|
||||||
|
long, eq, value = tokens.move().partition('=')
|
||||||
|
assert long.startswith('--')
|
||||||
|
value = None if eq == value == '' else value
|
||||||
|
similar = [o for o in options if o.long == long]
|
||||||
|
if tokens.error is DocoptExit and similar == []: # if no exact match
|
||||||
|
similar = [o for o in options if o.long and o.long.startswith(long)]
|
||||||
|
if len(similar) > 1: # might be simply specified ambiguously 2+ times?
|
||||||
|
raise tokens.error('%s is not a unique prefix: %s?' %
|
||||||
|
(long, ', '.join(o.long for o in similar)))
|
||||||
|
elif len(similar) < 1:
|
||||||
|
argcount = 1 if eq == '=' else 0
|
||||||
|
o = Option(None, long, argcount)
|
||||||
|
options.append(o)
|
||||||
|
if tokens.error is DocoptExit:
|
||||||
|
o = Option(None, long, argcount, value if argcount else True)
|
||||||
|
else:
|
||||||
|
o = Option(similar[0].short, similar[0].long,
|
||||||
|
similar[0].argcount, similar[0].value)
|
||||||
|
if o.argcount == 0:
|
||||||
|
if value is not None:
|
||||||
|
raise tokens.error('%s must not have an argument' % o.long)
|
||||||
|
else:
|
||||||
|
if value is None:
|
||||||
|
if tokens.current() in [None, '--']:
|
||||||
|
raise tokens.error('%s requires argument' % o.long)
|
||||||
|
value = tokens.move()
|
||||||
|
if tokens.error is DocoptExit:
|
||||||
|
o.value = value if value is not None else True
|
||||||
|
return [o]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_shorts(tokens, options):
|
||||||
|
"""shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
|
||||||
|
token = tokens.move()
|
||||||
|
assert token.startswith('-') and not token.startswith('--')
|
||||||
|
left = token.lstrip('-')
|
||||||
|
parsed = []
|
||||||
|
while left != '':
|
||||||
|
short, left = '-' + left[0], left[1:]
|
||||||
|
similar = [o for o in options if o.short == short]
|
||||||
|
if len(similar) > 1:
|
||||||
|
raise tokens.error('%s is specified ambiguously %d times' %
|
||||||
|
(short, len(similar)))
|
||||||
|
elif len(similar) < 1:
|
||||||
|
o = Option(short, None, 0)
|
||||||
|
options.append(o)
|
||||||
|
if tokens.error is DocoptExit:
|
||||||
|
o = Option(short, None, 0, True)
|
||||||
|
else: # why copying is necessary here?
|
||||||
|
o = Option(short, similar[0].long,
|
||||||
|
similar[0].argcount, similar[0].value)
|
||||||
|
value = None
|
||||||
|
if o.argcount != 0:
|
||||||
|
if left == '':
|
||||||
|
if tokens.current() in [None, '--']:
|
||||||
|
raise tokens.error('%s requires argument' % short)
|
||||||
|
value = tokens.move()
|
||||||
|
else:
|
||||||
|
value = left
|
||||||
|
left = ''
|
||||||
|
if tokens.error is DocoptExit:
|
||||||
|
o.value = value if value is not None else True
|
||||||
|
parsed.append(o)
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
|
def parse_pattern(source, options):
|
||||||
|
tokens = Tokens.from_pattern(source)
|
||||||
|
result = parse_expr(tokens, options)
|
||||||
|
if tokens.current() is not None:
|
||||||
|
raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
|
||||||
|
return Required(*result)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_expr(tokens, options):
|
||||||
|
"""expr ::= seq ( '|' seq )* ;"""
|
||||||
|
seq = parse_seq(tokens, options)
|
||||||
|
if tokens.current() != '|':
|
||||||
|
return seq
|
||||||
|
result = [Required(*seq)] if len(seq) > 1 else seq
|
||||||
|
while tokens.current() == '|':
|
||||||
|
tokens.move()
|
||||||
|
seq = parse_seq(tokens, options)
|
||||||
|
result += [Required(*seq)] if len(seq) > 1 else seq
|
||||||
|
return [Either(*result)] if len(result) > 1 else result
|
||||||
|
|
||||||
|
|
||||||
|
def parse_seq(tokens, options):
|
||||||
|
"""seq ::= ( atom [ '...' ] )* ;"""
|
||||||
|
result = []
|
||||||
|
while tokens.current() not in [None, ']', ')', '|']:
|
||||||
|
atom = parse_atom(tokens, options)
|
||||||
|
if tokens.current() == '...':
|
||||||
|
atom = [OneOrMore(*atom)]
|
||||||
|
tokens.move()
|
||||||
|
result += atom
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def parse_atom(tokens, options):
|
||||||
|
"""atom ::= '(' expr ')' | '[' expr ']' | 'options'
|
||||||
|
| long | shorts | argument | command ;
|
||||||
|
"""
|
||||||
|
token = tokens.current()
|
||||||
|
result = []
|
||||||
|
if token in '([':
|
||||||
|
tokens.move()
|
||||||
|
matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
|
||||||
|
result = pattern(*parse_expr(tokens, options))
|
||||||
|
if tokens.move() != matching:
|
||||||
|
raise tokens.error("unmatched '%s'" % token)
|
||||||
|
return [result]
|
||||||
|
elif token == 'options':
|
||||||
|
tokens.move()
|
||||||
|
return [OptionsShortcut()]
|
||||||
|
elif token.startswith('--') and token != '--':
|
||||||
|
return parse_long(tokens, options)
|
||||||
|
elif token.startswith('-') and token not in ('-', '--'):
|
||||||
|
return parse_shorts(tokens, options)
|
||||||
|
elif token.startswith('<') and token.endswith('>') or token.isupper():
|
||||||
|
return [Argument(tokens.move())]
|
||||||
|
else:
|
||||||
|
return [Command(tokens.move())]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_argv(tokens, options, options_first=False):
|
||||||
|
"""Parse command-line argument vector.
|
||||||
|
|
||||||
|
If options_first:
|
||||||
|
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
|
||||||
|
else:
|
||||||
|
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
|
||||||
|
|
||||||
|
"""
|
||||||
|
parsed = []
|
||||||
|
while tokens.current() is not None:
|
||||||
|
if tokens.current() == '--':
|
||||||
|
return parsed + [Argument(None, v) for v in tokens]
|
||||||
|
elif tokens.current().startswith('--'):
|
||||||
|
parsed += parse_long(tokens, options)
|
||||||
|
elif tokens.current().startswith('-') and tokens.current() != '-':
|
||||||
|
parsed += parse_shorts(tokens, options)
|
||||||
|
elif options_first:
|
||||||
|
return parsed + [Argument(None, v) for v in tokens]
|
||||||
|
else:
|
||||||
|
parsed.append(Argument(None, tokens.move()))
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
|
def parse_defaults(doc):
|
||||||
|
defaults = []
|
||||||
|
for s in parse_section('options:', doc):
|
||||||
|
# FIXME corner case "bla: options: --foo"
|
||||||
|
_, _, s = s.partition(':') # get rid of "options:"
|
||||||
|
split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:]
|
||||||
|
split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
|
||||||
|
options = [Option.parse(s) for s in split if s.startswith('-')]
|
||||||
|
defaults += options
|
||||||
|
return defaults
|
||||||
|
|
||||||
|
|
||||||
|
def parse_section(name, source):
|
||||||
|
pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
|
||||||
|
re.IGNORECASE | re.MULTILINE)
|
||||||
|
return [s.strip() for s in pattern.findall(source)]
|
||||||
|
|
||||||
|
|
||||||
|
def formal_usage(section):
|
||||||
|
_, _, section = section.partition(':') # drop "usage:"
|
||||||
|
pu = section.split()
|
||||||
|
return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
|
||||||
|
|
||||||
|
|
||||||
|
def extras(help, version, options, doc):
|
||||||
|
if help and any((o.name in ('-h', '--help')) and o.value for o in options):
|
||||||
|
print(doc.strip("\n"))
|
||||||
|
sys.exit()
|
||||||
|
if version and any(o.name == '--version' and o.value for o in options):
|
||||||
|
print(version)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
class Dict(dict):
|
||||||
|
def __repr__(self):
|
||||||
|
return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
|
||||||
|
|
||||||
|
|
||||||
|
def docopt(doc, argv=None, help=True, version=None, options_first=False):
|
||||||
|
"""Parse `argv` based on command-line interface described in `doc`.
|
||||||
|
|
||||||
|
`docopt` creates your command-line interface based on its
|
||||||
|
description that you pass as `doc`. Such description can contain
|
||||||
|
--options, <positional-argument>, commands, which could be
|
||||||
|
[optional], (required), (mutually | exclusive) or repeated...
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
doc : str
|
||||||
|
Description of your command-line interface.
|
||||||
|
argv : list of str, optional
|
||||||
|
Argument vector to be parsed. sys.argv[1:] is used if not
|
||||||
|
provided.
|
||||||
|
help : bool (default: True)
|
||||||
|
Set to False to disable automatic help on -h or --help
|
||||||
|
options.
|
||||||
|
version : any object
|
||||||
|
If passed, the object will be printed if --version is in
|
||||||
|
`argv`.
|
||||||
|
options_first : bool (default: False)
|
||||||
|
Set to True to require options precede positional arguments,
|
||||||
|
i.e. to forbid options and positional arguments intermix.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
args : dict
|
||||||
|
A dictionary, where keys are names of command-line elements
|
||||||
|
such as e.g. "--verbose" and "<path>", and values are the
|
||||||
|
parsed values of those elements.
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
>>> from docopt import docopt
|
||||||
|
>>> doc = '''
|
||||||
|
... Usage:
|
||||||
|
... my_program tcp <host> <port> [--timeout=<seconds>]
|
||||||
|
... my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
|
||||||
|
... my_program (-h | --help | --version)
|
||||||
|
...
|
||||||
|
... Options:
|
||||||
|
... -h, --help Show this screen and exit.
|
||||||
|
... --baud=<n> Baudrate [default: 9600]
|
||||||
|
... '''
|
||||||
|
>>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
|
||||||
|
>>> docopt(doc, argv)
|
||||||
|
{'--baud': '9600',
|
||||||
|
'--help': False,
|
||||||
|
'--timeout': '30',
|
||||||
|
'--version': False,
|
||||||
|
'<host>': '127.0.0.1',
|
||||||
|
'<port>': '80',
|
||||||
|
'serial': False,
|
||||||
|
'tcp': True}
|
||||||
|
|
||||||
|
See also
|
||||||
|
--------
|
||||||
|
* For video introduction see http://docopt.org
|
||||||
|
* Full documentation is available in README.rst as well as online
|
||||||
|
at https://github.com/docopt/docopt#readme
|
||||||
|
|
||||||
|
"""
|
||||||
|
argv = sys.argv[1:] if argv is None else argv
|
||||||
|
|
||||||
|
usage_sections = parse_section('usage:', doc)
|
||||||
|
if len(usage_sections) == 0:
|
||||||
|
raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
|
||||||
|
if len(usage_sections) > 1:
|
||||||
|
raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
|
||||||
|
DocoptExit.usage = usage_sections[0]
|
||||||
|
|
||||||
|
options = parse_defaults(doc)
|
||||||
|
pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
|
||||||
|
# [default] syntax for argument is disabled
|
||||||
|
#for a in pattern.flat(Argument):
|
||||||
|
# same_name = [d for d in arguments if d.name == a.name]
|
||||||
|
# if same_name:
|
||||||
|
# a.value = same_name[0].value
|
||||||
|
argv = parse_argv(Tokens(argv), list(options), options_first)
|
||||||
|
pattern_options = set(pattern.flat(Option))
|
||||||
|
for options_shortcut in pattern.flat(OptionsShortcut):
|
||||||
|
doc_options = parse_defaults(doc)
|
||||||
|
options_shortcut.children = list(set(doc_options) - pattern_options)
|
||||||
|
#if any_options:
|
||||||
|
# options_shortcut.children += [Option(o.short, o.long, o.argcount)
|
||||||
|
# for o in argv if type(o) is Option]
|
||||||
|
extras(help, version, argv, doc)
|
||||||
|
matched, left, collected = pattern.fix().match(argv)
|
||||||
|
if matched and left == []: # better error message if left?
|
||||||
|
return Dict((a.name, a.value) for a in (pattern.flat() + collected))
|
||||||
|
raise DocoptExit()
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Usage:
|
||||||
|
pip-diff (--fresh | --stale) <reqfile1> <reqfile2>
|
||||||
|
pip-diff (-h | --help)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h --help Show this screen.
|
||||||
|
--fresh List newly added packages.
|
||||||
|
--stale List removed packages.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from docopt import docopt
|
||||||
|
from pip.req import parse_requirements
|
||||||
|
|
||||||
|
class Requirements(object):
|
||||||
|
def __init__(self, reqfile=None):
|
||||||
|
super(Requirements, self).__init__()
|
||||||
|
self.path = reqfile
|
||||||
|
self.requirements = []
|
||||||
|
|
||||||
|
if reqfile:
|
||||||
|
self.load(reqfile)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Requirements \'{}\'>'.format(self.path)
|
||||||
|
|
||||||
|
def load(self, reqfile):
|
||||||
|
|
||||||
|
if not os.path.exists(reqfile):
|
||||||
|
raise ValueError('The given requirements file does not exist.')
|
||||||
|
|
||||||
|
for requirement in parse_requirements(reqfile):
|
||||||
|
if requirement.req:
|
||||||
|
self.requirements.append(requirement.req)
|
||||||
|
|
||||||
|
|
||||||
|
def diff(self, requirements, ignore_versions=False):
|
||||||
|
r1 = self
|
||||||
|
r2 = requirements
|
||||||
|
results = {'fresh': [], 'stale': []}
|
||||||
|
|
||||||
|
# Generate fresh packages.
|
||||||
|
other_reqs = (
|
||||||
|
[r.project_name for r in r1.requirements]
|
||||||
|
if ignore_versions else r1.requirements
|
||||||
|
)
|
||||||
|
|
||||||
|
for req in r2.requirements:
|
||||||
|
r = req.project_name if ignore_versions else req
|
||||||
|
|
||||||
|
if r not in other_reqs:
|
||||||
|
results['fresh'].append(req)
|
||||||
|
|
||||||
|
# Generate stale packages.
|
||||||
|
other_reqs = (
|
||||||
|
[r.project_name for r in r2.requirements]
|
||||||
|
if ignore_versions else r2.requirements
|
||||||
|
)
|
||||||
|
|
||||||
|
for req in r1.requirements:
|
||||||
|
r = req.project_name if ignore_versions else req
|
||||||
|
|
||||||
|
if r not in other_reqs:
|
||||||
|
results['stale'].append(req)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def diff(r1, r2, include_fresh=False, include_stale=False):
|
||||||
|
|
||||||
|
include_versions = True if include_stale else False
|
||||||
|
|
||||||
|
try:
|
||||||
|
r1 = Requirements(r1)
|
||||||
|
r2 = Requirements(r2)
|
||||||
|
except ValueError:
|
||||||
|
print 'There was a problem loading the given requirements files.'
|
||||||
|
exit(os.EX_NOINPUT)
|
||||||
|
|
||||||
|
results = r1.diff(r2, ignore_versions=True)
|
||||||
|
|
||||||
|
if include_fresh:
|
||||||
|
for line in results['fresh']:
|
||||||
|
print line.project_name if include_versions else line
|
||||||
|
|
||||||
|
if include_stale:
|
||||||
|
for line in results['stale']:
|
||||||
|
print line.project_name if include_versions else line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = docopt(__doc__, version='pip-diff')
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'r1': args['<reqfile1>'],
|
||||||
|
'r2': args['<reqfile2>'],
|
||||||
|
'include_fresh': args['--fresh'],
|
||||||
|
'include_stale': args['--stale']
|
||||||
|
}
|
||||||
|
|
||||||
|
diff(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Usage:
|
||||||
|
pip-grep [-s] <reqfile> <package>...
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h --help Show this screen.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from docopt import docopt
|
||||||
|
from pip.req import parse_requirements
|
||||||
|
|
||||||
|
class Requirements(object):
|
||||||
|
def __init__(self, reqfile=None):
|
||||||
|
super(Requirements, self).__init__()
|
||||||
|
self.path = reqfile
|
||||||
|
self.requirements = []
|
||||||
|
|
||||||
|
if reqfile:
|
||||||
|
self.load(reqfile)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Requirements \'{}\'>'.format(self.path)
|
||||||
|
|
||||||
|
def load(self, reqfile):
|
||||||
|
|
||||||
|
if not os.path.exists(reqfile):
|
||||||
|
raise ValueError('The given requirements file does not exist.')
|
||||||
|
|
||||||
|
for requirement in parse_requirements(reqfile):
|
||||||
|
self.requirements.append(requirement)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def grep(reqfile, packages, silent=False):
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = Requirements(reqfile)
|
||||||
|
except ValueError:
|
||||||
|
|
||||||
|
if not silent:
|
||||||
|
print 'There was a problem loading the given requirement file.'
|
||||||
|
|
||||||
|
exit(os.EX_NOINPUT)
|
||||||
|
|
||||||
|
for requirement in r.requirements:
|
||||||
|
|
||||||
|
if requirement.req:
|
||||||
|
|
||||||
|
if requirement.req.project_name in packages:
|
||||||
|
|
||||||
|
if not silent:
|
||||||
|
print 'Package {} found!'.format(requirement.req.project_name)
|
||||||
|
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if not silent:
|
||||||
|
print 'Not found.'.format(requirement.req.project_name)
|
||||||
|
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = docopt(__doc__, version='pip-grep')
|
||||||
|
|
||||||
|
kwargs = {'reqfile': args['<reqfile>'], 'packages': args['<package>'], 'silent': args['-s']}
|
||||||
|
|
||||||
|
|
||||||
|
grep(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user