@@ -9,68 +9,84 @@ USAGE=$(
9
9
Configure a development environment for this repository.
10
10
11
11
It does the following:
12
+ - Allows the user to specify the Python version to use for the virtual environment.
13
+ - Allows the user to specify a name for the virtual environment.
12
14
- Verifies pyenv and pyenv-virtualenv are installed.
13
- - Creates a Python virtual environment.
15
+ - Creates the Python virtual environment.
14
16
- Configures the activation of the virtual enviroment for the repo directory.
15
17
- Installs the requirements needed for development.
16
18
- Installs git pre-commit hooks.
17
- - Configures git upstream remote "lineage" repositories.
19
+ - Configures git remotes for upstream "lineage" repositories.
18
20
19
21
Usage:
20
- setup-env [options ] [virt_env_name ]
22
+ setup-env [--venv-name venv_name ] [--python-version python_version ]
21
23
setup-env (-h | --help)
22
24
23
25
Options:
24
- -f --force Delete virtual enviroment if it already exists.
25
- -h --help Show this message.
26
- -i --install-hooks Install hook environments for all environments in the
27
- pre-commit config file.
26
+ -f | --force Delete virtual enviroment if it already exists.
27
+ -h | --help Show this message.
28
+ -i | --install-hooks Install hook environments for all environments in the
29
+ pre-commit config file.
30
+ -l | --list-versions List available Python versions and select one interactively.
31
+ -v | --venv-name Specify the name of the virtual environment.
32
+ -p | --python-version Specify the Python version for the virtual environment.
28
33
29
34
END_OF_LINE
30
35
)
31
36
37
+ # Display pyenv's installed Python versions
38
+ python_versions () {
39
+ pyenv versions --bare --skip-aliases --skip-envs
40
+ }
41
+
32
42
# Flag to force deletion and creation of virtual environment
33
43
FORCE=0
34
44
35
- # Positional parameters
36
- PARAMS=" "
45
+ # Initialize the other flags
46
+ INSTALL_HOOKS=0
47
+ LIST_VERSIONS=0
48
+ PYTHON_VERSION=" "
49
+ VENV_NAME=" "
37
50
38
- # Parse command line arguments
39
- while (( "$# ")) ; do
40
- case " $1 " in
41
- -f | --force)
42
- FORCE=1
43
- shift
44
- ;;
45
- -h | --help)
46
- echo " ${USAGE} "
47
- exit 0
48
- ;;
49
- -i | --install-hooks)
50
- INSTALL_HOOKS=1
51
- shift
52
- ;;
53
- -* ) # unsupported flags
54
- echo " Error: Unsupported flag $1 " >&2
55
- exit 1
56
- ;;
57
- * ) # preserve positional arguments
58
- PARAMS=" $PARAMS $1 "
59
- shift
60
- ;;
61
- esac
62
- done
51
+ # Define long options
52
+ LONGOPTS=" force,help,install-hooks,list-versions,python-version:,venv-name:"
53
+
54
+ # Define short options for getopt
55
+ SHORTOPTS=" fhilp:v:"
56
+
57
+ # Check for GNU getopt by matching a specific pattern ("getopt from util-linux")
58
+ # in its version output. This approach presumes the output format remains stable.
59
+ # Be aware that format changes could invalidate this check.
60
+ if [[ $( getopt --version 2> /dev/null) != * " getopt from util-linux" * ]]; then
61
+ cat << 'END_OF_LINE '
62
+
63
+ Please note, this script requires GNU getopt due to its enhanced
64
+ functionality and compatibility with certain script features that
65
+ are not supported by the POSIX getopt found in some systems, particularly
66
+ those with a non-GNU version of getopt. This distinction is crucial
67
+ as a system might have a non-GNU version of getopt installed by default,
68
+ which could lead to unexpected behavior.
63
69
64
- # set positional arguments in their proper place
65
- eval set -- " $PARAMS "
70
+ On macOS, we recommend installing brew (https://brew.sh/). Then installation
71
+ is as simple as `brew install gnu-getopt` and adding this to your
72
+ profile:
73
+
74
+ export PATH="$(brew --prefix)/opt/gnu-getopt/bin:$PATH"
75
+
76
+ GNU getopt must be explicitly added to the PATH since it
77
+ is keg-only (https://docs.brew.sh/FAQ#what-does-keg-only-mean).
78
+
79
+ END_OF_LINE
80
+ exit 1
81
+ fi
66
82
67
83
# Check to see if pyenv is installed
68
84
if [ -z " $( command -v pyenv) " ] || { [ -z " $( command -v pyenv-virtualenv) " ] && [ ! -f " $( pyenv root) /plugins/pyenv-virtualenv/bin/pyenv-virtualenv" ]; }; then
69
85
echo " pyenv and pyenv-virtualenv are required."
70
86
if [[ " $OSTYPE " == " darwin" * ]]; then
71
87
cat << 'END_OF_LINE '
72
88
73
- On the Mac , we recommend installing brew, https://brew.sh/. Then installation
89
+ On macOS , we recommend installing brew, https://brew.sh/. Then installation
74
90
is as simple as `brew install pyenv pyenv-virtualenv` and adding this to your
75
91
profile:
76
92
@@ -81,7 +97,7 @@ END_OF_LINE
81
97
82
98
fi
83
99
cat << 'END_OF_LINE '
84
- For Linux, Windows Subsystem for Linux (WSL), or on the Mac (if you don't want
100
+ For Linux, Windows Subsystem for Linux (WSL), or macOS (if you don't want
85
101
to use "brew") you can use https://github.com/pyenv/pyenv-installer to install
86
102
the necessary tools. Before running this ensure that you have installed the
87
103
prerequisites for your platform according to the pyenv wiki page,
@@ -100,16 +116,88 @@ END_OF_LINE
100
116
exit 1
101
117
fi
102
118
103
- set +o nounset
119
+ # Use GNU getopt to parse options
120
+ if ! PARSED=$( getopt --options $SHORTOPTS --longoptions $LONGOPTS --name " $0 " -- " $@ " ) ; then
121
+ echo " Error parsing options"
122
+ exit 1
123
+ fi
124
+ eval set -- " $PARSED "
125
+
126
+ while true ; do
127
+ case " $1 " in
128
+ -f | --force)
129
+ FORCE=1
130
+ shift
131
+ ;;
132
+ -h | --help)
133
+ echo " $USAGE "
134
+ exit 0
135
+ ;;
136
+ -i | --install-hooks)
137
+ INSTALL_HOOKS=1
138
+ shift
139
+ ;;
140
+ -l | --list-versions)
141
+ LIST_VERSIONS=1
142
+ shift
143
+ ;;
144
+ -p | --python-version)
145
+ PYTHON_VERSION=" $2 "
146
+ shift 2
147
+ # Check the Python versions being passed in.
148
+ if [ -n " ${PYTHON_VERSION+x} " ]; then
149
+ if python_versions | grep -E " ^${PYTHON_VERSION} $" > /dev/null; then
150
+ echo Using Python version " $PYTHON_VERSION "
151
+ else
152
+ echo Error: Python version " $PYTHON_VERSION " is not installed.
153
+ echo Installed Python versions are:
154
+ python_versions
155
+ exit 1
156
+ fi
157
+ fi
158
+ ;;
159
+ -v | --venv-name)
160
+ VENV_NAME=" $2 "
161
+ shift 2
162
+ ;;
163
+ --)
164
+ shift
165
+ break
166
+ ;;
167
+ * )
168
+ # Unreachable due to GNU getopt handling all options
169
+ echo " Programming error"
170
+ exit 64
171
+ ;;
172
+ esac
173
+ done
174
+
104
175
# Determine the virtual environment name
105
- if [ " $1 " ]; then
176
+ if [ -n " $VENV_NAME " ]; then
106
177
# Use the user-provided environment name
107
- env_name=$1
178
+ env_name=" $VENV_NAME "
108
179
else
109
180
# Set the environment name to the last part of the working directory.
110
181
env_name=${PWD##*/ }
111
182
fi
112
- set -o nounset
183
+
184
+ # List Python versions and select one interactively.
185
+ if [ $LIST_VERSIONS -ne 0 ]; then
186
+ echo Available Python versions:
187
+ python_versions
188
+ # Read the user's desired Python version.
189
+ # -r: treat backslashes as literal, -p: display prompt before input.
190
+ read -r -p " Enter the desired Python version: " PYTHON_VERSION
191
+ # Check the Python versions being passed in.
192
+ if [ -n " ${PYTHON_VERSION+x} " ]; then
193
+ if python_versions | grep -E " ^${PYTHON_VERSION} $" > /dev/null; then
194
+ echo Using Python version " $PYTHON_VERSION "
195
+ else
196
+ echo Error: Python version " $PYTHON_VERSION " is not installed.
197
+ exit 1
198
+ fi
199
+ fi
200
+ fi
113
201
114
202
# Remove any lingering local configuration.
115
203
if [ $FORCE -ne 0 ]; then
@@ -118,7 +206,7 @@ if [ $FORCE -ne 0 ]; then
118
206
elif [[ -f .python-version ]]; then
119
207
cat << 'END_OF_LINE '
120
208
An existing .python-version file was found. Either remove this file yourself
121
- or re-run with --force option to have it deleted along with the associated
209
+ or re-run with the --force option to have it deleted along with the associated
122
210
virtual environment.
123
211
124
212
rm .python-version
@@ -128,10 +216,18 @@ END_OF_LINE
128
216
fi
129
217
130
218
# Create a new virtual environment for this project
131
- if ! pyenv virtualenv " ${env_name} " ; then
219
+ #
220
+ # If $PYTHON_VERSION is undefined then the current pyenv Python version will be used.
221
+ #
222
+ # We can't quote ${PYTHON_VERSION:=} below since if the variable is
223
+ # undefined then we want nothing to appear; this is the reason for the
224
+ # "shellcheck disable" line below.
225
+ #
226
+ # shellcheck disable=SC2086
227
+ if ! pyenv virtualenv ${PYTHON_VERSION:= } " ${env_name} " ; then
132
228
cat << END_OF_LINE
133
229
An existing virtual environment named $env_name was found. Either delete this
134
- environment yourself or re-run with --force option to have it deleted.
230
+ environment yourself or re-run with the --force option to have it deleted.
135
231
136
232
pyenv virtualenv-delete ${env_name}
137
233
0 commit comments