Skip to content

Commit 50bff6f

Browse files
First Commit
1 parent 5d7ac1d commit 50bff6f

File tree

5 files changed

+335
-0
lines changed

5 files changed

+335
-0
lines changed

MIT License.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Timothy C. Quinn <javascriptdude [at] protonmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.MD

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## Python Src Run
2+
Tool for generating and invoking of python sources that does not require installation in python libraries
3+
4+
Supports executing code as user and as root (eg as cron tasks). Tooled to leverage a separate python environment from the systems python, therefore allow userland applications to have flexibility of library installation without conflicting with the base systems python environment; as is best practice.
5+
6+
7+
## Applications
8+
When a project is in alpha state, its often not ready to be packaged in PyPi for the main stream. Secondly, sometimes the process for packaging a python application to make it easy to deploy in production environments can be challenging. This tool offers a bridge to allow tools be be developed and tested without having to deal with packaging and installation by allowing them to be run directly from source.
9+
10+
11+
## Project Install File
12+
Each project that uses this toolset, will have a <mod>_install.sh in its root file similar to the following:
13+
```
14+
#!/bin/bash
15+
# % cd <this directory>
16+
# % . ./pynx_install.sh
17+
. ~/.py_src_run/make_mod_exe.sh "pynx" "/usr/bin" "lib,foo/bar"
18+
```
19+
20+
This above example will deploy an executable called `pynx` to `/usr/bin`, It will also include in PYTHONPATH <project_root>/lib and <project_root>/foo/bar
21+
22+
By deploying to `/usr/bin`, the program can be invoked using sudo, which in the case of `pynx`, su is required as its for managing `nginx` and `wsgi`.
23+
24+
25+
## Files
26+
| Name | Deployed Name | Description |
27+
| py_src_run.sh | run.sh | Backend invocation script. No modification required |
28+
| make_mod_exe.sh | (same) | script for generating executable. No modification required |
29+
| pyinit.sh | (same) | script to set up python environment. Configuration is required |
30+
31+
Files are deployed to ~/.py_src_run/
32+
33+
Python environment used is suggested to be installed via `pyenv` but virtual env's could be used in theory. Virutal env's have not been tested yet as `pyenv` is the developers prefered mechanism for desktops and production server python deployments.
34+
35+
36+
## src directory
37+
This design assumes that the python project has a src directory in the root of the file structure as is recommended by most modern documentation on python project setup.
38+
39+
40+
## Installation
41+
Download the sources
42+
For each of `py_src_run.sh`, `make_mod_exe.sh` and `pyinit.sh` install by either following instructions in header of each file or run the following in a `bash shell`:
43+
```
44+
_P=py_src_run
45+
mkdir ~/.${_P}
46+
cp ./$_P.sh ~/.$_P/run.sh && chmod a+x ~/.$_P/run.sh
47+
_C=make_mod_exe && cp ./$_C.sh ~/.$_P/$_C.sh && chmod a+x ~/.$_P/$_C.sh
48+
_C=pyinit && cp ./$_C.sh ~/.$_P/$_C.sh
49+
```
50+
51+
## Configuration
52+
Besides generating a install script for any project you want to install, you must modify `~/.py_run_src/pyinit.sh`
53+
54+
This file will initialze the python environment
55+
56+

make_mod_exe.sh

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/bin/bash
2+
# .: make_mod_exe.sh :.
3+
# Executable creator script
4+
5+
# Author: Timothy C. Quinn
6+
# Home: https://github.com/JavaScriptDude/py_src_run
7+
8+
# .: Installation :.
9+
# note: install py_src_run.sh first
10+
# % _C=make_mod_exe _D=~/.py_src_run && cp ./${_C}.sh $_D/${_C}.sh && chmod a+x $_D/${_C}.sh
11+
12+
PROJ_ROOT=`pwd`
13+
ERR=""
14+
if [[ "$#" == "" ]]; then
15+
ERR="Invalid args. Expecting <module> <target_bin_dir>"
16+
else
17+
user_is_root () { [ ${EUID:-$(id -u)} -eq 0 ]; }
18+
if (user_is_root) ; then
19+
ERR="Do not run this as root or sudo"
20+
fi
21+
fi
22+
23+
24+
# Module name
25+
if [[ $ERR == "" ]]; then
26+
MOD=${1}
27+
28+
SRCDIR="$PROJ_ROOT/src"
29+
30+
_MOD_CHK=`echo $MOD | sed 's/\s*//g' | sed 's/\\n//g'`
31+
if [[ "$MOD" != "$_MOD_CHK" ]]; then # No spaces etc.
32+
ERR="Module must not have spaces in name. Got: \'$MOD\'"
33+
34+
elif [[ "$MOD" == "" ]]; then # Not empty
35+
ERR="Module variable must not be blank!"
36+
37+
elif [ ! -d "$SRCDIR" ]; then
38+
ERR="src directory not found: \'$SRCDIR\'"
39+
40+
elif [ ! -d "$SRCDIR/$MOD" ]; then # verify pwd and mod is correct
41+
ERR="This script must be run from project root (parent of src)"
42+
43+
fi
44+
fi
45+
46+
47+
# Bin path
48+
if [[ $ERR == "" ]]; then
49+
BINPATH=$2
50+
# remove trailing slash
51+
BINPATH=$(dirname "$BINPATH/x")
52+
# verify path exists
53+
if [ ! -d "$BINPATH" ]; then
54+
ERR="Directory ($BINPATH) does not exist. Please create if needed"
55+
fi
56+
fi
57+
58+
# Check alternate includes
59+
if [[ $ERR == "" ]]; then
60+
ALT_INCL_STR=""
61+
ALTINCL_ALL=$3
62+
63+
if [[ "$ALTINCL_ALL" != "" ]]; then
64+
readarray -d , -t INCL_PATHS<<< "$ALTINCL_ALL"
65+
66+
67+
for ((i=${#INCL_PATHS[@]}-1; i>=0; i--)); do
68+
INCL_PATH=${INCL_PATHS[$i]}
69+
INCL_PATH=`echo $INCL_PATH | sed 's/\s*//g' | sed 's/\\n//g'`
70+
71+
if [[ $ERR == "" ]]; then
72+
# Verify each path
73+
INCL_PATH_FULL=$PROJ_ROOT/$INCL_PATH
74+
if [ ! -d $INCL_PATH_FULL ]; then # verify incl directory exists
75+
ERR="Include directory provided ($INCL_PATH_FULL) does not exist"
76+
else
77+
ALT_INCL_STR="\$PROJ_ROOT/${INCL_PATH}:${ALT_INCL_STR}"
78+
# echo \'$ALT_INCL_STR\'
79+
fi
80+
fi
81+
done
82+
fi
83+
fi
84+
85+
86+
# Verify exe (don't clobber)
87+
if [[ $ERR == "" ]]; then
88+
BINPATH_FULL=$BINPATH/$MOD
89+
if [ -f "$BINPATH_FULL" ]; then # don't clobber
90+
ERR="Module executable $BINPATH_FULL already exists. Please remove first before running"
91+
fi
92+
fi
93+
94+
SUDO=0
95+
write_line () {
96+
if [ $SUDO -eq "1" ]; then
97+
echo $1 | sudo tee -a "$BINPATH_FULL" >/dev/null
98+
else
99+
echo $1 | tee -a "$BINPATH_FULL" >/dev/null
100+
fi
101+
}
102+
103+
# Create executable
104+
if [[ $ERR == "" ]]; then
105+
106+
# touch file
107+
if [ ! -w "$BINPATH" ]; then
108+
SUDO=1
109+
echo "About to create script $BINPATH_FULL. May need pwd..."
110+
sudo touch "$BINPATH_FULL"
111+
else
112+
touch "$BINPATH_FULL"
113+
fi
114+
115+
write_line "PROJ_ROOT=$PROJ_ROOT"
116+
117+
# PYTHONPATH (if applicable)
118+
if [[ "$ALT_INCL_STR" != "" ]]; then
119+
write_line "export PYTHONPATH=$ALT_INCL_STR\$PYTHONPATH"
120+
fi
121+
122+
# run.sh
123+
write_line "$HOME/.py_src_run/run.sh \"\$PROJ_ROOT/src\" $MOD \"\$@\""
124+
125+
# chmod +x
126+
if [ $SUDO -eq "1" ]; then
127+
sudo chmod a+x "$BINPATH_FULL"
128+
else
129+
chmod a+x "$BINPATH_FULL"
130+
fi
131+
132+
echo "Executable created: $BINPATH_FULL"
133+
134+
else
135+
echo "make_mod_exe.sh failed - $ERR"
136+
echo " . CLI Args: \'$@\'"
137+
fi

py_src_run.sh

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/bin/bash
2+
# .: py_src_run.sh (run.sh) :.
3+
# Main backend invokation script
4+
# Author: Timothy C. Quinn
5+
# Home: https://github.com/JavaScriptDude/py_src_run
6+
7+
# .: Installation :.
8+
#% mkdir ~/.py_src_run
9+
#% _C=py_src_run _D=~/.${_C} && cp ./${_C}.sh $_D/run.sh && chmod a+x $_D/run.sh
10+
11+
PYINITERR=""
12+
if [ "$#" -lt "2" ]; then
13+
PYINITERR="Invalid args. Expecting <scr_path> <module> [<program_arg1>, ...]"
14+
fi
15+
16+
# Parse Module Src Path
17+
if [[ $PYINITERR == "" ]]; then
18+
MSPATH="$1"
19+
if [ ! -d "$MSPATH" ]; then
20+
PYINITERR="Module path provided to py_run_as_root does not exist: ${MSPATH}"
21+
fi
22+
fi
23+
24+
# Parse Module
25+
if [[ $PYINITERR == "" ]]; then
26+
MOD="$2"
27+
if [ ! -d "$MSPATH/$MOD" ]; then
28+
PYINITERR="Module provided to py_run_as_root does not exist: $MSPATH/$MOD"
29+
fi
30+
fi
31+
32+
# Get HOME and pyinit.sh location
33+
if [[ $PYINITERR == "" ]]; then
34+
SCRP="$0"
35+
SCR_FILE=`basename $SCRP`
36+
PYRUNDIR=`dirname $SCRP`
37+
38+
readarray -d / -t a<<< "$PYRUNDIR"
39+
40+
PERR=0
41+
PERRMSG=""
42+
if [ "${#a[@]}" != "4" ]; then
43+
PERR=1
44+
elif [[ "${a[0]}" != "" ]]; then
45+
PERR=1
46+
elif [[ "${a[1]}" != "home" ]]; then
47+
PERR=1
48+
else
49+
export HOME=/home/${a[2]}
50+
LASTP=${a[3]}
51+
if [[ "${LASTP:0:11}" != ".py_src_run" ]]; then
52+
PERR=1
53+
else
54+
# Verify that pyinit.sh exists
55+
if [ ! -f "$PYRUNDIR/pyinit.sh" ]; then
56+
PERR=1
57+
PERRMSG="pyinit init script is missing: '$PYRUNDIR/pyinit.sh'"
58+
fi
59+
fi
60+
fi
61+
62+
63+
64+
if [ $PERR == 1 ]; then
65+
if [[ "$PERRMSG" != "" ]]; then
66+
PYINITERR=$PERRMSG
67+
else
68+
PYINITERR="Invalid path for py_src_run.sh. Expecting /home/<user>/.py_src_run/run.sh but got ${SCR_DIR}"
69+
fi
70+
fi
71+
72+
fi
73+
74+
if [[ $PYINITERR == "" ]]; then
75+
# source pyinit script
76+
source $PYRUNDIR/pyinit.sh
77+
fi
78+
79+
if [[ $PYINITERR == "" ]]; then
80+
# Add module path to PYTHONPATH
81+
export PYTHONPATH=${MSPATH}:${PYTHONPATH}
82+
83+
# strip first two cli args
84+
shift 2
85+
86+
if [ 0 -eq 1 ]; then # debug
87+
echo FOO=\'$FOO\'
88+
echo MSPATH=\'$MSPATH\'
89+
echo MOD=\'$MOD\'
90+
echo MOD Args=\'$@\'
91+
echo HOME=\'$HOME\'
92+
echo PATH=\'$PATH\'
93+
echo PYTHONPATH=\'$PYTHONPATH\'
94+
echo PY_EXE=`python -c "import sys; print(sys.executable);"`
95+
fi
96+
97+
# Execute
98+
python -m $MOD "$@"
99+
100+
else
101+
echo "py_run_from_src.sh failed - $PYINITERR"
102+
echo " . CLI Args: '$@'"
103+
104+
fi

pyinit.sh

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/bash
2+
# .: pyinit.sh :.
3+
# Python environment initialization for py_src_run invocations
4+
5+
# Author: Timothy C. Quinn
6+
# Home: https://github.com/JavaScriptDude/py_src_run
7+
8+
# .: Installation :.
9+
# note: install py_src_run.sh first
10+
#% _C=pyinit _D=~/.py_src_run && cp ./${_C}.sh $_D/${_C}.sh
11+
12+
13+
# Modify as required
14+
15+
# Example for pyenv
16+
export _PYVER=3.7.9
17+
export PATH=${HOME}/.pyenv/versions/${_PYVER}/bin/:${PATH}

0 commit comments

Comments
 (0)