Merge pull request #509 from coreemu/enhancement/local-install-option
Enhancement/local install option
This commit is contained in:
commit
5fd51e6b2f
4 changed files with 139 additions and 65 deletions
|
@ -6,7 +6,14 @@ authors = ["Boeing Research and Technology"]
|
||||||
license = "BSD-2-Clause"
|
license = "BSD-2-Clause"
|
||||||
repository = "https://github.com/coreemu/core"
|
repository = "https://github.com/coreemu/core"
|
||||||
documentation = "https://coreemu.github.io/core/"
|
documentation = "https://coreemu.github.io/core/"
|
||||||
include = ["core/gui/data/**/*", "core/configservices/*/templates"]
|
include = [
|
||||||
|
"core/api/grpc/*",
|
||||||
|
"core/configservices/*/templates",
|
||||||
|
"core/constants.py",
|
||||||
|
"core/gui/data/**/*",
|
||||||
|
]
|
||||||
|
exclude = ["core/constants.py.in"]
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.6"
|
python = "^3.6"
|
||||||
|
|
|
@ -74,11 +74,16 @@ sudo apt remove core
|
||||||
|
|
||||||
## Automated Installation
|
## Automated Installation
|
||||||
|
|
||||||
The automated install will install the various tools needed to help automate
|
> **NOTE:** installing globally can have issues with dependency conflicts etc
|
||||||
the CORE installation (python3, pip, pipx, invoke, poetry). The script will
|
|
||||||
also automatically clone, build, and install the latest version of OSPF MDR.
|
The automated install will install do the following:
|
||||||
Finally it will install CORE scripts and a systemd service, which have
|
* install base tools needed for installation
|
||||||
been modified to use the installed poetry created virtual environment.
|
* python3, pip, pipx, invoke, poetry
|
||||||
|
* installs system dependencies for building core
|
||||||
|
* installs latest version of [OPSF MDR](https://github.com/USNavalResearchLaboratory/ospf-mdr)
|
||||||
|
* installs core into poetry managed virtual environment or locally, if flag is passed
|
||||||
|
* installs scripts pointing to python interpreter being used
|
||||||
|
* installs systemd service, disabled by default
|
||||||
|
|
||||||
After installation has completed you should be able to run the various
|
After installation has completed you should be able to run the various
|
||||||
CORE scripts for running core.
|
CORE scripts for running core.
|
||||||
|
@ -92,10 +97,11 @@ git clone https://github.com/coreemu/core.git
|
||||||
cd core
|
cd core
|
||||||
|
|
||||||
# run install script
|
# run install script
|
||||||
# script usage: install.sh [-d] [-v]
|
# script usage: install.sh [-v] [-d] [-l] [-p <prefix>]
|
||||||
#
|
#
|
||||||
# -v enable verbose install
|
# -v enable verbose install
|
||||||
# -d enable developer install
|
# -d enable developer install
|
||||||
|
# -l enable local install, not compatible with developer install
|
||||||
# -p install prefix, defaults to /usr/local
|
# -p install prefix, defaults to /usr/local
|
||||||
./install.sh
|
./install.sh
|
||||||
```
|
```
|
||||||
|
@ -117,16 +123,17 @@ After the installation complete it will have installed the following scripts.
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| core-cleanup | tool to help removed lingering core created containers, bridges, directories |
|
||||||
|
| core-cli | tool to query, open xml files, and send commands using gRPC |
|
||||||
| core-daemon | runs the backed core server providing TLV and gRPC APIs |
|
| core-daemon | runs the backed core server providing TLV and gRPC APIs |
|
||||||
| core-gui | runs the legacy tcl/tk based GUI |
|
| core-gui | runs the legacy tcl/tk based GUI |
|
||||||
| core-pygui | runs the new python/tk based GUI |
|
|
||||||
| core-cleanup | tool to help removed lingering core created containers, bridges, directories |
|
|
||||||
| core-imn-to-xml | tool to help automate converting a .imn file to .xml format |
|
| core-imn-to-xml | tool to help automate converting a .imn file to .xml format |
|
||||||
|
| core-manage | tool to add, remove, or check for services, models, and node types |
|
||||||
|
| core-pygui | runs the new python/tk based GUI |
|
||||||
|
| core-python | provides a convenience for running the core python virtual environment |
|
||||||
| core-route-monitor | tool to help monitor traffic across nodes and feed that to SDT |
|
| core-route-monitor | tool to help monitor traffic across nodes and feed that to SDT |
|
||||||
| core-service-update | tool to update automate modifying a legacy service to match current naming |
|
| core-service-update | tool to update automate modifying a legacy service to match current naming |
|
||||||
| coresendmsg | tool to send TLV API commands from command line |
|
| coresendmsg | tool to send TLV API commands from command line |
|
||||||
| core-cli | tool to query, open xml files, and send commands using gRPC |
|
|
||||||
| core-manage | tool to add, remove, or check for services, models, and node types |
|
|
||||||
|
|
||||||
## Running User Scripts
|
## Running User Scripts
|
||||||
|
|
||||||
|
@ -142,28 +149,57 @@ environment interpreter or to run a script within it.
|
||||||
core-python <script>
|
core-python <script>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Manually Install EMANE
|
If CORE was installed locally, then you can run scripts using the default python3
|
||||||
|
interpreter.
|
||||||
|
|
||||||
EMANE can be installed from deb or RPM packages or from source. See the
|
```shell
|
||||||
[EMANE GitHub](https://github.com/adjacentlink/emane) for full details.
|
python3 <script>
|
||||||
|
```
|
||||||
|
|
||||||
There is an invoke task to help with installing EMANE, but has issues,
|
## Installing EMANE
|
||||||
which attempts to build EMANE from source, but has issue on systems with
|
|
||||||
older protobuf-compilers.
|
> **NOTE:** installng emane for the virtual environment is known to work for 1.21+
|
||||||
|
> **NOTE:** automated install currently targets 1.25
|
||||||
|
|
||||||
|
There is an invoke task to help with installing EMANE, which attempts to
|
||||||
|
build EMANE from source, but has issue on systems with older protobuf-compilers.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
cd <CORE_REPO>
|
cd <CORE_REPO>
|
||||||
|
|
||||||
|
# install to virtual environment
|
||||||
inv install-emane
|
inv install-emane
|
||||||
|
|
||||||
|
# install locally to system python3
|
||||||
|
inv install-emane -l
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, you can
|
Alternatively EMANE can be installed from deb or RPM packages or from source. See the
|
||||||
|
[EMANE GitHub](https://github.com/adjacentlink/emane) for full details.
|
||||||
|
With the caveat that the python bindings need to be installed into CORE's
|
||||||
|
virtualenv, unless installed locally.
|
||||||
|
|
||||||
|
### Installing EMANE Python Bindings for Virtual Environment
|
||||||
|
|
||||||
|
If you need to just install the EMANE python bindings to the CORE virtual
|
||||||
|
environment, since you are installing EMANE itself from pre-built packages.
|
||||||
|
You can run the following
|
||||||
|
|
||||||
|
Leveraging the following wiki:
|
||||||
[build EMANE](https://github.com/adjacentlink/emane/wiki/Build)
|
[build EMANE](https://github.com/adjacentlink/emane/wiki/Build)
|
||||||
from source and install the python
|
|
||||||
bindings into the core virtual environment.
|
|
||||||
|
|
||||||
The following would install the EMANE python bindings after being
|
The following would install the EMANE python bindings after being
|
||||||
successfully built.
|
successfully built.
|
||||||
```shell
|
```shell
|
||||||
|
# clone and build emane python bindings
|
||||||
|
git clone https://github.com/adjacentlink/emane.git
|
||||||
|
cd emane
|
||||||
|
./autogen.sh
|
||||||
|
PYTHON=python3 ./configure --prefix=/usr
|
||||||
|
cd src/python
|
||||||
|
make
|
||||||
|
|
||||||
|
# install to core virtual environment
|
||||||
cd <CORE_REPO>/daemon
|
cd <CORE_REPO>/daemon
|
||||||
poetry run pip install <EMANE_REPO>/src/python
|
poetry run pip install <EMANE_REPO>/src/python
|
||||||
```
|
```
|
||||||
|
|
11
install.sh
11
install.sh
|
@ -14,7 +14,8 @@ fi
|
||||||
dev=""
|
dev=""
|
||||||
verbose=""
|
verbose=""
|
||||||
prefix=""
|
prefix=""
|
||||||
while getopts "dvp:" opt; do
|
local=""
|
||||||
|
while getopts "dvlp:" opt; do
|
||||||
case ${opt} in
|
case ${opt} in
|
||||||
d)
|
d)
|
||||||
dev="-d"
|
dev="-d"
|
||||||
|
@ -22,14 +23,18 @@ while getopts "dvp:" opt; do
|
||||||
v)
|
v)
|
||||||
verbose="-v"
|
verbose="-v"
|
||||||
;;
|
;;
|
||||||
|
l)
|
||||||
|
local="-l"
|
||||||
|
;;
|
||||||
p)
|
p)
|
||||||
prefix="-p ${OPTARG}"
|
prefix="-p ${OPTARG}"
|
||||||
;;
|
;;
|
||||||
\?)
|
\?)
|
||||||
echo "script usage: $(basename $0) [-d] [-v]" >&2
|
echo "script usage: $(basename $0) [-v] [-d] [-l] [-p <prefix>]" >&2
|
||||||
echo "" >&2
|
echo "" >&2
|
||||||
echo "-v enable verbose install" >&2
|
echo "-v enable verbose install" >&2
|
||||||
echo "-d enable developer install" >&2
|
echo "-d enable developer install" >&2
|
||||||
|
echo "-l enable local install, not compatible with developer install" >&2
|
||||||
echo "-p install prefix, defaults to /usr/local" >&2
|
echo "-p install prefix, defaults to /usr/local" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
|
@ -54,4 +59,4 @@ python3 -m pip install --user pipx
|
||||||
python3 -m pipx ensurepath
|
python3 -m pipx ensurepath
|
||||||
export PATH=$PATH:~/.local/bin
|
export PATH=$PATH:~/.local/bin
|
||||||
pipx install invoke
|
pipx install invoke
|
||||||
inv install ${dev} ${verbose} ${prefix}
|
inv install ${dev} ${verbose} ${local} ${prefix}
|
||||||
|
|
110
tasks.py
110
tasks.py
|
@ -171,13 +171,18 @@ def install_core(c: Context, hide: bool) -> None:
|
||||||
c.run("sudo make install", hide=hide)
|
c.run("sudo make install", hide=hide)
|
||||||
|
|
||||||
|
|
||||||
def install_poetry(c: Context, dev: bool, hide: bool) -> None:
|
def install_poetry(c: Context, dev: bool, local: bool, hide: bool) -> None:
|
||||||
c.run("pipx install poetry", hide=hide)
|
c.run("pipx install poetry", hide=hide)
|
||||||
args = "" if dev else "--no-dev"
|
if local:
|
||||||
with c.cd(DAEMON_DIR):
|
with c.cd(DAEMON_DIR):
|
||||||
c.run(f"poetry install {args}", hide=hide)
|
c.run("poetry build -f wheel", hide=hide)
|
||||||
if dev:
|
c.run("sudo python3 -m pip install dist/*")
|
||||||
c.run("poetry run pre-commit install", hide=hide)
|
else:
|
||||||
|
args = "" if dev else "--no-dev"
|
||||||
|
with c.cd(DAEMON_DIR):
|
||||||
|
c.run(f"poetry install {args}", hide=hide)
|
||||||
|
if dev:
|
||||||
|
c.run("poetry run pre-commit install", hide=hide)
|
||||||
|
|
||||||
|
|
||||||
def install_ospf_mdr(c: Context, os_info: OsInfo, hide: bool) -> None:
|
def install_ospf_mdr(c: Context, os_info: OsInfo, hide: bool) -> None:
|
||||||
|
@ -243,10 +248,11 @@ def install_service(c, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
@task(
|
@task(
|
||||||
help={
|
help={
|
||||||
"verbose": "enable verbose",
|
"verbose": "enable verbose",
|
||||||
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}"
|
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}",
|
||||||
|
"local": "determines if core will install to local system, default is False",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def install_scripts(c, verbose=False, prefix=DEFAULT_PREFIX):
|
def install_scripts(c, local=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
"""
|
"""
|
||||||
install core script files, modified to leverage virtual environment
|
install core script files, modified to leverage virtual environment
|
||||||
"""
|
"""
|
||||||
|
@ -259,7 +265,7 @@ def install_scripts(c, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
first = lines[0].strip()
|
first = lines[0].strip()
|
||||||
# modify python scripts to point to virtual environment
|
# modify python scripts to point to virtual environment
|
||||||
if first == "#!/usr/bin/env python3":
|
if not local and first == "#!/usr/bin/env python3":
|
||||||
lines[0] = f"#!{python}\n"
|
lines[0] = f"#!{python}\n"
|
||||||
temp = NamedTemporaryFile("w", delete=False)
|
temp = NamedTemporaryFile("w", delete=False)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
@ -273,16 +279,17 @@ def install_scripts(c, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
c.run(f"sudo cp {script} {dest}", hide=hide)
|
c.run(f"sudo cp {script} {dest}", hide=hide)
|
||||||
|
|
||||||
# setup core python helper
|
# setup core python helper
|
||||||
core_python = bin_dir.joinpath("core-python")
|
if not local:
|
||||||
temp = NamedTemporaryFile("w", delete=False)
|
core_python = bin_dir.joinpath("core-python")
|
||||||
temp.writelines([
|
temp = NamedTemporaryFile("w", delete=False)
|
||||||
"#!/bin/bash\n",
|
temp.writelines([
|
||||||
f'exec "{python}" "$@"\n',
|
"#!/bin/bash\n",
|
||||||
])
|
f'exec "{python}" "$@"\n',
|
||||||
temp.close()
|
])
|
||||||
c.run(f"sudo cp {temp.name} {core_python}", hide=hide)
|
temp.close()
|
||||||
c.run(f"sudo chmod 755 {core_python}", hide=hide)
|
c.run(f"sudo cp {temp.name} {core_python}", hide=hide)
|
||||||
os.unlink(temp.name)
|
c.run(f"sudo chmod 755 {core_python}", hide=hide)
|
||||||
|
os.unlink(temp.name)
|
||||||
|
|
||||||
# install core configuration file
|
# install core configuration file
|
||||||
config_dir = "/etc/core"
|
config_dir = "/etc/core"
|
||||||
|
@ -295,13 +302,15 @@ def install_scripts(c, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
help={
|
help={
|
||||||
"dev": "install development mode",
|
"dev": "install development mode",
|
||||||
"verbose": "enable verbose",
|
"verbose": "enable verbose",
|
||||||
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}"
|
"local": "determines if core will install to local system, default is False",
|
||||||
|
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def install(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
def install(c, dev=False, verbose=False, local=False, prefix=DEFAULT_PREFIX):
|
||||||
"""
|
"""
|
||||||
install core, poetry, scripts, service, and ospf mdr
|
install core, poetry, scripts, service, and ospf mdr
|
||||||
"""
|
"""
|
||||||
|
print(f"installing core locally: {local}")
|
||||||
print(f"installing core with prefix: {prefix}")
|
print(f"installing core with prefix: {prefix}")
|
||||||
c.run("sudo -v", hide=True)
|
c.run("sudo -v", hide=True)
|
||||||
p = Progress(verbose)
|
p = Progress(verbose)
|
||||||
|
@ -317,10 +326,11 @@ def install(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
build_core(c, hide, prefix)
|
build_core(c, hide, prefix)
|
||||||
with p.start("installing vcmd/gui"):
|
with p.start("installing vcmd/gui"):
|
||||||
install_core(c, hide)
|
install_core(c, hide)
|
||||||
with p.start("installing poetry virtual environment"):
|
install_type = "core" if local else "core virtual environment"
|
||||||
install_poetry(c, dev, hide)
|
with p.start(f"installing {install_type}"):
|
||||||
|
install_poetry(c, dev, local, hide)
|
||||||
with p.start("installing scripts and /etc/core"):
|
with p.start("installing scripts and /etc/core"):
|
||||||
install_scripts(c, hide, prefix)
|
install_scripts(c, local, hide, prefix)
|
||||||
with p.start("installing systemd service"):
|
with p.start("installing systemd service"):
|
||||||
install_service(c, hide, prefix)
|
install_service(c, hide, prefix)
|
||||||
with p.start("installing ospf mdr"):
|
with p.start("installing ospf mdr"):
|
||||||
|
@ -331,9 +341,10 @@ def install(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
@task(
|
@task(
|
||||||
help={
|
help={
|
||||||
"verbose": "enable verbose",
|
"verbose": "enable verbose",
|
||||||
|
"local": "used determine if core is installed locally, default is False",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def install_emane(c, verbose=False):
|
def install_emane(c, verbose=False, local=False):
|
||||||
"""
|
"""
|
||||||
install emane and the python bindings
|
install emane and the python bindings
|
||||||
"""
|
"""
|
||||||
|
@ -373,18 +384,25 @@ def install_emane(c, verbose=False):
|
||||||
with c.cd(emane_dir):
|
with c.cd(emane_dir):
|
||||||
c.run("sudo make install", hide=hide)
|
c.run("sudo make install", hide=hide)
|
||||||
with p.start("installing python binding for core"):
|
with p.start("installing python binding for core"):
|
||||||
with c.cd(DAEMON_DIR):
|
if local:
|
||||||
c.run(f"poetry run pip install {emane_python_dir.absolute()}", hide=hide)
|
with c.cd(str(emane_python_dir)):
|
||||||
|
c.run("sudo python3 -m pip install .", hide=hide)
|
||||||
|
else:
|
||||||
|
with c.cd(DAEMON_DIR):
|
||||||
|
c.run(
|
||||||
|
f"poetry run pip install {emane_python_dir.absolute()}", hide=hide
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@task(
|
@task(
|
||||||
help={
|
help={
|
||||||
"dev": "uninstall development mode",
|
"dev": "uninstall development mode",
|
||||||
"verbose": "enable verbose",
|
"verbose": "enable verbose",
|
||||||
|
"local": "determines if core was installed local to system, default is False",
|
||||||
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}"
|
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def uninstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
def uninstall(c, dev=False, verbose=False, local=False, prefix=DEFAULT_PREFIX):
|
||||||
"""
|
"""
|
||||||
uninstall core, scripts, service, virtual environment, and clean build directory
|
uninstall core, scripts, service, virtual environment, and clean build directory
|
||||||
"""
|
"""
|
||||||
|
@ -399,14 +417,18 @@ def uninstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
c.run("make clean", hide=hide)
|
c.run("make clean", hide=hide)
|
||||||
c.run("./bootstrap.sh clean", hide=hide)
|
c.run("./bootstrap.sh clean", hide=hide)
|
||||||
|
|
||||||
python = get_python(c, warn=True)
|
if local:
|
||||||
if python:
|
with p.start("uninstalling core"):
|
||||||
with c.cd(DAEMON_DIR):
|
c.run("sudo python3 -m pip uninstall -y core", hide=hide)
|
||||||
if dev:
|
else:
|
||||||
with p.start("uninstalling pre-commit"):
|
python = get_python(c, warn=True)
|
||||||
c.run("poetry run pre-commit uninstall", hide=hide)
|
if python:
|
||||||
with p.start("uninstalling poetry virtual environment"):
|
with c.cd(DAEMON_DIR):
|
||||||
c.run(f"poetry env remove {python}", hide=hide)
|
if dev:
|
||||||
|
with p.start("uninstalling pre-commit"):
|
||||||
|
c.run("poetry run pre-commit uninstall", hide=hide)
|
||||||
|
with p.start("uninstalling poetry virtual environment"):
|
||||||
|
c.run(f"poetry env remove {python}", hide=hide)
|
||||||
|
|
||||||
# remove installed files
|
# remove installed files
|
||||||
bin_dir = Path(prefix).joinpath("bin")
|
bin_dir = Path(prefix).joinpath("bin")
|
||||||
|
@ -416,10 +438,11 @@ def uninstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
c.run(f"sudo rm -f {dest}", hide=hide)
|
c.run(f"sudo rm -f {dest}", hide=hide)
|
||||||
|
|
||||||
# remove core-python symlink
|
# remove core-python symlink
|
||||||
core_python = bin_dir.joinpath("core-python")
|
if not local:
|
||||||
c.run(f"sudo rm -f {core_python}", hide=hide)
|
core_python = bin_dir.joinpath("core-python")
|
||||||
|
c.run(f"sudo rm -f {core_python}", hide=hide)
|
||||||
|
|
||||||
# install service
|
# remove service
|
||||||
systemd_dir = Path("/lib/systemd/system/")
|
systemd_dir = Path("/lib/systemd/system/")
|
||||||
service_name = "core-daemon.service"
|
service_name = "core-daemon.service"
|
||||||
service_file = systemd_dir.joinpath(service_name)
|
service_file = systemd_dir.joinpath(service_name)
|
||||||
|
@ -433,15 +456,18 @@ def uninstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX):
|
||||||
help={
|
help={
|
||||||
"dev": "reinstall development mode",
|
"dev": "reinstall development mode",
|
||||||
"verbose": "enable verbose",
|
"verbose": "enable verbose",
|
||||||
|
"local": "determines if core will install to local system, default is False",
|
||||||
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}",
|
"prefix": f"prefix where scripts are installed, default is {DEFAULT_PREFIX}",
|
||||||
"branch": "branch to install latest code from, default is current branch"
|
"branch": "branch to install latest code from, default is current branch"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def reinstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX, branch=None):
|
def reinstall(
|
||||||
|
c, dev=False, verbose=False, local=False, prefix=DEFAULT_PREFIX, branch=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
run the uninstall task, get latest from specified branch, and run install task
|
run the uninstall task, get latest from specified branch, and run install task
|
||||||
"""
|
"""
|
||||||
uninstall(c, dev, verbose, prefix)
|
uninstall(c, dev, verbose, local, prefix)
|
||||||
hide = not verbose
|
hide = not verbose
|
||||||
p = Progress(verbose)
|
p = Progress(verbose)
|
||||||
with p.start("pulling latest code"):
|
with p.start("pulling latest code"):
|
||||||
|
@ -453,7 +479,7 @@ def reinstall(c, dev=False, verbose=False, prefix=DEFAULT_PREFIX, branch=None):
|
||||||
c.run("git pull", hide=hide)
|
c.run("git pull", hide=hide)
|
||||||
if not Path("tasks.py").exists():
|
if not Path("tasks.py").exists():
|
||||||
raise FileNotFoundError(f"missing tasks.py on branch: {branch}")
|
raise FileNotFoundError(f"missing tasks.py on branch: {branch}")
|
||||||
install(c, dev, verbose, prefix)
|
install(c, dev, verbose, local, prefix)
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
|
|
Loading…
Reference in a new issue