├── .dockerignore ├── .github └── workflows │ ├── test-linux.yml │ ├── test-macos.yml │ └── test-windows.yml ├── AUTHORS ├── Dockerfile ├── LICENSE ├── README.md ├── install.ps1 ├── install.sh ├── proxy ├── .dockerignore ├── Dockerfile └── nginx.conf ├── test.sh └── test ├── .gitignore ├── async.py ├── opencv ├── opencv.py └── requirements.txt ├── package-lock.json ├── package.js ├── package.json ├── requirements.py ├── requirements.txt ├── script.js ├── script.py └── spacex ├── launchpads.py ├── requirements.txt └── spacex.js /.dockerignore: -------------------------------------------------------------------------------- 1 | ** 2 | !test 3 | !proxy/nginx.conf 4 | !install.sh 5 | -------------------------------------------------------------------------------- /.github/workflows/test-linux.yml: -------------------------------------------------------------------------------- 1 | name: Install MetaCall on Linux Test 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | trigger-cli-build: 11 | name: Trigger CLI Docker Build 12 | runs-on: ubuntu-latest 13 | if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Trigger metacall/cli Build Workflow 18 | uses: convictional/trigger-workflow-and-wait@v1.6.1 19 | with: 20 | owner: metacall 21 | repo: cli 22 | github_token: ${{ secrets.G_PERSONAL_ACCESS_TOKEN }} 23 | workflow_file_name: docker-hub.yml 24 | wait_workflow: true 25 | ref: master 26 | 27 | install-local: 28 | name: Install MetaCall via Default Installation (local) 29 | runs-on: ubuntu-latest 30 | if: always() 31 | needs: trigger-cli-build 32 | steps: 33 | - uses: actions/checkout@v4 34 | - name: Tests 35 | run: ./test.sh 36 | 37 | install-remote: 38 | name: Install MetaCall via Default Installation (remote) 39 | runs-on: ubuntu-latest 40 | if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' 41 | needs: trigger-cli-build 42 | steps: 43 | - uses: actions/checkout@v4 44 | - run: echo "METACALL_INSTALL_CERTS=certificates_remote" >> $GITHUB_ENV 45 | - name: Tests 46 | run: ./test.sh 47 | -------------------------------------------------------------------------------- /.github/workflows/test-macos.yml: -------------------------------------------------------------------------------- 1 | name: Install MetaCall on MacOS Test 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | install-default: 11 | name: Install MetaCall via Default Installation 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | os: [macos-13, macos-14] 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Install MetaCall 20 | env: 21 | METACALL_INSTALL_DEBUG: 1 22 | run: ./install.sh 23 | 24 | - name: NodeJS Test 25 | run: metacall ./test/script.js | grep "123456" 26 | 27 | - name: Python Test 28 | run: metacall pip install -r ./test/requirements.txt | grep "Successfully installed" 29 | 30 | - name: Deploy & FaaS Test 31 | run: | 32 | metacall deploy --version | grep -E "^v.*\..*\..*" 33 | metacall faas --version | grep -E "^v.*\..*\..*" 34 | 35 | - name: REPL Test 36 | run: | 37 | printf "load mock test.mock\ninspect\nexit" \ 38 | | metacall \ 39 | | grep "function three_str(a_str, b_str, c_str)" 40 | 41 | - name: Uninstall MetaCall 42 | env: 43 | METACALL_INSTALL_DEBUG: 1 44 | run: ./install.sh --uninstall 45 | 46 | - name: Check Uninstall 47 | # TODO: A good test case would be to do a $(find /) and then 48 | # compare the filesystems before and after installation 49 | run: | 50 | if command -v metacall >/dev/null 2>&1; then 51 | echo "Failed to uninstall MetaCall, the program is still available" 52 | exit 1 53 | fi 54 | 55 | install-from-path: 56 | name: Install MetaCall via Path Installation 57 | strategy: 58 | fail-fast: false 59 | matrix: 60 | triplet: [ 61 | {os: macos-13, arch: amd64}, 62 | {os: macos-14, arch: arm64} 63 | ] 64 | package: [tar.gz] # [tar.gz, pkg] # TODO: pkg 65 | runs-on: ${{ matrix.triplet.os }} 66 | steps: 67 | - uses: actions/checkout@v4 68 | - name: Download Tarball 69 | run: | 70 | LATEST_VERSION="$(curl -sqI https://github.com/metacall/distributable-macos/releases/latest | awk -F '/' '/^location/ {print substr($NF, 1, length($NF)-1)}')" 71 | PACKAGE="metacall-tarball-macos-${{ matrix.triplet.arch }}.${{ matrix.package }}" 72 | URL="https://github.com/metacall/distributable-macos/releases/download/$LATEST_VERSION/$PACKAGE" 73 | curl -sL "$URL" -o "metacall-tarball-macos.${{ matrix.package }}" 74 | ls -la metacall-tarball-macos.${{ matrix.package }} 75 | 76 | - name: Install MetaCall 77 | env: 78 | METACALL_INSTALL_DEBUG: 1 79 | run: ./install.sh --from-path ./metacall-tarball-macos.${{ matrix.package }} 80 | 81 | - name: NodeJS Test 82 | run: metacall ./test/script.js | grep "123456" 83 | 84 | - name: Python Test 85 | run: metacall pip install -r ./test/requirements.txt | grep "Successfully installed" 86 | 87 | - name: Deploy & FaaS Test 88 | run: | 89 | metacall deploy --version | grep -E "^v.*\..*\..*" 90 | metacall faas --version | grep -E "^v.*\..*\..*" 91 | 92 | - name: REPL Test 93 | run: | 94 | printf "load mock test.mock\ninspect\nexit" \ 95 | | metacall \ 96 | | grep "function three_str(a_str, b_str, c_str)" 97 | 98 | - name: Uninstall MetaCall 99 | env: 100 | METACALL_INSTALL_DEBUG: 1 101 | run: ./install.sh --uninstall 102 | 103 | - name: Check Uninstall 104 | # TODO: A good test case would be to do a $(find /) and then 105 | # compare the filesystems before and after installation 106 | run: | 107 | if command -v metacall >/dev/null 2>&1; then 108 | echo "Failed to uninstall MetaCall, the program is still available" 109 | exit 1 110 | fi 111 | -------------------------------------------------------------------------------- /.github/workflows/test-windows.yml: -------------------------------------------------------------------------------- 1 | name: Install MetaCall on Windows Test 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | install-default: 11 | name: Install MetaCall via Default Installation 12 | runs-on: windows-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Install MetaCall 16 | shell: cmd 17 | env: 18 | METACALL_INSTALL_DEBUG: 1 19 | run: | 20 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 21 | 22 | - name: NodeJS Test 23 | shell: cmd 24 | run: | 25 | metacall ./test/script.js | findstr "123456" 26 | IF %ERRORLEVEL% NEQ 0 exit /B 1 27 | 28 | - name: Python Test 29 | shell: cmd 30 | run: | 31 | rem metacall pip install -r test/requirements.txt | findstr "Successfully installed" 32 | metacall pip install -r test/requirements.txt 33 | IF %ERRORLEVEL% NEQ 0 exit /B 1 34 | rem metacall ./test/requirements.py | findstr "123456" 35 | metacall ./test/requirements.py 36 | IF %ERRORLEVEL% NEQ 0 exit /B 1 37 | 38 | - name: Deploy & FaaS Test 39 | shell: cmd 40 | run: | 41 | metacall deploy --version | findstr /R "^v.*\..*\..*" 42 | IF %ERRORLEVEL% NEQ 0 exit /B 1 43 | metacall faas --version | findstr /R "^v.*\..*\..*" 44 | IF %ERRORLEVEL% NEQ 0 exit /B 1 45 | 46 | - name: Uninstall MetaCall 47 | shell: cmd 48 | env: 49 | METACALL_INSTALL_DEBUG: 1 50 | run: | 51 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 -Uninstall 52 | 53 | - name: Uninstall Test 54 | shell: pwsh 55 | run: | 56 | $MetaCallPath = "$env:LocalAppData\MetaCall" 57 | Write-Output "Checking MetaCall installation directory: $MetaCallPath" 58 | If (Test-Path $MetaCallPath) { 59 | Write-Error "MetaCall installation directory still exists" 60 | exit 1 61 | } 62 | $MetaCallBinary = (Get-Command metacall -ErrorAction SilentlyContinue) 63 | If ($MetaCallBinary) { 64 | Write-Error "MetaCall binary is still available" 65 | exit 2 66 | } 67 | Write-Output "Uninstall verification passed." 68 | 69 | install-from-path: 70 | name: Install MetaCall via Path Installation 71 | runs-on: windows-latest 72 | steps: 73 | - uses: actions/checkout@v4 74 | - name: Download Tarball 75 | shell: pwsh 76 | run: | 77 | $request = Invoke-WebRequest -UseBasicParsing -Method Head -Uri https://github.com/metacall/distributable-windows/releases/latest 78 | $redirectUri = $request.BaseResponse.RequestMessage.RequestUri 79 | $version = $redirectUri.Segments[$redirectUri.Segments.Count - 1] 80 | $url = "https://github.com/metacall/distributable-windows/releases/download/$version/metacall-tarball-win-x64.zip" 81 | Invoke-WebRequest $url -OutFile metacall-tarball-win-x64.zip 82 | 83 | - name: Install MetaCall 84 | shell: cmd 85 | env: 86 | METACALL_INSTALL_DEBUG: 1 87 | run: | 88 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 -FromPath metacall-tarball-win-x64.zip 89 | 90 | - name: NodeJS Test 91 | shell: cmd 92 | run: | 93 | metacall ./test/script.js | findstr "123456" 94 | IF %ERRORLEVEL% NEQ 0 exit /B 1 95 | 96 | - name: Python Test 97 | shell: cmd 98 | run: | 99 | metacall pip install -r test/requirements.txt | findstr "Successfully installed" 100 | IF %ERRORLEVEL% NEQ 0 exit /B 1 101 | metacall ./test/requirements.py | findstr "123456" 102 | IF %ERRORLEVEL% NEQ 0 exit /B 1 103 | 104 | - name: Deploy & FaaS Test 105 | shell: cmd 106 | run: | 107 | metacall deploy --version | findstr /R "^v.*\..*\..*" 108 | IF %ERRORLEVEL% NEQ 0 exit /B 1 109 | metacall faas --version | findstr /R "^v.*\..*\..*" 110 | IF %ERRORLEVEL% NEQ 0 exit /B 1 111 | 112 | - name: Uninstall MetaCall 113 | shell: cmd 114 | env: 115 | METACALL_INSTALL_DEBUG: 1 116 | run: | 117 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 -Uninstall 118 | 119 | - name: Uninstall Test 120 | shell: pwsh 121 | run: | 122 | $MetaCallPath = "$env:LocalAppData\MetaCall" 123 | Write-Output "Checking MetaCall installation directory: $MetaCallPath" 124 | If (Test-Path $MetaCallPath) { 125 | Write-Error "MetaCall installation directory still exists" 126 | exit 1 127 | } 128 | $MetaCallBinary = (Get-Command metacall -ErrorAction SilentlyContinue) 129 | If ($MetaCallBinary) { 130 | Write-Error "MetaCall binary is still available" 131 | exit 2 132 | } 133 | Write-Output "Uninstall verification passed." 134 | 135 | install-path-with-whitespaces: 136 | name: Install MetaCall via Path With Whitespaces 137 | runs-on: windows-latest 138 | steps: 139 | - uses: actions/checkout@v4 140 | - name: Create install folder 141 | shell: cmd 142 | run: | 143 | mkdir "install folder with spaces" 144 | 145 | - name: Install MetaCall 146 | shell: cmd 147 | env: 148 | METACALL_INSTALL_DEBUG: 1 149 | run: | 150 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 -InstallDir '%cd%\install folder with spaces' 151 | 152 | - name: Install Test 153 | shell: cmd 154 | run: | 155 | dir "%cd%\install folder with spaces" 156 | 157 | - name: NodeJS Test 158 | shell: cmd 159 | run: | 160 | metacall ./test/script.js | findstr "123456" 161 | IF %ERRORLEVEL% NEQ 0 exit /B 1 162 | 163 | - name: Python Test 164 | shell: cmd 165 | run: | 166 | metacall pip install -r test/requirements.txt | findstr "Successfully installed" 167 | IF %ERRORLEVEL% NEQ 0 exit /B 1 168 | metacall ./test/requirements.py | findstr "123456" 169 | IF %ERRORLEVEL% NEQ 0 exit /B 1 170 | 171 | - name: Deploy & FaaS Test 172 | shell: cmd 173 | run: | 174 | metacall deploy --version | findstr /R "^v.*\..*\..*" 175 | IF %ERRORLEVEL% NEQ 0 exit /B 1 176 | metacall faas --version | findstr /R "^v.*\..*\..*" 177 | IF %ERRORLEVEL% NEQ 0 exit /B 1 178 | 179 | - name: Uninstall MetaCall 180 | shell: cmd 181 | env: 182 | METACALL_INSTALL_DEBUG: 1 183 | run: | 184 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 -Uninstall -InstallDir '%cd%\install folder with spaces' 185 | 186 | - name: Uninstall Test 187 | shell: pwsh 188 | run: | 189 | $MetaCallPath = Join-Path (Get-Location) "install folder with spaces" 190 | Write-Output "Checking MetaCall installation directory: $MetaCallPath" 191 | If (Test-Path $MetaCallPath) { 192 | Write-Error "MetaCall installation directory still exists" 193 | exit 1 194 | } 195 | $MetaCallBinary = (Get-Command metacall -ErrorAction SilentlyContinue) 196 | If ($MetaCallBinary) { 197 | Write-Error "MetaCall binary is still available" 198 | exit 2 199 | } 200 | Write-Output "Uninstall verification passed." 201 | 202 | install-version-opencv: 203 | name: Install MetaCall with Specific Version 204 | runs-on: windows-latest 205 | steps: 206 | - uses: actions/checkout@v4 207 | - name: Install MetaCall 208 | run: | 209 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 -Version 0.1.7 210 | 211 | - name: NodeJS Test 212 | shell: cmd 213 | run: | 214 | metacall ./test/script.js | findstr "123456" 215 | IF %ERRORLEVEL% NEQ 0 exit /B 1 216 | 217 | - name: Python Test 218 | shell: cmd 219 | run: | 220 | metacall pip install -r test/requirements.txt | findstr "Successfully installed" 221 | IF %ERRORLEVEL% NEQ 0 exit /B 1 222 | metacall ./test/requirements.py | findstr "123456" 223 | IF %ERRORLEVEL% NEQ 0 exit /B 1 224 | 225 | - name: Python OpenCV Test (Install OpenCV) 226 | shell: cmd 227 | run: | 228 | metacall pip install -r test/opencv/requirements.txt | findstr "Successfully installed" 229 | IF %ERRORLEVEL% NEQ 0 exit /B 1 230 | 231 | # For some reason, OpenCV fails if you do not reinstall numpy 232 | - name: Python OpenCV Test (Uninstall Numpy for OpenCV) 233 | shell: cmd 234 | run: | 235 | metacall pip uninstall numpy --yes 236 | IF %ERRORLEVEL% NEQ 0 exit /B 1 237 | 238 | # For some reason, it needs to be split into two different steps in order to work 239 | - name: Python OpenCV Test (Install Numpy for OpenCV) 240 | shell: cmd 241 | run: | 242 | metacall pip install numpy==1.21.6 243 | IF %ERRORLEVEL% NEQ 0 exit /B 1 244 | 245 | - name: Python OpenCV Test (Test OpenCV) 246 | shell: cmd 247 | run: | 248 | metacall ./test/opencv/opencv.py | findstr "OpenCV Version: 3.4.11" 249 | IF %ERRORLEVEL% NEQ 0 exit /B 1 250 | 251 | - name: Deploy & FaaS Test 252 | shell: cmd 253 | run: | 254 | metacall deploy --version | findstr /R "^v.*\..*\..*" 255 | IF %ERRORLEVEL% NEQ 0 exit /B 1 256 | metacall faas --version | findstr /R "^v.*\..*\..*" 257 | IF %ERRORLEVEL% NEQ 0 exit /B 1 258 | 259 | - name: Uninstall MetaCall 260 | shell: cmd 261 | env: 262 | METACALL_INSTALL_DEBUG: 1 263 | run: | 264 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 -Uninstall 265 | 266 | - name: Uninstall Test 267 | shell: pwsh 268 | run: | 269 | $MetaCallPath = "$env:LocalAppData\MetaCall" 270 | Write-Output "Checking MetaCall installation directory: $MetaCallPath" 271 | If (Test-Path $MetaCallPath) { 272 | Write-Error "MetaCall installation directory still exists" 273 | exit 1 274 | } 275 | $MetaCallBinary = (Get-Command metacall -ErrorAction SilentlyContinue) 276 | If ($MetaCallBinary) { 277 | Write-Error "MetaCall binary is still available" 278 | exit 2 279 | } 280 | Write-Output "Uninstall verification passed." 281 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | Vicente Eduardo Ferrer Garcia 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # MetaCall Install Script by Parra Studios 3 | # Cross-platform set of scripts to install MetaCall infrastructure. 4 | # 5 | # Copyright (C) 2016 - 2024 Vicente Eduardo Ferrer Garcia 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | ARG METACALL_INSTALL_CERTS=certificates_local 21 | 22 | FROM scratch AS testing 23 | 24 | # Image descriptor 25 | LABEL copyright.name="Vicente Eduardo Ferrer Garcia" \ 26 | copyright.address="vic798@gmail.com" \ 27 | maintainer.name="Vicente Eduardo Ferrer Garcia" \ 28 | maintainer.address="vic798@gmail.com" \ 29 | vendor="MetaCall Inc." \ 30 | version="0.1" 31 | 32 | # Proxy certificates 33 | FROM metacall/install_nginx AS certificates_local 34 | 35 | # Remote certificates 36 | FROM debian:bookworm-slim AS certificates_remote 37 | 38 | RUN mkdir -p /etc/ssl/certs/ 39 | 40 | FROM ${METACALL_INSTALL_CERTS} AS certificates 41 | 42 | # Debian Base (root) 43 | FROM debian:bookworm-slim AS debian_root 44 | 45 | ENV METACALL_INSTALL_DEBUG=1 46 | 47 | COPY --from=certificates /etc/ssl/certs/ /etc/ssl/certs/ 48 | 49 | COPY test/ /test/ 50 | 51 | # Install dependencies and set up a sudo user without password 52 | RUN apt-get update \ 53 | && apt-get install -y --no-install-recommends sudo curl wget ca-certificates \ 54 | && apt-get clean && rm -rf /var/lib/apt/lists/ \ 55 | && printf "\nca_directory=/etc/ssl/certs" | tee -a /etc/wgetrc \ 56 | && update-ca-certificates \ 57 | && adduser --disabled-password --gecos "" user \ 58 | && usermod -aG sudo user \ 59 | && echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \ 60 | && chown -R user /test \ 61 | && chmod -R 700 /test 62 | 63 | # Debian Base (user) 64 | FROM debian_root AS debian_user 65 | 66 | USER user 67 | 68 | # Test install debian with root and wget from path 69 | FROM debian_root AS test_debian_root_wget_from_path 70 | 71 | RUN wget https://github.com/metacall/distributable-linux/releases/download/v0.7.0/metacall-tarball-linux-amd64.tar.gz \ 72 | && wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | bash -s -- --from-path /metacall-tarball-linux-amd64.tar.gz \ 73 | && metacall /test/script.js | grep '123456' \ 74 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 75 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 76 | && printf "load mock test.mock\ninspect\nexit" \ 77 | | metacall \ 78 | | grep -e 'function three_str(a_str, b_str, c_str)' 79 | 80 | # Test install Debian with root and curl 81 | FROM debian_root AS test_debian_root_curl 82 | 83 | RUN curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 84 | && metacall /test/script.js | grep '123456' \ 85 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 86 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 87 | && printf "load mock test.mock\ninspect\nexit" \ 88 | | metacall \ 89 | | grep -e 'function three_str(a_str, b_str, c_str)' 90 | 91 | # Test certificates in Debian with root (comparing against in buffer format) 92 | FROM test_debian_root_curl AS test_debian_root_certificates 93 | 94 | RUN export WEB_RESULT="`printf 'load py /test/script.py\ninspect\ncall fetch_https(\"www.google.com\")\nexit' | metacall`" \ 95 | && export WEB_BUFFER="[\n 60, 33, 100, 111, 99,\n 116, 121, 112, 101, 32,\n 104, 116, 109, 108, 62\n]" \ 96 | && [ -z "${WEB_RESULT##*$WEB_BUFFER*}" ] || exit 1 97 | 98 | # Test install Debian with root and wget 99 | FROM debian_root AS test_debian_root_wget 100 | 101 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 102 | && metacall /test/script.js | grep '123456' \ 103 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 104 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 105 | && printf "load mock test.mock\ninspect\nexit" \ 106 | | metacall \ 107 | | grep -e 'function three_str(a_str, b_str, c_str)' 108 | 109 | # Test install Debian without root and curl 110 | FROM debian_user AS test_debian_user_curl 111 | 112 | RUN curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 113 | && metacall /test/script.js | grep '123456' \ 114 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 115 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 116 | && printf "load mock test.mock\ninspect\nexit" \ 117 | | metacall \ 118 | | grep -e 'function three_str(a_str, b_str, c_str)' 119 | 120 | # Test uninstall Debian without root and curl 121 | FROM test_debian_user_curl AS test_debian_user_curl_uninstall 122 | 123 | RUN curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh \ 124 | | bash -s -- --uninstall \ 125 | && [ ! -f "/usr/local/bin/metacall" ] 126 | 127 | # Test uninstall Debian without root and curl, checking if it preserves existing files 128 | FROM debian_user AS test_debian_user_curl_uninstall_existing_files 129 | 130 | RUN sudo mkdir -p /gnu \ 131 | && curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 132 | && metacall /test/script.js | grep '123456' \ 133 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 134 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 135 | && printf "load mock test.mock\ninspect\nexit" \ 136 | | metacall \ 137 | | grep -e 'function three_str(a_str, b_str, c_str)' \ 138 | && curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh \ 139 | | bash -s -- --uninstall \ 140 | && [ ! -f "/usr/local/bin/metacall" ] \ 141 | && [ -d /gnu ] 142 | 143 | # TODO: 144 | # When implementing timestamp support: 145 | # 146 | # Create a test that has a /gnu folder, then install metacall, then update the mtime of a random file 147 | # from metacall installation, then uninstall and then verify that /gnu and the random file that has been 148 | # update are still present after the uninstall process 149 | 150 | # Test certificates in Debian with user (comparing against in buffer format) 151 | FROM test_debian_user_curl AS test_debian_user_certificates 152 | 153 | RUN export WEB_RESULT="`printf 'load py /test/script.py\ninspect\ncall fetch_https(\"www.google.com\")\nexit' | metacall`" \ 154 | && export WEB_BUFFER="[\n 60, 33, 100, 111, 99,\n 116, 121, 112, 101, 32,\n 104, 116, 109, 108, 62\n]" \ 155 | && [ -z "${WEB_RESULT##*$WEB_BUFFER*}" ] || exit 1 156 | 157 | # Test install Debian without root and wget 158 | FROM debian_user AS test_debian_user_wget 159 | 160 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 161 | && metacall /test/script.js | grep '123456' \ 162 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 163 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 164 | && printf "load mock test.mock\ninspect\nexit" \ 165 | | metacall \ 166 | | grep -e 'function three_str(a_str, b_str, c_str)' 167 | 168 | # Test reinstall Debian without root and wget 169 | FROM test_debian_user_wget AS test_debian_user_wget_reinstall 170 | 171 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | bash -s -- --update \ 172 | && metacall /test/script.js | grep '123456' \ 173 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 174 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 175 | && printf "load mock test.mock\ninspect\nexit" \ 176 | | metacall \ 177 | | grep -e 'function three_str(a_str, b_str, c_str)' 178 | 179 | # Test pip installation 180 | FROM test_debian_user_wget AS test_debian_user_pip 181 | 182 | RUN metacall pip3 install -r /test/requirements.txt \ 183 | && metacall /test/requirements.py | grep '123456' 184 | 185 | # Test npm installation 186 | FROM test_debian_user_wget AS test_debian_user_npm 187 | 188 | WORKDIR /test 189 | 190 | RUN metacall npm install \ 191 | && metacall /test/package.js | grep 'eyJhbGciOiJIUzI1NiJ9.eWVldA.bS3dTiCfusUIIqeH3484ByiBZC_cH0y8G5vonpPdqXA' 192 | 193 | # Test PYTHONPATH 194 | FROM test_debian_user_wget AS test_debian_user_pythonpath 195 | 196 | RUN metacall /test/async.py | grep 'Async Done' 197 | 198 | # Fedora Base (root) 199 | FROM fedora:latest AS fedora_root 200 | 201 | ENV METACALL_INSTALL_DEBUG=1 202 | 203 | COPY --from=certificates /etc/ssl/certs/ /etc/pki/ca-trust/source/anchors/ 204 | 205 | COPY test/ /test/ 206 | 207 | # Install dependencies and set up a sudo user without password 208 | RUN dnf update -y \ 209 | && dnf install -y sudo curl wget ca-certificates findutils util-linux gawk \ 210 | && dnf clean all \ 211 | && printf "\nca_directory=/etc/ssl/certs" | tee -a /etc/wgetrc \ 212 | && update-ca-trust extract \ 213 | && adduser user \ 214 | && usermod -aG wheel user \ 215 | && echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \ 216 | && chown -R user /test \ 217 | && chmod -R 700 /test 218 | 219 | # Fedora Base (user) 220 | FROM fedora_root AS fedora_user 221 | 222 | USER user 223 | 224 | # Test install Fedora with root and curl 225 | FROM fedora_root AS test_fedora_root_curl 226 | 227 | RUN curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 228 | && metacall /test/script.js | grep '123456' \ 229 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 230 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 231 | && printf "load mock test.mock\ninspect\nexit" \ 232 | | metacall \ 233 | | grep -e 'function three_str(a_str, b_str, c_str)' 234 | 235 | # Test install Fedora with root and wget 236 | FROM fedora_root AS test_fedora_root_wget 237 | 238 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 239 | && metacall /test/script.js | grep '123456' \ 240 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 241 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 242 | && printf "load mock test.mock\ninspect\nexit" \ 243 | | metacall \ 244 | | grep -e 'function three_str(a_str, b_str, c_str)' 245 | 246 | # Test install Fedora without root and curl 247 | FROM fedora_user AS test_fedora_user_curl 248 | 249 | RUN curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 250 | && metacall /test/script.js | grep '123456' \ 251 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 252 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 253 | && printf "load mock test.mock\ninspect\nexit" \ 254 | | metacall \ 255 | | grep -e 'function three_str(a_str, b_str, c_str)' 256 | 257 | # Test install Fedora without root and wget 258 | FROM fedora_user AS test_fedora_user_wget 259 | 260 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | bash \ 261 | && metacall /test/script.js | grep '123456' \ 262 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 263 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 264 | && printf "load mock test.mock\ninspect\nexit" \ 265 | | metacall \ 266 | | grep -e 'function three_str(a_str, b_str, c_str)' 267 | 268 | # Test uninstall Fedora 269 | FROM test_fedora_user_wget AS test_fedora_user_wget_uninstall 270 | 271 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh \ 272 | | sh -s -- --uninstall \ 273 | && [ ! -f "/usr/local/bin/metacall" ] 274 | 275 | # Alpine Base (root) 276 | FROM alpine:latest AS alpine_root 277 | 278 | ENV METACALL_INSTALL_DEBUG=1 279 | 280 | COPY --from=certificates /etc/ssl/certs/ /etc/ssl/certs/ 281 | 282 | COPY test/ /test/ 283 | 284 | # Install dependencies and set up a sudo user without password 285 | RUN apk update \ 286 | && apk add --no-cache sudo curl wget ca-certificates \ 287 | && rm -rf /var/cache/apk/* \ 288 | && printf "\nca_directory=/etc/ssl/certs" | tee -a /etc/wgetrc \ 289 | && update-ca-certificates \ 290 | && adduser --disabled-password --gecos "" user \ 291 | && echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \ 292 | && chown -R user /test \ 293 | && chmod -R 700 /test 294 | 295 | # Alpine Base (user) 296 | FROM alpine_root AS alpine_user 297 | 298 | USER user 299 | 300 | # Test install Alpine with root and curl 301 | FROM alpine_root AS test_alpine_root_curl 302 | 303 | RUN curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | sh \ 304 | && metacall /test/script.js | grep '123456' \ 305 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 306 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 307 | && printf "load mock test.mock\ninspect\nexit" \ 308 | | metacall \ 309 | | grep -e 'function three_str(a_str, b_str, c_str)' 310 | 311 | # Test install Alpine with root and wget 312 | FROM alpine_root AS test_alpine_root_wget 313 | 314 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh \ 315 | && metacall /test/script.js | grep '123456' \ 316 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 317 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 318 | && printf "load mock test.mock\ninspect\nexit" \ 319 | | metacall \ 320 | | grep -e 'function three_str(a_str, b_str, c_str)' 321 | 322 | # Test install Alpine without root and curl 323 | FROM alpine_user AS test_alpine_user_curl 324 | 325 | RUN curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | sh \ 326 | && metacall /test/script.js | grep '123456' \ 327 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 328 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 329 | && printf "load mock test.mock\ninspect\nexit" \ 330 | | metacall \ 331 | | grep -e 'function three_str(a_str, b_str, c_str)' 332 | 333 | # Test install Alpine without root and wget 334 | FROM alpine_user AS test_alpine_user_wget 335 | 336 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh \ 337 | && metacall /test/script.js | grep '123456' \ 338 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 339 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 340 | && printf "load mock test.mock\ninspect\nexit" \ 341 | | metacall \ 342 | | grep -e 'function three_str(a_str, b_str, c_str)' 343 | 344 | # Test update Alpine 345 | FROM test_alpine_user_wget AS test_alpine_user_wget_update 346 | 347 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh \ 348 | | sh -s -- --update \ 349 | | grep 'MetaCall has been installed' 350 | 351 | # Test uninstall Alpine 352 | FROM test_alpine_user_wget AS test_alpine_user_wget_uninstall 353 | 354 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh \ 355 | | sh -s -- --uninstall \ 356 | && [ ! -f "/usr/local/bin/metacall" ] 357 | 358 | # BusyBox Base 359 | FROM busybox:stable-uclibc AS test_busybox 360 | 361 | ENV METACALL_INSTALL_DEBUG=1 362 | 363 | # Busybox wget fails with self signed certificates so we avoid the tests 364 | FROM test_busybox AS busybox_fail_certificates_local 365 | 366 | # Test install BusyBox fail due to lack of SSL implementation in wget (if it fails, then the test passes) 367 | FROM test_busybox AS busybox_fail_certificates_remote 368 | 369 | RUN wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh \ 370 | || if [ $? -ne 0 ]; then exit 0; else exit 1; fi 371 | 372 | FROM busybox_fail_${METACALL_INSTALL_CERTS} AS test_busybox_fail 373 | 374 | # BusyBox Base (with sources) 375 | FROM test_busybox AS test_busybox_base 376 | 377 | COPY test/ /test/ 378 | 379 | # Busybox wget fails with self signed certificates so we avoid the tests 380 | FROM test_busybox_base AS busybox_without_certificates_local 381 | FROM busybox_without_certificates_local AS busybox_uninstall_without_certificates_local 382 | 383 | # Test install BusyBox without certificates 384 | FROM test_busybox_base AS busybox_without_certificates_remote 385 | 386 | RUN wget --no-check-certificate -O - https://raw.githubusercontent.com/metacall/install/master/install.sh \ 387 | | sh -s -- --no-check-certificate \ 388 | && sh /usr/local/bin/metacall /test/script.js | grep '123456' \ 389 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 390 | && metacall faas --version | grep -e '^v.*\..*\..*' \ 391 | && printf "load mock test.mock\ninspect\nexit" \ 392 | | metacall \ 393 | | grep -e 'function three_str(a_str, b_str, c_str)' 394 | 395 | # Test uninstall BusyBox without certificates 396 | FROM busybox_without_certificates_remote AS busybox_uninstall_without_certificates_remote 397 | 398 | RUN wget --no-check-certificate -O - https://raw.githubusercontent.com/metacall/install/master/install.sh \ 399 | | sh -s -- --no-check-certificate --uninstall \ 400 | && [ ! -f "/usr/local/bin/metacall" ] 401 | 402 | # Test install BusyBox 403 | FROM busybox_without_${METACALL_INSTALL_CERTS} AS test_busybox_without_certificates 404 | 405 | # Test uninstall BusyBox 406 | FROM busybox_uninstall_without_${METACALL_INSTALL_CERTS} AS test_busybox_uninstall_without_certificates 407 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016-2024 Vicente Eduardo Ferrer Garcia 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | METACALL 3 |

MetaCall Polyglot Runtime

4 |
5 | 6 | # Abstract 7 | 8 | Cross-platform set of scripts to install MetaCall Core infrastructure. For advanced install information, [check the documentation](https://github.com/metacall/core/blob/develop/docs/README.md#41-installation). 9 | 10 | # Install 11 | 12 | The following scripts are provided in order to install MetaCall: 13 | - [install.sh](https://raw.githubusercontent.com/metacall/install/master/install.sh) `bash or zsh | Linux or MacOS` 14 | 15 | - [install.ps1](https://raw.githubusercontent.com/metacall/install/master/install.ps1) `PowerShell | Windows` 16 | 17 | In order to install MetaCall in one line, curl or wget or powershell can be used: 18 | - `curl`: 19 | ```sh 20 | curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | sh 21 | ``` 22 | - `wget`: 23 | ```sh 24 | wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh 25 | ``` 26 | - `powershell`: 27 | ```powershell 28 | powershell -NoProfile -ExecutionPolicy unrestricted -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; &([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://raw.githubusercontent.com/metacall/install/master/install.ps1')))" 29 | ``` 30 | 31 | ## Install Linux or MacOS 32 | 33 | Additional parameters for the install script: 34 | 35 | - `--update`: Updates automatically MetaCall if it is already installed without asking to the user. 36 | - `--uninstall`: Uninstalls MetaCall if it is already installed without asking to the user. Overwrites the update command. 37 | - `--docker-install`: Runs Docker installation overwriting Docker fallback option over binary installation. 38 | - `--no-check-certificate`: When running binary installation (the default one), disables checking certificates when downloading the tarball. Useful for environments where there is not certificates, but insecure. 39 | - `--no-docker-fallback`: When running binary installation (the default one), disables Docker installation as fallback if the binary installation fails. 40 | - `--from-path `: Installs MetaCall from specific path, the `` points to a previously download tarball located in your file system. 41 | 42 | Example usage: 43 | 44 | - Install with `curl` without checking certificates and without docker fallback: 45 | ```sh 46 | curl --insecure -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | sh -s -- --no-check-certificate --no-docker-fallback 47 | ``` 48 | 49 | - Install with `wget` using Docker installer: 50 | ```sh 51 | wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh -s -- --docker-install 52 | ``` 53 | 54 | - Install with `wget` from a existing tarball located at `/root/downloads/metacall-tarball-linux-amd64.tar.gz`: 55 | ```sh 56 | wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh -s -- --from-path /root/downloads/metacall-tarball-linux-amd64.tar.gz 57 | ``` 58 | 59 | - Install `metacall` in a BusyBox without certificates: 60 | ```sh 61 | wget --no-check-certificate -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh -s -- --no-check-certificate 62 | ``` 63 | 64 | ## Install Windows 65 | 66 | Additional parameters for the install script: 67 | 68 | - `-InstallDir `: Defines a custom folder in order to install MetaCall in, otherwise it uses `%LocalAppData%\MetaCall` by default. 69 | - `-Version `: Version of the tarball to be downloaded. Versions are available [here](https://github.com/metacall/distributable-windows/releases). Uses latest version by default. 70 | - `-FromPath `: Install MetaCall from an existing distributable tarball, path must point to a tarball downloaded from [releases](https://github.com/metacall/distributable-windows/releases). 71 | 72 | Example usage: 73 | 74 | - Install tarball version `v0.1.0` into `D:\metacall`: 75 | ```powershell 76 | powershell -NoProfile -ExecutionPolicy unrestricted -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; &([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://raw.githubusercontent.com/metacall/install/master/install.ps1'))) -InstallDir 'D:\metacall' -Version '0.1.0'" 77 | ``` 78 | 79 | # Testing 80 | 81 | ### Linux / MacOS 82 | 83 | Requires docker to be installed. 84 | 85 | ```sh 86 | git clone https://github.com/metacall/install.git metacall-install 87 | cd metacall-install 88 | ./test.sh 89 | ``` 90 | 91 | ### Windows 92 | 93 | Windows does not include a test script yet, but you can use `install.ps1` script for testing yourself on your computer. 94 | 95 | ```sh 96 | git clone https://github.com/metacall/install.git metacall-install 97 | cd metacall-install 98 | powershell -NoProfile -ExecutionPolicy unrestricted ./install.ps1 99 | ``` 100 | 101 | # Troubleshooting 102 | Sometimes the domain _raw.githubusercontent.com_ maybe blocked by your ISP. Due to this, you may not be able to install metacall directly from previous commands. In that case, you may clone this repo and directly run [install.sh](https://github.com/metacall/install/blob/master/install.sh) for Linux and run [install.ps1](https://github.com/metacall/install/blob/master/install.ps1) for Windows. 103 | -------------------------------------------------------------------------------- /install.ps1: -------------------------------------------------------------------------------- 1 | # MetaCall Install Script by Parra Studios 2 | # Cross-platform set of scripts to install MetaCall infrastructure. 3 | # 4 | # Copyright (C) 2016 - 2024 Vicente Eduardo Ferrer Garcia 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | <# 19 | .SYNOPSIS 20 | Installs MetaCall CLI 21 | .DESCRIPTION 22 | MetaCall is a extensible, embeddable and interoperable cross-platform polyglot runtime. It supports NodeJS, Vanilla JavaScript, TypeScript, Python, Ruby, C#, Java, WASM, Go, C, C++, Rust, D, Cobol and more. 23 | .PARAMETER Version 24 | Default: latest 25 | Version of the tarball to be downloaded. Versions are available here: https://github.com/metacall/distributable-windows/releases. 26 | Possible values are: 27 | - latest - most latest build 28 | - 3-part version in a format A.B.C - represents specific version of build 29 | examples: 0.2.0, 0.1.0, 0.0.22 30 | .PARAMETER InstallDir 31 | Default: %LocalAppData%\MetaCall 32 | Path to where to install MetaCall. Note that binaries will be placed directly in a given directory. 33 | .PARAMETER FromPath 34 | Default: $null 35 | Path to the tarball to be installed. If specified, this parameter will override the Version parameter. 36 | .PARAMETER Uninstall 37 | Removes MetaCall from the specified installation directory and clears its entry from the PATH environment variable. 38 | If this parameter is specified, the script will perform an uninstallation rather than an installation. 39 | #> 40 | 41 | [cmdletbinding()] 42 | param( 43 | [string]$InstallDir="", 44 | [string]$Version="latest", 45 | [string]$FromPath=$null, 46 | [switch]$Uninstall=$false 47 | ) 48 | 49 | Set-StrictMode -Version Latest 50 | $ErrorActionPreference="Stop" 51 | $ProgressPreference="SilentlyContinue" 52 | 53 | function Print-With-Fallback([string]$Message) { 54 | try { 55 | Write-Host "$Message" 56 | } catch { 57 | Write-Output "$Message" 58 | } 59 | } 60 | 61 | function Print-Title([string]$Message) { 62 | Print-With-Fallback "$Message`n" 63 | } 64 | 65 | function Print-Info([string]$Message) { 66 | Print-With-Fallback "$([char]0x25B7) $Message" 67 | } 68 | 69 | function Print-Success([string]$Message) { 70 | Print-With-Fallback "$([char]0x2714) $Message" 71 | } 72 | 73 | function Print-Warning([string]$Message) { 74 | Print-With-Fallback "$([char]0x26A0) $Message" 75 | } 76 | 77 | function Print-Error([string]$Message) { 78 | Print-With-Fallback "$([char]0x2718) $Message" 79 | } 80 | 81 | function Print-Debug([string]$Message) { 82 | if ($env:METACALL_INSTALL_DEBUG) { 83 | Print-With-Fallback "$([char]0x2699) $Message" 84 | } 85 | } 86 | 87 | function Get-Machine-Architecture() { 88 | # On PS x86, PROCESSOR_ARCHITECTURE reports x86 even on x64 systems. 89 | # To get the correct architecture, we need to use PROCESSOR_ARCHITEW6432. 90 | # PS x64 doesn't define this, so we fall back to PROCESSOR_ARCHITECTURE. 91 | # Possible values: amd64, x64, x86, arm64, arm 92 | 93 | if( $env:PROCESSOR_ARCHITEW6432 -ne $null ) 94 | { 95 | return $env:PROCESSOR_ARCHITEW6432 96 | } 97 | 98 | return $env:PROCESSOR_ARCHITECTURE 99 | } 100 | 101 | function Get-CLI-Architecture() { 102 | $Architecture = $(Get-Machine-Architecture) 103 | switch ($Architecture.ToLowerInvariant()) { 104 | { ($_ -eq "amd64") -or ($_ -eq "x64") } { return "x64" } 105 | # TODO: 106 | # { $_ -eq "x86" } { return "x86" } 107 | # { $_ -eq "arm" } { return "arm" } 108 | # { $_ -eq "arm64" } { return "arm64" } 109 | default { throw "Architecture '$Architecture' not supported. If you are interested in this platform feel free to contribute to https://github.com/metacall/distributable-windows" } 110 | } 111 | } 112 | 113 | function Get-User-Share-Path() { 114 | $InstallRoot = $env:METACALL_INSTALL_DIR 115 | if (!$InstallRoot) { 116 | $InstallRoot = "$env:LocalAppData\MetaCall" 117 | } 118 | return $InstallRoot 119 | } 120 | 121 | function Resolve-Installation-Path([string]$InstallDir) { 122 | if ($InstallDir -eq "") { 123 | return Get-User-Share-Path 124 | } 125 | return $InstallDir 126 | } 127 | 128 | function Get-RedirectedUri { 129 | <# 130 | .SYNOPSIS 131 | Gets the real download URL from the redirection. 132 | .DESCRIPTION 133 | Used to get the real URL for downloading a file, this will not work if downloading the file directly. 134 | .EXAMPLE 135 | Get-RedirectedURL -URL "https://download.mozilla.org/?product=firefox-latest&os=win&lang=en-US" 136 | .PARAMETER URL 137 | URL for the redirected URL to be un-obfuscated 138 | .NOTES 139 | Code from: Redone per issue #2896 in core https://github.com/PowerShell/PowerShell/issues/2896 140 | #> 141 | 142 | [CmdletBinding()] 143 | param ( 144 | [Parameter(Mandatory = $true)] 145 | [string]$Uri 146 | ) 147 | process { 148 | do { 149 | try { 150 | $Request = Invoke-WebRequest -UseBasicParsing -Method Head -Uri $Uri 151 | if ($Request.BaseResponse.ResponseUri -ne $null) { 152 | # This is for Powershell 5 153 | $RedirectUri = $Request.BaseResponse.ResponseUri 154 | } 155 | elseif ($Request.BaseResponse.RequestMessage.RequestUri -ne $null) { 156 | # This is for Powershell core 157 | $RedirectUri = $Request.BaseResponse.RequestMessage.RequestUri 158 | } 159 | 160 | $Retry = $false 161 | } 162 | catch { 163 | if (($_.Exception.GetType() -match "HttpResponseException") -and ($_.Exception -match "302")) { 164 | $Uri = $_.Exception.Response.Headers.Location.AbsoluteUri 165 | $Retry = $true 166 | } 167 | else { 168 | throw $_ 169 | } 170 | } 171 | } while ($Retry) 172 | 173 | $RedirectUri 174 | } 175 | } 176 | 177 | function Resolve-Version([string]$Version) { 178 | if ($Version.ToLowerInvariant() -eq "latest") { 179 | $LatestTag = $(Get-RedirectedUri "https://github.com/metacall/distributable-windows/releases/latest") 180 | return $LatestTag.Segments[$LatestTag.Segments.Count - 1] 181 | } else { 182 | return "v$Version" 183 | } 184 | } 185 | 186 | function Post-Install([string]$InstallRoot) { 187 | # Reinstall Python Pip to the latest version (needed in order to patch the python.exe location) 188 | $InstallLocation = Join-Path -Path $InstallRoot -ChildPath "metacall" 189 | $InstallPythonScript = @" 190 | setlocal 191 | set "PYTHONHOME=$($InstallLocation)\runtimes\python" 192 | set "PIP_TARGET=$($InstallLocation)\runtimes\python\Pip" 193 | set "PATH=$($InstallLocation)\runtimes\python;$($InstallLocation)\runtimes\python\Scripts" 194 | start "" "$($InstallLocation)\runtimes\python\python.exe" -m pip install --upgrade --force-reinstall pip 195 | endlocal 196 | "@ 197 | # PIP_TARGET here might be incorrect here, for more info check https://github.com/metacall/distributable-windows/pull/20 198 | $InstallPythonScriptOneLine = $($InstallPythonScript.Trim()).replace("`n", " && ") 199 | cmd /V /C "$InstallPythonScriptOneLine" 200 | 201 | # Install Additional Packages 202 | Install-Additional-Packages -InstallRoot $InstallRoot -Component "deploy" 203 | Install-Additional-Packages -InstallRoot $InstallRoot -Component "faas" 204 | 205 | # TODO: Replace in the files D:/ and D:\ 206 | } 207 | 208 | function Path-Install([string]$InstallRoot) { 209 | # Add safely MetaCall command to the PATH (and persist it) 210 | 211 | # To add folder containing metacall.bat to PATH 212 | $PersistedPaths = [Environment]::GetEnvironmentVariable('PATH', [EnvironmentVariableTarget]::User) -split ';' 213 | if ($PersistedPaths -notcontains $InstallRoot) { 214 | [Environment]::SetEnvironmentVariable('PATH', $env:PATH+";"+$InstallRoot, [EnvironmentVariableTarget]::User) 215 | } 216 | 217 | # To verify if PATH isn't already added 218 | $EnvPaths = $env:PATH -split ';' 219 | if ($EnvPaths -notcontains $InstallRoot) { 220 | $EnvPaths = $EnvPaths + $InstallRoot | where { $_ } 221 | $env:Path = $EnvPaths -join ';' 222 | } 223 | 224 | # Support for GitHub actions environment 225 | if ($env:GITHUB_ENV -ne $null) { 226 | echo "PATH=$env:PATH" >> $env:GITHUB_ENV 227 | } 228 | } 229 | 230 | function Path-Uninstall([string]$Path) { 231 | $PersistedPaths = [Environment]::GetEnvironmentVariable('PATH', [EnvironmentVariableTarget]::User) -split ';' 232 | if ($PersistedPaths -contains $Path) { 233 | $PersistedPaths = $PersistedPaths | where { $_ -and $_ -ne $Path } 234 | [Environment]::SetEnvironmentVariable('PATH', $PersistedPaths -join ';', [EnvironmentVariableTarget]::User) 235 | } 236 | 237 | $EnvPaths = $env:PATH -split ';' 238 | 239 | if ($EnvPaths -contains $Path) { 240 | $EnvPaths = $EnvPaths | where { $_ -and $_ -ne $Path } 241 | $env:Path = $EnvPaths -join ';' 242 | } 243 | } 244 | 245 | function Install-Tarball([string]$InstallDir, [string]$Version) { 246 | Print-Title "MetaCall Binary Installation." 247 | 248 | $InstallRoot = Resolve-Installation-Path $InstallDir 249 | $InstallOutput = Join-Path -Path $InstallRoot -ChildPath "metacall-tarball-win.zip" 250 | 251 | # Delete directory contents if any 252 | if (Test-Path $InstallRoot) { 253 | Remove-Item -Recurse -Force $InstallRoot | Out-Null 254 | } 255 | 256 | Print-Debug "Install MetaCall in folder: $InstallRoot" 257 | 258 | # Create directory if it does not exist 259 | New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null 260 | 261 | if (!$FromPath) { 262 | Print-Info "Downloading tarball." 263 | 264 | $InstallVersion = Resolve-Version $Version 265 | $InstallArchitecture = Get-CLI-Architecture 266 | $DownloadUri = "https://github.com/metacall/distributable-windows/releases/download/$InstallVersion/metacall-tarball-win-$InstallArchitecture.zip" 267 | 268 | # Download the tarball 269 | Invoke-WebRequest -Uri $DownloadUri -OutFile $InstallOutput 270 | 271 | Print-Success "Tarball downloaded." 272 | } else { 273 | # Copy the tarball from the path 274 | Copy-Item -Path $FromPath -Destination $InstallOutput 275 | } 276 | 277 | Print-Info "Uncompressing tarball." 278 | 279 | # Unzip the tarball 280 | Expand-Archive -Path $InstallOutput -DestinationPath $InstallRoot -Force 281 | 282 | Print-Success "Tarball extracted correctly." 283 | 284 | # Delete the tarball 285 | Remove-Item -Force $InstallOutput | Out-Null 286 | 287 | Print-Info "Running post-install scripts." 288 | 289 | # Run post install scripts 290 | Post-Install $InstallRoot 291 | 292 | Print-Info "Adding MetaCall to PATH." 293 | 294 | # Add MetaCall CLI to PATH 295 | Path-Install $InstallRoot 296 | 297 | Print-Success "MetaCall installed successfully." 298 | } 299 | 300 | function Set-NodePath { 301 | param ( 302 | [string]$NodePath, 303 | [string]$FilePath 304 | ) 305 | 306 | if (-not (Test-Path $FilePath)) { 307 | Print-Error "Failed to set up an additional package, the file $FilePath does not exist." 308 | return 309 | } 310 | 311 | $Content = Get-Content -Path $FilePath 312 | 313 | Print-Debug "Replace $FilePath content:`n$Content" 314 | 315 | $Content = $Content -replace '%dp0%\\node.exe', $NodePath 316 | $Content = $Content -replace '""', '"' 317 | 318 | Print-Debug "With new content:`n$Content" 319 | 320 | Set-Content -Path $FilePath -Value $Content 321 | } 322 | 323 | function Install-Additional-Packages { 324 | param ( 325 | [string]$InstallRoot, 326 | [string]$Component 327 | ) 328 | 329 | $ComponentDir = Join-Path -Path $InstallRoot -ChildPath "deps\$Component" 330 | 331 | if (-not (Test-Path $ComponentDir)) { 332 | New-Item -ItemType Directory -Force -Path $ComponentDir | Out-Null 333 | } 334 | 335 | Print-Info "Installing '$Component' additional package." 336 | 337 | $NodePath = Join-Path -Path $InstallRoot -ChildPath "metacall\runtimes\nodejs\node.exe" 338 | Invoke-Expression "npm install --global --prefix=`"$ComponentDir`" @metacall/$Component" 339 | Set-NodePath -NodePath $NodePath -FilePath "$ComponentDir\metacall-$Component.cmd" 340 | 341 | Print-Success "Package '$Component' has been installed." 342 | } 343 | 344 | function Uninstall([string]$InstallDir) { 345 | Print-Title "MetaCall Uninstallation" 346 | 347 | $InstallRoot = Resolve-Installation-Path $InstallDir 348 | 349 | if (-not (Test-Path $InstallRoot)) { 350 | Print-Error "Failed to uninstall MetaCall, the folder $InstallRoot does not exist." 351 | return 352 | } 353 | 354 | Print-Info "Removing MetaCall files." 355 | 356 | # Delete MetaCall files from the install directory 357 | Remove-Item -Recurse -Force $InstallRoot 358 | 359 | if (-not (Test-Path $InstallRoot)) { 360 | Print-Debug "MetaCall files removed from: $InstallRoot successfully" 361 | } 362 | 363 | Print-Info "Removing MetaCall from PATH." 364 | 365 | # Call the Path-Uninstall function to remove from PATH 366 | Path-Uninstall $InstallRoot 367 | 368 | Print-Success "MetaCall uninstallation completed." 369 | } 370 | 371 | if ($Uninstall) { 372 | # Uninstall the metacall and remove path 373 | Uninstall $InstallDir 374 | } else { 375 | # Install the tarball and post scripts 376 | Install-Tarball $InstallDir $Version 377 | } 378 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # MetaCall Install Script by Parra Studios 4 | # Cross-platform set of scripts to install MetaCall infrastructure. 5 | # 6 | # Copyright (C) 2016 - 2024 Vicente Eduardo Ferrer Garcia 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | 20 | if [ -n "${METACALL_INSTALL_DEBUG:-}" ]; then 21 | set -euxo pipefail 22 | else 23 | set -eu 24 | fi 25 | 26 | # Program options 27 | OPT_DOCKER_INSTALL=0 28 | OPT_NO_CHECK_CERTIFICATE=0 29 | OPT_NO_DOCKER_FALLBACK=0 30 | OPT_UPDATE=0 31 | OPT_UNINSTALL=0 32 | OPT_FROM_PATH=0 33 | OPT_FROM_PATH_TARGET="" 34 | 35 | # Program commands 36 | CMD_DOWNLOAD="" 37 | CMD_SHEBANG="" 38 | CMD_SUDO="" 39 | 40 | # Platform dependant variables 41 | PLATFORM_OS="" 42 | PLATFORM_ARCH="" 43 | PLATFORM_PREFIX="" 44 | PLATFORM_BIN="" 45 | 46 | # Check for command line arguments 47 | while [ $# -ne 0 ] 48 | do 49 | if [ "$1" = '--docker-install' ]; then 50 | OPT_DOCKER_INSTALL=1 51 | fi 52 | if [ "$1" = '--no-check-certificate' ]; then 53 | OPT_NO_CHECK_CERTIFICATE=1 54 | fi 55 | if [ "$1" = '--no-docker-fallback' ]; then 56 | OPT_NO_DOCKER_FALLBACK=1 57 | fi 58 | if [ "$1" = '--update' ]; then 59 | OPT_UPDATE=1 60 | fi 61 | if [ "$1" = '--uninstall' ]; then 62 | OPT_UNINSTALL=1 63 | fi 64 | if [ "$1" = '--from-path' ]; then 65 | OPT_FROM_PATH=1 66 | shift 67 | OPT_FROM_PATH_TARGET="$1" 68 | fi 69 | # Get the next argument 70 | shift 71 | done 72 | 73 | # Check if program exists 74 | program() { 75 | command -v $1 >/dev/null 2>&1 76 | } 77 | 78 | # List of colors 79 | bold="" 80 | normal="" 81 | black="" 82 | red="" 83 | green="" 84 | yellow="" 85 | blue="" 86 | magenta="" 87 | cyan="" 88 | white="" 89 | 90 | # Set up colors 91 | if program tput; then 92 | ncolors=$(tput colors 2>/dev/null || echo) 93 | if [ -n "$ncolors" ] && [ "$ncolors" -ge 8 ]; then 94 | bold="$(tput bold || echo)" 95 | normal="$(tput sgr0 || echo)" 96 | black="$(tput setaf 0 || echo)" 97 | red="$(tput setaf 1 || echo)" 98 | green="$(tput setaf 2 || echo)" 99 | yellow="$(tput setaf 3 || echo)" 100 | blue="$(tput setaf 4 || echo)" 101 | magenta="$(tput setaf 5 || echo)" 102 | cyan="$(tput setaf 6 || echo)" 103 | white="$(tput setaf 7 || echo)" 104 | fi 105 | fi 106 | 107 | # Title message 108 | title() { 109 | printf "%b\n\n" "${normal:-}${bold:-}$@${normal:-}" 110 | } 111 | 112 | # Warning message 113 | warning() { 114 | printf "%b\n" "${yellow:-}⚠️ $@${normal:-}" 115 | } 116 | 117 | # Error message 118 | err() { 119 | printf "%b\n" "${red:-}✘ $@${normal:-}" 120 | } 121 | 122 | # Print message 123 | print() { 124 | printf "%b\n" "${normal:-}▷ $@" 125 | } 126 | 127 | # Success message 128 | success() { 129 | printf "%b\n" "${green:-}✔️ $@${normal:-}" 130 | } 131 | 132 | # Debug message 133 | debug() { 134 | if [ -n "${METACALL_INSTALL_DEBUG:-}" ]; then 135 | printf "%b\n" "${normal:-}⚙ $@" 136 | fi 137 | } 138 | 139 | # Ask message 140 | ask() { 141 | while true; do 142 | printf "${normal:-}▷ $@? [Y/n] " 143 | read -r yn < /dev/tty 144 | case $yn in 145 | [Yy]* ) break;; 146 | [Nn]* ) exit 1;; 147 | * ) warning "Please answer yes [Yy] or no [Nn].";; 148 | esac 149 | done 150 | } 151 | 152 | # Check if a list of programs exist or aborts 153 | programs_required() { 154 | for prog in "$@"; do 155 | if ! program ${prog}; then 156 | err "The program '${prog}' is not found, it is required to run the installer. Aborting installation." 157 | exit 1 158 | fi 159 | done 160 | } 161 | 162 | # Check if at least one program exists in the list or aborts 163 | programs_required_one() { 164 | for prog in "$@"; do 165 | if program ${prog}; then 166 | echo "${prog}" 167 | return 168 | fi 169 | done 170 | } 171 | 172 | # Find proper shebang for the launcher script 173 | find_shebang() { 174 | # Check common shells 175 | local sh_program=$(programs_required_one bash dash sh) 176 | 177 | if [ -z "${sh_program:-}" ]; then 178 | err "None of the following programs are installed: 'bash' 'dash' 'sh'. One of them is required at least to find the shell. Aborting installation." 179 | exit 1 180 | fi 181 | 182 | # Detect where is the 'env' found in order to set properly the shebang 183 | local env_program=$(programs_required_one env) 184 | 185 | if [ -z "${env_program:-}" ]; then 186 | CMD_SHEBANG="${env_program} ${sh_program}" 187 | else 188 | # Set up shebang command by default 189 | CMD_SHEBANG="/usr/bin/env ${sh_program}" 190 | fi 191 | } 192 | 193 | # Detect sudo or run with root 194 | find_sudo() { 195 | if ! program sudo && [ $(id -u) -ne 0 ]; then 196 | err "You need either having sudo installed or running this script as root. Aborting installation." 197 | exit 1 198 | fi 199 | 200 | if [ $(id -u) -ne 0 ]; then 201 | CMD_SUDO="sudo" 202 | fi 203 | } 204 | 205 | # Check all dependencies 206 | dependencies() { 207 | print "Checking system dependencies." 208 | 209 | # Check if required programs are installed 210 | programs_required uname tar grep echo printf rm id head chmod chown ln tee touch read 211 | 212 | # Check if download programs are installed 213 | if [ $OPT_FROM_PATH -eq 0 ]; then 214 | programs_required tail awk rev cut 215 | 216 | local download_program=$(programs_required_one curl wget) 217 | 218 | if [ -z "${download_program}" ]; then 219 | err "None of the following programs are installed: curl wget. One of them is required at least to download the tarball. Aborting installation." 220 | exit 1 221 | fi 222 | 223 | # Set up download command 224 | CMD_DOWNLOAD="${download_program}" 225 | fi 226 | 227 | # Locate shebang 228 | find_shebang 229 | 230 | # Check for sudo permissions 231 | find_sudo 232 | 233 | success "Dependencies satisfied." 234 | } 235 | 236 | # Get operative system name 237 | operative_system() { 238 | local os=$(uname) 239 | 240 | # TODO: Implement other operative systems (FreeBSD, ...) 241 | case ${os} in 242 | Darwin) 243 | PLATFORM_OS="macos" 244 | if [ "${PLATFORM_ARCH}" = "arm64" ]; then 245 | PLATFORM_PREFIX="/opt/homebrew" 246 | elif [ "${PLATFORM_ARCH}" = "amd64" ]; then 247 | PLATFORM_PREFIX="/usr/local" 248 | fi 249 | PLATFORM_BIN="${PLATFORM_PREFIX}/bin" 250 | return 251 | ;; 252 | # FreeBSD) 253 | # PLATFORM_OS="freebsd" 254 | # return 255 | # ;; 256 | Linux) 257 | PLATFORM_OS="linux" 258 | PLATFORM_PREFIX="/gnu" 259 | PLATFORM_BIN="/usr/local/bin" 260 | return 261 | ;; 262 | esac 263 | 264 | err "Operative System detected (${os}) is not supported." \ 265 | " Please, refer to https://github.com/metacall/install/issues and create a new issue." \ 266 | " Aborting installation." 267 | exit 1 268 | } 269 | 270 | # Get architecture name 271 | architecture() { 272 | local arch=$(uname -m) 273 | 274 | # TODO: Implement other architectures in metacall/distributable-linux (armv7l, aarch64, ...) 275 | case ${arch} in 276 | x86_64) 277 | PLATFORM_ARCH="amd64" 278 | return 279 | ;; 280 | arm64) 281 | PLATFORM_ARCH="arm64" 282 | return 283 | ;; 284 | esac 285 | 286 | err "Architecture detected (${arch}) is not supported." \ 287 | " Please, refer to https://github.com/metacall/install/issues and create a new issue." \ 288 | " Aborting installation." 289 | exit 1 290 | } 291 | 292 | # Detect platform details 293 | platform() { 294 | # Detect operative system and architecture 295 | print "Detecting Operative System and Architecture." 296 | 297 | # Get the operative system and architecture 298 | architecture 299 | operative_system 300 | 301 | success "Operative System (${PLATFORM_OS}) and Architecture (${PLATFORM_ARCH}) detected." 302 | } 303 | 304 | # Get download url from tag 305 | download_url() { 306 | local version=$(printf "$1" | rev | cut -d '/' -f1 | rev) 307 | printf "https://github.com/metacall/distributable-${PLATFORM_OS}/releases/download/${version}/metacall-tarball-${PLATFORM_OS}-${PLATFORM_ARCH}.tar.gz" 308 | } 309 | 310 | # Download tarball with cURL 311 | download_curl() { 312 | local tag_url=$(${CMD_DOWNLOAD} --retry 10 -f -sL -o /dev/null -w %{url_effective} "https://github.com/metacall/distributable-${PLATFORM_OS}/releases/latest") 313 | local final_url=$(download_url "${tag_url}") 314 | 315 | ${CMD_DOWNLOAD} --retry 10 -f --create-dirs -L ${final_url} --output "/tmp/metacall-tarball.tar.gz" || echo "true" 316 | } 317 | 318 | # Download tarball with wget 319 | download_wget() { 320 | local tag_url=$(${CMD_DOWNLOAD} --tries 10 -S -O /dev/null "https://github.com/metacall/distributable-${PLATFORM_OS}/releases/latest" 2>&1 | grep Location: | tail -n 1 | awk '{print $2}') 321 | local final_url=$(download_url "${tag_url}") 322 | 323 | ${CMD_DOWNLOAD} --tries 10 -O "/tmp/metacall-tarball.tar.gz" ${final_url} || echo "true" 324 | } 325 | 326 | # Download tarball 327 | download() { 328 | local download_func=download_${CMD_DOWNLOAD} 329 | 330 | print "Start to download the tarball." 331 | 332 | # Skip certificate checks 333 | if [ $OPT_NO_CHECK_CERTIFICATE -eq 1 ]; then 334 | local insecure_curl="--insecure" 335 | local insecure_wget="--no-check-certificate" 336 | CMD_DOWNLOAD="$CMD_DOWNLOAD $(eval echo -e \"\$insecure_$CMD_DOWNLOAD\")" 337 | fi 338 | 339 | # Download depending on the program selected 340 | local fail="$(eval echo -e \"\$\(${download_func}\)\")" 341 | 342 | if [ "${fail}" = "true" ]; then 343 | ${CMD_SUDO} rm -rf "/tmp/metacall-tarball.tar.gz" 344 | err "The tarball metacall-tarball-${PLATFORM_OS}-${PLATFORM_ARCH}.tar.gz could not be downloaded." \ 345 | " Please, refer to https://github.com/metacall/install/issues and create a new issue." \ 346 | " Aborting installation." 347 | exit 1 348 | fi 349 | 350 | success "Tarball downloaded." 351 | } 352 | 353 | # Extract the tarball (requires root or sudo) 354 | uncompress() { 355 | if [ $OPT_FROM_PATH -eq 1 ]; then 356 | local tmp="${OPT_FROM_PATH_TARGET}" 357 | else 358 | local tmp="/tmp/metacall-tarball.tar.gz" 359 | fi 360 | 361 | local share_dir="${PLATFORM_PREFIX}/share/metacall" 362 | local install_list="${share_dir}/metacall-binary-install.txt" 363 | local install_tmp_list="/tmp/metacall-binary-install.txt" 364 | 365 | print "Uncompress the tarball." 366 | 367 | # List the files inside the tar and store them into a txt for running 368 | # chown selectively and for uninstalling it later on, install files 369 | # that do not exist already in the system, this will allow to make the 370 | # installer idempotent, so later on we delete only our files 371 | ${CMD_SUDO} rm -rf ${install_tmp_list} 372 | 373 | # Disable debug info 374 | if [ -n "${METACALL_INSTALL_DEBUG:-}" ]; then 375 | set +x 376 | fi 377 | 378 | # The sed is needed in order to store properly the paths because they 379 | # are listed always with prefix ./ and we have to check with -e if they 380 | # are present as absoulte path / in the system, then we write them again with 381 | # the dot . so they are written as ./ for uncompressing them 382 | ${CMD_SUDO} tar -tf "${tmp}" | sed 's/^\.//' | while IFS= read -r file; do 383 | if [ ! -e "${file}" ]; then 384 | echo "${file}" >> ${install_tmp_list} 385 | fi 386 | done 387 | 388 | if [ -n "${METACALL_INSTALL_DEBUG:-}" ]; then 389 | set -x 390 | fi 391 | 392 | # Check if the file list was created properly 393 | if [ ! -f "${install_tmp_list}" ]; then 394 | err "The file list could not be created properly, this means that metacall was already installed but the command is not available. Aborting installation." 395 | ${CMD_SUDO} rm -rf "/tmp/metacall-tarball.tar.gz" 396 | exit 1 397 | fi 398 | 399 | # Give read write permissions for all 400 | ${CMD_SUDO} chmod 666 "${install_tmp_list}" 401 | 402 | # Uncompress the tarball. Use the install list to uncompress only the files that are new in the filesystem, 403 | # don't restore mtime (-m), don't restore user:group (-o) and avoid overwriting existing files (-k). 404 | local user="$(id -u)" 405 | local group="$(id -g)" 406 | ${CMD_SUDO} tar xzf "${tmp}" -m -o -k -C / 407 | 408 | # Check for valid uncompression 409 | if [ ! -e "${PLATFORM_PREFIX}" ]; then 410 | err "The tarball could not be uncompressed properly. Aborting installation." 411 | ${CMD_SUDO} rm -rf "/tmp/metacall-tarball.tar.gz" 412 | exit 1 413 | fi 414 | 415 | # Create shared directory 416 | if [ ! -d "${share_dir}" ]; then 417 | ${CMD_SUDO} mkdir -p ${share_dir} 418 | ${CMD_SUDO} chmod 775 ${share_dir} 419 | fi 420 | 421 | # Move the install list to the share directory 422 | ${CMD_SUDO} mv "${install_tmp_list}" "${install_list}" 423 | 424 | # TODO: Tag with a timestamp the files in order to uninstall them later on 425 | # only if they have not been modified since the install time 426 | 427 | success "Tarball uncompressed successfully." 428 | 429 | # In Linux, add links for certificates 430 | if [ "${PLATFORM_OS}" = "linux" ]; then 431 | local openssl_base="${PLATFORM_PREFIX}/store/`ls ${PLATFORM_PREFIX}/store/ | grep openssl | head -n 1`/share" 432 | local openssl_dir="${openssl_base}/`ls ${openssl_base} | grep openssl`" 433 | local openssl_cert_dir="${openssl_dir}/certs" 434 | local openssl_cert_file="${openssl_dir}/cert.pem" 435 | local nss_cert_dir="${PLATFORM_PREFIX}/etc/ssl/certs" 436 | local nss_cert_file="${PLATFORM_PREFIX}/etc/ssl/certs/ca-certificates.crt" 437 | 438 | print "Linking certificates: ${openssl_cert_dir} => ${nss_cert_dir}" 439 | print "Linking certificate CA: ${openssl_cert_file} => ${nss_cert_file}" 440 | 441 | ${CMD_SUDO} rmdir ${openssl_cert_dir} 442 | ${CMD_SUDO} ln -s ${nss_cert_dir} ${openssl_cert_dir} 443 | ${CMD_SUDO} ln -s ${nss_cert_file} ${openssl_cert_file} 444 | 445 | # Store the certificate links in the install list 446 | echo "${openssl_cert_dir}" | ${CMD_SUDO} tee -a "${install_list}" > /dev/null 447 | echo "${openssl_cert_file}" | ${CMD_SUDO} tee -a "${install_list}" > /dev/null 448 | 449 | # In MacOS, create a binary list for allowing 'metacall npm ...' and other commands 450 | elif [ "${PLATFORM_OS}" = "macos" ]; then 451 | local bin_list="${share_dir}/metacall-binary-install-bin.txt" 452 | 453 | # Get the binary files installed, use the tar directly because if we use the ${install_list} it is 454 | # going to exclude the binaries that were already installed, also do not include metacall itself 455 | ${CMD_SUDO} tar -tf "${tmp}" | sed 's/^\.//' \ 456 | | grep -E "^${PLATFORM_BIN}/.+" \ 457 | | grep -v "^${PLATFORM_BIN}/metacall" \ 458 | | ${CMD_SUDO} tee "${bin_list}" > /dev/null 459 | 460 | # Give read write permissions for all 461 | ${CMD_SUDO} chmod 666 "${bin_list}" 462 | 463 | # Add the bin list to the install list, this helper file will allow to handle package managers from metacall 464 | echo "${bin_list}" | ${CMD_SUDO} tee -a "${install_list}" > /dev/null 465 | fi 466 | 467 | # Clean the tarball 468 | if [ $OPT_FROM_PATH -eq 0 ]; then 469 | print "Cleaning the tarball." 470 | ${CMD_SUDO} rm -rf "${tmp}" 471 | success "Tarball cleaned successfully." 472 | fi 473 | } 474 | 475 | # Install the CLI 476 | cli() { 477 | print "Installing the Command Line Interface shortcut." 478 | 479 | if [ "${PLATFORM_OS}" = "linux" ]; then 480 | # Write shell script pointing to MetaCall CLI 481 | local pythonpath_base="${PLATFORM_PREFIX}/store/`ls ${PLATFORM_PREFIX}/store/ | grep python-3 | head -n 1`/lib" 482 | local pythonpath_dynlink="`ls -d ${pythonpath_base}/*/ | grep 'python3\.[0-9]*\/$'`lib-dynload" 483 | 484 | # Create folder and file 485 | ${CMD_SUDO} mkdir -p "${PLATFORM_BIN}/" 486 | ${CMD_SUDO} touch "${PLATFORM_BIN}/metacall" 487 | 488 | # Write the shebang 489 | printf "#!" | ${CMD_SUDO} tee "${PLATFORM_BIN}/metacall" > /dev/null 490 | echo "${CMD_SHEBANG}" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 491 | 492 | # MetaCall Environment 493 | echo "export LOADER_SCRIPT_PATH=\"\${LOADER_SCRIPT_PATH:-\`pwd\`}\"" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 494 | 495 | # Certificates 496 | echo "export GIT_SSL_FILE=\"${PLATFORM_PREFIX}/etc/ssl/certs/ca-certificates.crt\"" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 497 | echo "export GIT_SSL_CAINFO=\"${PLATFORM_PREFIX}/etc/ssl/certs/ca-certificates.crt\"" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 498 | 499 | # Locale 500 | echo "export GUIX_LOCPATH=\"${PLATFORM_PREFIX}/lib/locale\"" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 501 | echo "export LANG=\"en_US.UTF-8\"" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 502 | 503 | # Python 504 | echo "export PYTHONPATH=\"${pythonpath_base}:${pythonpath_dynlink}\"" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 505 | 506 | # Guix generated environment variables (TODO: Move all environment variables to metacall/distributable-linux) 507 | echo ". ${PLATFORM_PREFIX}/etc/profile" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 508 | 509 | # Set up command line 510 | echo "CMD=\`ls -a ${PLATFORM_PREFIX}/bin | grep \"\$1\" | head -n 1\`" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 511 | 512 | echo "if [ \"\${CMD}\" = \"\$1\" ]; then" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 513 | echo " if [ -z \"\${PATH-}\" ]; then export PATH=\"${PLATFORM_PREFIX}/bin\"; else PATH=\"${PLATFORM_PREFIX}/bin:\${PATH}\"; fi" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 514 | echo " \$@" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 515 | echo " exit \$?" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 516 | echo "fi" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 517 | 518 | # CLI 519 | echo "${PLATFORM_PREFIX}/bin/metacallcli \$@" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 520 | ${CMD_SUDO} chmod 775 "${PLATFORM_BIN}/metacall" 521 | 522 | elif [ "${PLATFORM_OS}" = "macos" ]; then 523 | local share_dir="${PLATFORM_PREFIX}/share/metacall" 524 | local install_list="${share_dir}/metacall-binary-install.txt" 525 | local bin_list="${share_dir}/metacall-binary-install-bin.txt" 526 | 527 | # Remove last line of the shell script for the CLI 528 | ${CMD_SUDO} sed -i '' -e '$d' "${PLATFORM_BIN}/metacall" 529 | 530 | # In case of having an argument 531 | echo "if [ \"\$1\" != \"\" ]; then" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 532 | 533 | # Set up command line 534 | echo " CMD=\"\$(grep \"${PLATFORM_BIN}/\$1\" \"${bin_list}\" | head -n 1)\"" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 535 | 536 | # If we find a binary on the list, execute it 537 | echo " if [ \"\${CMD}\" != \"\" ]; then" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 538 | echo " if [ -z \"\${PATH-}\" ]; then export PATH=\"${PLATFORM_BIN}\"; else PATH=\"${PLATFORM_BIN}:\${PATH}\"; fi" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 539 | echo " \$@" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 540 | echo " exit \$?" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 541 | echo " fi" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 542 | echo "fi" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 543 | 544 | # Execute the CLI 545 | echo "\${PREFIX}/metacallcli \$@" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 546 | fi 547 | 548 | success "CLI shortcut installed successfully." 549 | } 550 | 551 | binary_install() { 552 | # Show title 553 | title "MetaCall Self-Contained Binary Installer" 554 | 555 | # Check dependencies 556 | dependencies 557 | 558 | # Check platform 559 | platform 560 | 561 | if [ $OPT_FROM_PATH -eq 0 ]; then 562 | # Download tarball 563 | download 564 | else 565 | # Check if the tarball is correct 566 | if [ ! -f "$OPT_FROM_PATH_TARGET" ]; then 567 | err "The tarball $OPT_FROM_PATH_TARGET does not exist, exiting..." 568 | exit 1 569 | fi 570 | 571 | case "$OPT_FROM_PATH_TARGET" in 572 | *.tar.gz) 573 | # Valid format (noop) 574 | : 575 | ;; 576 | *.pkg) 577 | # Only valid in darwin 578 | if [ "${PLATFORM_OS}" != "macos" ]; then 579 | err "The tarball $OPT_FROM_PATH_TARGET has pkg format, and this is only valid on MacOS, exiting..." 580 | exit 1 581 | fi 582 | 583 | # TODO: Implement pkg for MacOS (https://superuser.com/a/525395) 584 | err "The tarball $OPT_FROM_PATH_TARGET has pkg format, and it is not implemented, use tar.gz instead for now, exiting..." 585 | exit 1 586 | ;; 587 | *) 588 | # Invalid format 589 | err "The tarball $OPT_FROM_PATH_TARGET has an invalid format, exiting..." 590 | exit 1 591 | ;; 592 | esac 593 | fi 594 | 595 | # Extract 596 | uncompress 597 | 598 | # Install CLI 599 | cli 600 | 601 | # Install additional dependencies 602 | additional_packages_install 603 | 604 | # Make metacall available into PATH 605 | path_install 606 | } 607 | 608 | docker_install() { 609 | # Show title 610 | title "MetaCall Docker Installer" 611 | 612 | # Check if Docker command is installed 613 | print "Checking Docker dependencies." 614 | 615 | # Dependencies 616 | programs_required docker echo chmod tee touch 617 | 618 | # Check platform 619 | platform 620 | 621 | # Locate shebang 622 | find_shebang 623 | 624 | # Pull MetaCall CLI Docker Image 625 | print "Pulling MetaCall CLI Image." 626 | 627 | if ! (docker pull metacall/cli:latest); then 628 | err "Docker image could not be pulled. Aborting installation." 629 | exit 1 630 | fi 631 | 632 | # Install Docker based CLI 633 | print "Installing the Command Line Interface shortcut." 634 | 635 | # Check for sudo permissions 636 | find_sudo 637 | 638 | local command="docker run --rm --network host -e \"LOADER_SCRIPT_PATH=/metacall/source\" -v \`pwd\`:/metacall/source -w /metacall/source -it metacall/cli \$@" 639 | 640 | # Write shell script wrapping the Docker run of MetaCall CLI image 641 | ${CMD_SUDO} mkdir -p "${PLATFORM_BIN}/" 642 | ${CMD_SUDO} touch "${PLATFORM_BIN}/metacall" 643 | printf '#!' | ${CMD_SUDO} tee "${PLATFORM_BIN}/metacall" > /dev/null 644 | echo "${CMD_SHEBANG}" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 645 | echo "${command}" | ${CMD_SUDO} tee -a "${PLATFORM_BIN}/metacall" > /dev/null 646 | ${CMD_SUDO} chmod 775 "${PLATFORM_BIN}/metacall" 647 | ${CMD_SUDO} chown $(id -u):$(id -g) "${PLATFORM_BIN}/metacall" 648 | 649 | # Make metacall available into PATH 650 | path_install 651 | } 652 | 653 | check_path_env() { 654 | # Check if the PATH contains the install path (${PLATFORM_BIN} aka /usr/local/bin on Linux), checks 4 cases: 655 | # 1) /usr/local/bin 656 | # 2) /usr/local/bin:/usr/bin 657 | # 3) /usr/bin:/usr/local/bin 658 | # 4) /usr/bin:/usr/local/bin:/bin 659 | echo "${PATH}" | grep -e "\(^\|:\)${PLATFORM_BIN}\(:\|$\)" 660 | } 661 | 662 | uninstall() { 663 | # Show title 664 | title "MetaCall Uninstall" 665 | 666 | # Check dependencies 667 | programs_required rm cat awk sort cut read readlink 668 | 669 | # Check platform 670 | platform 671 | 672 | # Check for sudo permissions 673 | find_sudo 674 | 675 | print "Deleting MetaCall binary installation, this operation may take a while." 676 | 677 | # Delete the launcher 678 | ${CMD_SUDO} rm -f "${PLATFORM_BIN}/metacall" 679 | 680 | # Delete shortcuts if any 681 | ${CMD_SUDO} rm -f "/etc/profile.d/metacall.sh" 682 | 683 | # Delete all the previously installed files 684 | local install_list="$(readlink -f "${PLATFORM_PREFIX}/share/metacall/metacall-binary-install.txt")" 685 | local install_tmp_list="/tmp/metacall-binary-install.txt" 686 | 687 | # Move install list to temp folder 688 | ${CMD_SUDO} mv "${install_list}" "${install_tmp_list}" 689 | 690 | # Disable debug info 691 | if [ -n "${METACALL_INSTALL_DEBUG:-}" ]; then 692 | set +x 693 | fi 694 | 695 | print "Deleting MetaCall symlinks." 696 | 697 | # First delete the symbolic links and get files and folders 698 | while IFS= read -r line; do 699 | # Reinterpret escaped unicode characters 700 | local path="$(printf "%b" "${line}")" 701 | 702 | # Delete symlink 703 | if [ -L "${path}" ]; then 704 | ${CMD_SUDO} rm -f "${path}" 705 | fi 706 | done < "${install_tmp_list}" 707 | 708 | print "Deleting MetaCall files." 709 | 710 | # Then delete the files 711 | while IFS= read -r line; do 712 | # Reinterpret escaped unicode characters 713 | local path="$(printf "%b" "${line}")" 714 | 715 | # Delete file 716 | if [ -f "${path}" ]; then 717 | ${CMD_SUDO} rm -f "${path}" 718 | fi 719 | done < "${install_tmp_list}" 720 | 721 | print "Deleting MetaCall folders." 722 | 723 | # Then delete the folders 724 | cat "${install_tmp_list}" | awk '{ print length, $0 }' | sort -r -n -s | cut -d ' ' -f2- | while IFS= read -r line; do 725 | # Reinterpret escaped unicode characters 726 | local path="$(printf "%b" "${line}")" 727 | 728 | # Delete folder only if it is empty 729 | if [ -d "${path}" ]; then 730 | if [ -n "${METACALL_INSTALL_DEBUG:-}" ]; then 731 | # Print debug information if the folder is not empty 732 | ${CMD_SUDO} rmdir "${path}" || (warning "Invalid file type '${path}', expected empty folder." && ls -la -R "${path}") 733 | else 734 | # Skip if the folder is not empty 735 | ${CMD_SUDO} rmdir "${path}" || true 736 | fi 737 | fi 738 | done 739 | 740 | if [ -n "${METACALL_INSTALL_DEBUG:-}" ]; then 741 | set -x 742 | fi 743 | 744 | # Remove the list itself 745 | ${CMD_SUDO} rm -f "${install_tmp_list}" 746 | } 747 | 748 | package_install() { 749 | local package_name="$1" 750 | local install_dir="${PLATFORM_PREFIX}/lib/node_modules" 751 | local bin_dir="${PLATFORM_PREFIX}/bin" 752 | local install_list="${PLATFORM_PREFIX}/share/metacall/metacall-binary-install.txt" 753 | 754 | # Create additional dependencies folder 755 | ${CMD_SUDO} mkdir -p "${install_dir}" 756 | ${CMD_SUDO} mkdir -p "${bin_dir}" 757 | 758 | # Get full paths 759 | local package_install_dir="$(readlink -f "${install_dir}")/${package_name}" 760 | local package_bin_dir="$(readlink -f "${bin_dir}")/${package_name}" 761 | 762 | # Install package 763 | ${CMD_SUDO} metacall npm install --global --prefix="${package_install_dir}" @metacall/${package_name} 764 | echo "#!${CMD_SHEBANG}" | ${CMD_SUDO} tee "${package_bin_dir}" > /dev/null 765 | echo "metacall node ${package_install_dir}/lib/node_modules/@metacall/${package_name}/dist/index.js \$@" | ${CMD_SUDO} tee -a "${package_bin_dir}" > /dev/null 766 | ${CMD_SUDO} chmod 775 "${package_bin_dir}" 767 | ${CMD_SUDO} chown $(id -u):$(id -g) "${package_bin_dir}" 768 | 769 | # Give permissions and ownership 770 | ${CMD_SUDO} chmod -R 775 "${package_install_dir}" 771 | ${CMD_SUDO} chown -R $(id -u):$(id -g) "${package_install_dir}" 772 | 773 | # Add the files to the install list 774 | ${CMD_SUDO} find "${package_install_dir}" | ${CMD_SUDO} tee -a "${install_list}" > /dev/null 775 | ${CMD_SUDO} echo "${package_bin_dir}" | ${CMD_SUDO} tee -a "${install_list}" > /dev/null 776 | 777 | # In MacOS, add package launcher to the binary list, so it can be found later on 778 | if [ "${PLATFORM_OS}" = "macos" ]; then 779 | local share_dir="${PLATFORM_PREFIX}/share/metacall" 780 | local bin_list="${share_dir}/metacall-binary-install-bin.txt" 781 | 782 | # Add the binary to the binary list without readlink, use the binary prefix instead 783 | echo "${bin_dir}/${package_name}" | ${CMD_SUDO} tee -a "${bin_list}" > /dev/null 784 | fi 785 | } 786 | 787 | additional_packages_install() { 788 | print "Installing additional dependencies." 789 | 790 | # Install Deploy 791 | package_install "deploy" 792 | 793 | # Install FaaS 794 | package_install "faas" 795 | 796 | success "Additional dependencies installed." 797 | } 798 | 799 | path_install() { 800 | debug "Checking if ${PLATFORM_BIN} is in PATH environment variable ($PATH)." 801 | 802 | local path="$(check_path_env)" 803 | 804 | # Check if ${PLATFORM_BIN} (aka /usr/local/bin in Linux) is in PATH 805 | if [ -z "${path}" ]; then 806 | # Add ${PLATFORM_BIN} to PATH 807 | echo "export PATH=\"\${PATH}:${PLATFORM_BIN}\"" | ${CMD_SUDO} tee "/etc/profile.d/metacall.sh" > /dev/null 808 | ${CMD_SUDO} mkdir -p /etc/profile.d/ 809 | ${CMD_SUDO} chmod 644 /etc/profile.d/metacall.sh 810 | 811 | warning "MetaCall install path is not present in PATH so we added it for you." \ 812 | " The command 'metacall' will be available in your subsequent terminal instances." \ 813 | " Run 'source /etc/profile' to make 'metacall' command available to your current terminal instance." 814 | fi 815 | } 816 | 817 | main() { 818 | if ! program metacall; then 819 | if [ $OPT_UPDATE -eq 1 ] || [ $OPT_UNINSTALL -eq 1 ]; then 820 | err "MetaCall is not installed." 821 | exit 1 822 | fi 823 | else 824 | # Skip asking for updates if the update flag is enabled 825 | if [ $OPT_UPDATE -eq 0 ] && [ $OPT_UNINSTALL -eq 0 ]; then 826 | # Check if the shell is interactive 827 | case $- in 828 | *i*) local interactive=1;; 829 | *) local interactive=0;; 830 | esac 831 | 832 | if [ $interactive -ne 0 ]; then 833 | # Ask for Docker fallback if we are in a terminal 834 | ask "MetaCall is already installed. Do you want to update it?" 835 | else 836 | warning "MetaCall is already installed." 837 | exit 0 838 | fi 839 | fi 840 | 841 | uninstall 842 | 843 | # Exit if the user only wants to uninstall 844 | if [ $OPT_UNINSTALL -eq 1 ]; then 845 | success "MetaCall has been successfully uninstalled." 846 | exit 0 847 | fi 848 | fi 849 | 850 | if [ $OPT_DOCKER_INSTALL -eq 1 ]; then 851 | # Run docker install 852 | docker_install 853 | else 854 | # TODO: Remember to do MacOS install fallback to brew in order to compile metacall 855 | # spctl --status 856 | 857 | # Run binary install 858 | if ! (binary_install); then 859 | # Exit if Docker fallback is disabled 860 | if [ $OPT_NO_DOCKER_FALLBACK -eq 1 ]; then 861 | err "Binary installation has failed and fallback to Docker installation is disabled, exiting..." 862 | exit 1 863 | fi 864 | 865 | # Required program for ask question to the user 866 | programs_required read 867 | 868 | # Check if the shell is interactive 869 | case $- in 870 | *i*) local interactive=1;; 871 | *) local interactive=0;; 872 | esac 873 | 874 | if [ $interactive -ne 0 ]; then 875 | # Ask for Docker fallback if we are in a terminal 876 | ask "Binary installation has failed, do you want to fallback to Docker installation" 877 | else 878 | # Run Docker fallback otherwise 879 | warning "Binary installation has failed, fallback to Docker installation." 880 | fi 881 | 882 | # On error, fallback to docker install 883 | docker_install 884 | fi 885 | fi 886 | 887 | # Show information 888 | success "MetaCall has been installed." \ 889 | " Run 'metacall' command for start the CLI and type help for more information about CLI commands." 890 | } 891 | 892 | # Run main 893 | main 894 | -------------------------------------------------------------------------------- /proxy/.dockerignore: -------------------------------------------------------------------------------- 1 | ** 2 | !nginx.conf 3 | -------------------------------------------------------------------------------- /proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # MetaCall Install Script by Parra Studios 3 | # Cross-platform set of scripts to install MetaCall infrastructure. 4 | # 5 | # Copyright (C) 2016 - 2024 Vicente Eduardo Ferrer Garcia 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | FROM nginx:alpine-slim AS proxy 21 | 22 | # Image descriptor 23 | LABEL copyright.name="Vicente Eduardo Ferrer Garcia" \ 24 | copyright.address="vic798@gmail.com" \ 25 | maintainer.name="Vicente Eduardo Ferrer Garcia" \ 26 | maintainer.address="vic798@gmail.com" \ 27 | vendor="MetaCall Inc." \ 28 | version="0.1" 29 | 30 | COPY install.sh /usr/share/nginx/html/ 31 | COPY proxy/nginx.conf /etc/nginx/ 32 | 33 | RUN apk add openssl \ 34 | && openssl req -x509 -nodes -days 365 -subj "/C=CA/ST=QC/O=Company, Inc./CN=raw.githubusercontent.com" \ 35 | -addext "subjectAltName=DNS:raw.githubusercontent.com" -newkey rsa:2048 \ 36 | -keyout /etc/ssl/private/nginx-selfsigned.key \ 37 | -out /etc/ssl/certs/nginx-selfsigned.crt \ 38 | && cat /etc/ssl/certs/nginx-selfsigned.crt >> /etc/ssl/certs/ca-certificates.crt 39 | 40 | USER root 41 | 42 | EXPOSE 80 43 | EXPOSE 443 44 | -------------------------------------------------------------------------------- /proxy/nginx.conf: -------------------------------------------------------------------------------- 1 | user root; 2 | worker_processes 1; 3 | error_log /var/log/nginx/error.log notice; 4 | pid /var/run/nginx.pid; 5 | 6 | events { 7 | worker_connections 1024; 8 | } 9 | 10 | http { 11 | sendfile on; 12 | keepalive_timeout 65; 13 | 14 | server { 15 | listen 80; 16 | listen [::]:80; 17 | server_name raw.githubusercontent.com; 18 | 19 | listen 443 ssl; 20 | listen [::]:443 ssl; 21 | ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; 22 | ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; 23 | 24 | location /metacall/install/master/install.sh { 25 | alias /usr/share/nginx/html/install.sh; 26 | types { 27 | application/x-sh sh; 28 | } 29 | default_type application/x-sh; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # MetaCall Install Script by Parra Studios 4 | # Cross-platform set of scripts to install MetaCall infrastructure. 5 | # 6 | # Copyright (C) 2016 - 2024 Vicente Eduardo Ferrer Garcia 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | 20 | set -exuo pipefail 21 | 22 | # Run with Buildkit 23 | export DOCKER_BUILDKIT=1 24 | 25 | # Get current root folder 26 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) 27 | 28 | # Get test list (any target prefixed by 'test_') 29 | TEST_LIST=$(cat Dockerfile | grep -v '^#' | grep 'AS test_' | awk '{print $4}') 30 | 31 | # Define default certificate setup 32 | METACALL_INSTALL_CERTS="${METACALL_INSTALL_CERTS:-certificates_local}" 33 | 34 | # Run a local server static file server for tricking the tests into using the 35 | # current version of install.sh script instead the one from GitHub URL 36 | docker build -t metacall/install_nginx -f proxy/Dockerfile . 37 | 38 | # Stop the container if it is already running 39 | if [ "$(docker ps -f "name=metacall_install_nginx" --format '{{.Names}}')" = "metacall_install_nginx" ]; then 40 | docker stop metacall_install_nginx 41 | fi 42 | 43 | # Run the proxy for serving install.sh locally under raw.githubusercontent.com domain 44 | docker run --rm \ 45 | --name metacall_install_nginx \ 46 | -p 80:80 \ 47 | -p 443:443 \ 48 | --network host \ 49 | -d metacall/install_nginx 50 | 51 | # Fake the DNS entry pointing to our interceptor proxy when testing locally 52 | if [ "${METACALL_INSTALL_CERTS}" = "certificates_local" ]; then 53 | METACALL_INSTALL_DNS=--add-host="raw.githubusercontent.com:127.0.0.1" 54 | else 55 | METACALL_INSTALL_DNS= 56 | fi 57 | 58 | # Disable exit on error for printing the test fails 59 | set +e 60 | 61 | # Run tests 62 | for test in ${TEST_LIST}; do 63 | docker build \ 64 | --no-cache \ 65 | --progress=plain \ 66 | --target ${test} \ 67 | --build-arg "METACALL_INSTALL_CERTS=${METACALL_INSTALL_CERTS}" \ 68 | --network host \ 69 | ${METACALL_INSTALL_DNS} \ 70 | -t metacall/install:${test} . 71 | 72 | result=$? 73 | if [[ $result -ne 0 ]]; then 74 | echo "Test ${test} failed. Abort." 75 | exit 1 76 | fi 77 | 78 | # Clean test on each iteration in order to not clog the disk 79 | if [[ "${CI:-}" == "true" ]]; then 80 | docker system prune -f --all 81 | fi 82 | done 83 | 84 | # Clear the proxy 85 | docker stop metacall_install_nginx 86 | 87 | # Clean 88 | docker system prune -f --all 89 | 90 | # Test Docker Install 91 | DOCKER_HOST_PATH="${SCRIPT_DIR}/test" 92 | 93 | if [ "${METACALL_INSTALL_CERTS}" = "certificates_local" ]; then 94 | DOCKER_ADDITIONAL_VOLUME="-v ${SCRIPT_DIR}/install.sh:/bin/install.sh" 95 | DOCKER_INSTALL_CMD="sh /bin/install.sh" 96 | DOCKER_FALLBACK_CMD="true" 97 | else 98 | DOCKER_ADDITIONAL_VOLUME="" 99 | DOCKER_INSTALL_CMD="wget -O - https://raw.githubusercontent.com/metacall/install/master/install.sh | sh -s --" 100 | DOCKER_FALLBACK_CMD="wget https://raw.githubusercontent.com/metacall/install/master/install.sh -O /bin/install.sh" 101 | fi 102 | 103 | # Run Docker install with --docker-install parameter 104 | docker run --rm \ 105 | -v /var/run/docker.sock:/var/run/docker.sock \ 106 | -v ${DOCKER_HOST_PATH}:/metacall/source \ 107 | ${DOCKER_ADDITIONAL_VOLUME} \ 108 | -t docker:19.03.13-dind \ 109 | sh -c "${DOCKER_INSTALL_CMD} --docker-install \ 110 | && mkdir -p ${DOCKER_HOST_PATH} \ 111 | && cd ${DOCKER_HOST_PATH} \ 112 | && metacall script.js | grep '123456' \ 113 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 114 | && metacall faas --version | grep -e '^v.*\..*\..*'" 115 | 116 | result=$? 117 | if [[ $result -ne 0 ]]; then 118 | echo "Test test_docker failed. Abort." 119 | exit 1 120 | fi 121 | 122 | # Run Docker install with fallback (remove wget during the install phase in order to trigger the fallback) 123 | docker run --rm \ 124 | -v /var/run/docker.sock:/var/run/docker.sock \ 125 | -v ${DOCKER_HOST_PATH}:/metacall/source \ 126 | ${DOCKER_ADDITIONAL_VOLUME} \ 127 | -t docker:19.03.13-dind \ 128 | sh -c "${DOCKER_FALLBACK_CMD} \ 129 | && rm -rf /usr/bin/wget \ 130 | && sh /bin/install.sh \ 131 | && mkdir -p ${DOCKER_HOST_PATH} \ 132 | && cd ${DOCKER_HOST_PATH} \ 133 | && metacall script.js | grep '123456' \ 134 | && metacall deploy --version | grep -e '^v.*\..*\..*' \ 135 | && metacall faas --version | grep -e '^v.*\..*\..*'" 136 | 137 | result=$? 138 | if [[ $result -ne 0 ]]; then 139 | echo "Test test_docker_fallback failed. Abort." 140 | exit 1 141 | fi 142 | 143 | echo "All tests passed." 144 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | node_modules 3 | -------------------------------------------------------------------------------- /test/async.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # MetaCall Install Script by Parra Studios 5 | # Cross-platform set of scripts to install MetaCall infrastructure. 6 | # 7 | # Copyright (C) 2016 - 2024 Vicente Eduardo Ferrer Garcia 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | import asyncio 23 | 24 | async def main(): 25 | await asyncio.sleep(1) 26 | print('Async Done') 27 | 28 | # Python 3.7+ 29 | asyncio.run(main()) 30 | -------------------------------------------------------------------------------- /test/opencv/opencv.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | print("OpenCV Version", cv2.__version__) 3 | -------------------------------------------------------------------------------- /test/opencv/requirements.txt: -------------------------------------------------------------------------------- 1 | opencv-contrib-python==3.4.11.45 2 | -------------------------------------------------------------------------------- /test/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "test", 9 | "version": "1.0.0", 10 | "dependencies": { 11 | "jsonwebtoken": "^9.0.2" 12 | } 13 | }, 14 | "node_modules/buffer-equal-constant-time": { 15 | "version": "1.0.1", 16 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 17 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" 18 | }, 19 | "node_modules/ecdsa-sig-formatter": { 20 | "version": "1.0.11", 21 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 22 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 23 | "dependencies": { 24 | "safe-buffer": "^5.0.1" 25 | } 26 | }, 27 | "node_modules/jsonwebtoken": { 28 | "version": "9.0.2", 29 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", 30 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", 31 | "dependencies": { 32 | "jws": "^3.2.2", 33 | "lodash.includes": "^4.3.0", 34 | "lodash.isboolean": "^3.0.3", 35 | "lodash.isinteger": "^4.0.4", 36 | "lodash.isnumber": "^3.0.3", 37 | "lodash.isplainobject": "^4.0.6", 38 | "lodash.isstring": "^4.0.1", 39 | "lodash.once": "^4.0.0", 40 | "ms": "^2.1.1", 41 | "semver": "^7.5.4" 42 | }, 43 | "engines": { 44 | "node": ">=12", 45 | "npm": ">=6" 46 | } 47 | }, 48 | "node_modules/jwa": { 49 | "version": "1.4.1", 50 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", 51 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 52 | "dependencies": { 53 | "buffer-equal-constant-time": "1.0.1", 54 | "ecdsa-sig-formatter": "1.0.11", 55 | "safe-buffer": "^5.0.1" 56 | } 57 | }, 58 | "node_modules/jws": { 59 | "version": "3.2.2", 60 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", 61 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 62 | "dependencies": { 63 | "jwa": "^1.4.1", 64 | "safe-buffer": "^5.0.1" 65 | } 66 | }, 67 | "node_modules/lodash.includes": { 68 | "version": "4.3.0", 69 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 70 | "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" 71 | }, 72 | "node_modules/lodash.isboolean": { 73 | "version": "3.0.3", 74 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 75 | "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" 76 | }, 77 | "node_modules/lodash.isinteger": { 78 | "version": "4.0.4", 79 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 80 | "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" 81 | }, 82 | "node_modules/lodash.isnumber": { 83 | "version": "3.0.3", 84 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 85 | "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" 86 | }, 87 | "node_modules/lodash.isplainobject": { 88 | "version": "4.0.6", 89 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 90 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" 91 | }, 92 | "node_modules/lodash.isstring": { 93 | "version": "4.0.1", 94 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 95 | "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" 96 | }, 97 | "node_modules/lodash.once": { 98 | "version": "4.1.1", 99 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 100 | "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" 101 | }, 102 | "node_modules/ms": { 103 | "version": "2.1.3", 104 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 105 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 106 | }, 107 | "node_modules/safe-buffer": { 108 | "version": "5.2.1", 109 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 110 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 111 | "funding": [ 112 | { 113 | "type": "github", 114 | "url": "https://github.com/sponsors/feross" 115 | }, 116 | { 117 | "type": "patreon", 118 | "url": "https://www.patreon.com/feross" 119 | }, 120 | { 121 | "type": "consulting", 122 | "url": "https://feross.org/support" 123 | } 124 | ] 125 | }, 126 | "node_modules/semver": { 127 | "version": "7.6.3", 128 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", 129 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", 130 | "bin": { 131 | "semver": "bin/semver.js" 132 | }, 133 | "engines": { 134 | "node": ">=10" 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /test/package.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | 3 | console.log(jwt.sign('yeet', '123')) 4 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "main": "package.js", 5 | "dependencies": { 6 | "jsonwebtoken": "^9.0.2" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/requirements.py: -------------------------------------------------------------------------------- 1 | import certifi 2 | print('123456') 3 | -------------------------------------------------------------------------------- /test/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2024.7.4 2 | -------------------------------------------------------------------------------- /test/script.js: -------------------------------------------------------------------------------- 1 | console.log('123456'); 2 | -------------------------------------------------------------------------------- /test/script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # MetaCall Install Script by Parra Studios 5 | # Cross-platform set of scripts to install MetaCall infrastructure. 6 | # 7 | # Copyright (C) 2016 - 2024 Vicente Eduardo Ferrer Garcia 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | from http import client 23 | import ssl 24 | import sys 25 | 26 | def fetch_https(url: str): 27 | try: 28 | print(ssl.get_default_verify_paths()) 29 | sys.stdout.flush() 30 | conn = client.HTTPSConnection(url, 443) 31 | conn.request('GET', '/') 32 | response = conn.getresponse() 33 | data = response.read() 34 | conn.close() 35 | return [x for x in data[:15]] 36 | except Exception as e: 37 | print(e) 38 | sys.stdout.flush() 39 | return b'' 40 | -------------------------------------------------------------------------------- /test/spacex/launchpads.py: -------------------------------------------------------------------------------- 1 | from metacall import metacall_load_from_file, metacall_await 2 | import json 3 | 4 | # TODO: This test won't work because python port has no metacall_await 5 | # implemented yet, this is a task to be done in metacall/core 6 | 7 | metacall_load_from_file('node', ['./spacex.js']) 8 | response = metacall_await('getSpaceXData') 9 | print(json.dumps(response, indent=4)) 10 | -------------------------------------------------------------------------------- /test/spacex/requirements.txt: -------------------------------------------------------------------------------- 1 | metacall==0.5.0 2 | -------------------------------------------------------------------------------- /test/spacex/spacex.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getSpaceXData: async () => { 3 | try { 4 | const response = await axios.get('https://api.spacexdata.com/v3/launchpads') 5 | return response.data 6 | } catch (error) { 7 | return error 8 | } 9 | } 10 | }; 11 | --------------------------------------------------------------------------------