From 5c29acb728af98ae75527947477f1061b715302b Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Sun, 15 Mar 2026 21:03:01 +0100 Subject: [PATCH] [script] install nodes in ~/.local/share/otns so that OTNS can run from anywhere The installation is updated to copy node executables to a .local/share directory. This directory is added to the node search path, so that standard OT node executables can be found from any directory location where OTNS is run from. The build and copying of node executables is added to the './script/install' script. Close #587 --- .github/workflows/build.yml | 4 +-- .github/workflows/develop.yml | 4 +-- .github/workflows/lint.yml | 4 +-- GUIDE.md | 2 +- ot-rfsim/ot-versions/README.md | 4 ++- script/install | 18 ++++------- script/install-nodes | 9 +++++- script/install-otns | 55 ++++++++++++++++++++++++++++++++++ script/test | 4 +-- simulation/node_config.go | 4 +-- simulation/utils.go | 10 ++++++- 11 files changed, 92 insertions(+), 26 deletions(-) create mode 100755 script/install-otns diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e553d26..e375e7ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2025, The OTNS Authors. +# Copyright (c) 2020-2026, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -58,7 +58,7 @@ jobs: - name: Build run: | ./script/install-deps - ./script/install + ./script/install-otns build-nodes: name: Build Nodes (${{ matrix.os }}) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index f495871c..063fb5ea 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2025, The OTNS Authors. +# Copyright (c) 2020-2026, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -77,7 +77,7 @@ jobs: git diff exit 1 fi - ./script/install + ./script/install-otns - name: Build custom OT node # FIXME: OT_CMAKE_NINJA_TARGET used to exclude tests, because test_platform.cpp is missing otPlatAssertFail() run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 58093ed5..94af4f08 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2025, The OTNS Authors. +# Copyright (c) 2020-2026, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -59,5 +59,5 @@ jobs: - name: Check pretty run: | ./script/install-deps - ./script/install + ./script/install-otns ./script/make-pretty check diff --git a/GUIDE.md b/GUIDE.md index 5168c228..2f0151d5 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -52,7 +52,7 @@ Running this script will also set up a Python 3 virtual environment (venv) in `. #### Install OTNS ```bash -./script/install +./script/install-otns ``` This installs `otns` in the Go binary directory of the user (typically `~/go/bin`) and makes the command available in the path. Also, it installs the pyOTNS library in the local Python virtual environment `.venv-otns`. The OT nodes required for running a simulation are not yet installed at this point: this is the next step. diff --git a/ot-rfsim/ot-versions/README.md b/ot-rfsim/ot-versions/README.md index c26f5f74..8bc4acc4 100644 --- a/ot-rfsim/ot-versions/README.md +++ b/ot-rfsim/ot-versions/README.md @@ -18,4 +18,6 @@ Versions are listed below. With each version tag, the directory is listed in whi - br-ccm - `openthread-ccm` - (In development) A Thread CCM Border Router. -Build scripts: the build scripts to build all of the versions are `../script/build_`. Each of these specific build scripts invokes the general `build` script. The `../script/build_all` builds all commonly used versions. +Build scripts: the build scripts to build all of the versions are `./script/build_`, which are invoked from the `./ot-rfsim` directory. Each of these specific build scripts invokes the general `build` script. The `./script/build_all` builds all commonly used versions. + +Note: all build scripts copy the resulting executables to the `./ot-rfsim/ot-versions` directory. Before OTNS will use these executables, they must be copied to the `~/.local/share/otns/bin` directory. This is done by the installation script `./script/install-nodes` which is invoked from the main OTNS repo directory. diff --git a/script/install b/script/install index 6c78a82a..e7fdfa0d 100755 --- a/script/install +++ b/script/install @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2020-2025, The OTNS Authors. +# Copyright (c) 2020-2026, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,31 +25,25 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -# Installs OTNS (without any OT node executables) and pyOTNS. +# Installs OTNS in ~/go/bin, pyOTNS, and all nodes in ~/.local/share/otns # shellcheck source=script/common.sh . "$(dirname "$0")"/common.sh install_otns() { - go mod tidy - repeat 3 go_install ./cmd/... - echo "otns installed: $(command -v otns)" + ./script/install-otns } -install_pyotns() +install_nodes() { - activate_python_venv - cd pylibs - python3 -m pip install . - # python3 setup.py install --user --prefix= 2>/dev/null # alternative - fails on macos-14 - cd - + ./script/install-nodes } main() { - install_pyotns install_otns + install_nodes } main diff --git a/script/install-nodes b/script/install-nodes index 9a642675..e480e774 100755 --- a/script/install-nodes +++ b/script/install-nodes @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2024-2025, The OTNS Authors. +# Copyright (c) 2024-2026, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,9 +31,16 @@ # shellcheck source=script/common.sh . "$(dirname "$0")"/common.sh +install_nodes_to_local_share() +{ + mkdir -p ~/.local/share/otns/bin + cp ./ot-rfsim/ot-versions/* ~/.local/share/otns/bin/ +} + main() { build_openthread_versions + install_nodes_to_local_share } main diff --git a/script/install-otns b/script/install-otns new file mode 100755 index 00000000..ed4a7e22 --- /dev/null +++ b/script/install-otns @@ -0,0 +1,55 @@ +#!/bin/bash +# Copyright (c) 2020-2026, The OTNS Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# Installs OTNS (without any OT node executables) and pyOTNS. + +# shellcheck source=script/common.sh +. "$(dirname "$0")"/common.sh + +install_otns() +{ + go mod tidy + repeat 3 go_install ./cmd/... + echo "otns installed: $(command -v otns)" +} + +install_pyotns() +{ + activate_python_venv + cd pylibs || die "required directory 'pylibs' not found" + python3 -m pip install . + # python3 setup.py install --user --prefix= 2>/dev/null # alternative - fails on macos-14 + cd - || die "cd failed" +} + +main() +{ + install_pyotns + install_otns +} + +main diff --git a/script/test b/script/test index 4263db51..812ea4a9 100755 --- a/script/test +++ b/script/test @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2020-2025, The OTNS Authors. +# Copyright (c) 2020-2026, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -80,7 +80,7 @@ install_deps() install_otns() { - ./script/install + ./script/install-otns } py_unittests() diff --git a/simulation/node_config.go b/simulation/node_config.go index 1bcee5d5..304860d8 100644 --- a/simulation/node_config.go +++ b/simulation/node_config.go @@ -144,7 +144,7 @@ var DefaultExecutableConfig ExecutableConfig = ExecutableConfig{ Mtd: "ot-cli-mtd", Br: "ot-cli-ftd_br", Matter: "ot-matter-node", - SearchPaths: []string{".", "./ot-rfsim/ot-versions", "./build/bin"}, + SearchPaths: []string{".", filePathInUserHomeDir(".local/share/otns/bin"), "./ot-rfsim/ot-versions"}, } func DefaultNodeConfig() NodeConfig { @@ -280,7 +280,7 @@ func (cfg *ExecutableConfig) FindExecutable(exeName string) string { return "./" + exePath } } - // if not found, try to relay on OS $PATH to find the executables. + // if not found, try to rely on OS $PATH to find the executables. return exeName } diff --git a/simulation/utils.go b/simulation/utils.go index f7a02f30..221ed6b6 100644 --- a/simulation/utils.go +++ b/simulation/utils.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2024, The OTNS Authors. +// Copyright (c) 2020-2026, The OTNS Authors. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -37,6 +37,14 @@ import ( "golang.org/x/net/ipv6" ) +func filePathInUserHomeDir(relPath string) string { + home, err := os.UserHomeDir() + if err == nil { + return filepath.Join(home, relPath) + } + return "/tmp/UserHomeDirNotFound" +} + func removeAllFiles(globPath string) error { files, err := filepath.Glob(globPath) if err != nil {