├── .github └── workflows │ ├── lint.yml │ ├── release_rust.yml │ ├── semgrep.yml │ ├── test.yml │ └── test_rust.yml ├── .gitignore ├── README.md ├── example-binary ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── src │ └── main.rs └── tests │ └── c.rs ├── lerna.json ├── package-lock.json ├── package.json └── packages ├── binary-install-example ├── .gitignore ├── binary.js ├── install.js ├── package-lock.json ├── package.json ├── run.js └── uninstall.js ├── binary-install ├── .gitignore ├── .prettierrc ├── LICENSE ├── index.js ├── package-lock.json ├── package.json └── src │ └── binary.js └── test ├── .gitignore ├── index.js ├── package-lock.json └── package.json /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | binary-install: 7 | name: JavaScript linter 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Install JavaScript dependencies 13 | run: npm i 14 | 15 | - name: Check JavaScript Formatting 16 | run: npm run fmt:check 17 | 18 | rust-example: 19 | name: Rust Example Linter 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - name: Install Rust 25 | run: | 26 | rustup update stable 27 | rustup default stable 28 | rustup component add rustfmt 29 | 30 | - name: Check Rust Formatting 31 | working-directory: ./example-binary 32 | run: cargo fmt -- --check 33 | 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/release_rust.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "rust_v*" # Run when tag matches rust_v*, i.e. rust_v1.0, rust_v20.15.10 5 | 6 | name: Release Rust Binary 7 | 8 | env: 9 | RELEASE_BIN: binary-install-example 10 | RELEASE_DIR: artifacts 11 | WORKING_DIR: ./example-binary 12 | GITHUB_REF: "${{ github.ref }}" 13 | WINDOWS_TARGET: x86_64-pc-windows-msvc 14 | MACOS_TARGET: x86_64-apple-darwin 15 | LINUX_TARGET: x86_64-unknown-linux-musl 16 | 17 | jobs: 18 | build: 19 | name: Build artifacts 20 | runs-on: ${{ matrix.os }} 21 | strategy: 22 | matrix: 23 | build: [linux, macos, windows] 24 | include: 25 | - build: linux 26 | os: ubuntu-latest 27 | rust: stable 28 | - build: macos 29 | os: macos-latest 30 | rust: stable 31 | - build: windows 32 | os: windows-latest 33 | rust: stable 34 | 35 | steps: 36 | - uses: actions/checkout@v1 37 | 38 | - name: Cache Cargo registry 39 | uses: actions/cache@v1 40 | if: matrix.rust 41 | with: 42 | path: ~/.cargo/registry 43 | key: ${{ matrix.build }}-stable-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 44 | restore-keys: | 45 | ${{ matrix.build }}-stable-cargo-registry- 46 | 47 | - name: Cache Cargo index 48 | uses: actions/cache@v1 49 | if: matrix.rust 50 | with: 51 | path: ~/.cargo/git 52 | key: ${{ matrix.build }}-stable-cargo-index-${{ hashFiles('**/Cargo.lock') }} 53 | restore-keys: | 54 | ${{ matrix.build }}-stable-cargo-index- 55 | 56 | - name: Cache Cargo build 57 | uses: actions/cache@v1 58 | if: matrix.rust 59 | with: 60 | path: target/release 61 | key: ${{ matrix.build }}-stable-release-target-${{ hashFiles('**/Cargo.lock') }} 62 | restore-keys: | 63 | ${{ matrix.build }}-stable-release-target- 64 | 65 | - name: Query version number 66 | id: get_version 67 | shell: bash 68 | run: | 69 | echo "using version tag ${GITHUB_REF:15}" 70 | echo ::set-output name=version::"${GITHUB_REF:15}" 71 | 72 | - name: Install Rust 73 | if: matrix.rust 74 | run: | 75 | rustup update ${{ matrix.rust }} --no-self-update 76 | rustup default ${{ matrix.rust }} 77 | 78 | - name: Install musl-tools (Linux) 79 | if: matrix.build == 'linux' 80 | run: | 81 | sudo apt-get update -y 82 | sudo apt-get install musl-tools -y 83 | 84 | - name: Install p7zip (MacOS) 85 | if: matrix.build == 'macos' 86 | run: brew install p7zip 87 | 88 | - name: Build (Linux) 89 | if: matrix.build == 'linux' 90 | working-directory: ${{ env.WORKING_DIR }} 91 | run: | 92 | rustup target add ${{ env.LINUX_TARGET }} 93 | cargo build --release --target ${{ env.LINUX_TARGET }} 94 | 95 | - name: Build (MacOS) 96 | if: matrix.build == 'macos' 97 | working-directory: ${{ env.WORKING_DIR }} 98 | run: cargo build --release 99 | 100 | - name: Build (Windows) 101 | if: matrix.build == 'windows' 102 | working-directory: ${{ env.WORKING_DIR }} 103 | run: cargo build --release 104 | env: 105 | RUSTFLAGS: -Ctarget-feature=+crt-static 106 | 107 | - name: Create artifact directory 108 | working-directory: ${{ env.WORKING_DIR }} 109 | run: | 110 | mkdir ${{ env.RELEASE_DIR }} 111 | mkdir dist 112 | 113 | - name: Create tarball (Linux) 114 | if: matrix.build == 'linux' 115 | working-directory: ${{ env.WORKING_DIR }} 116 | run: | 117 | mv ./target/${{ env.LINUX_TARGET }}/release/${{ env.RELEASE_BIN }} ./dist/${{ env.RELEASE_BIN }} 118 | 7z a -ttar -so -an ./dist | 7z a -si ./${{ env.RELEASE_DIR }}/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.LINUX_TARGET }}.tar.gz 119 | 120 | - name: Create tarball (Windows) 121 | if: matrix.build == 'windows' 122 | working-directory: ${{ env.WORKING_DIR }} 123 | shell: bash 124 | run: | 125 | mv ./target/release/${{ env.RELEASE_BIN }}.exe ./dist/${{ env.RELEASE_BIN }}.exe 126 | 7z a -ttar -so -an ./dist | 7z a -si ./${{ env.RELEASE_DIR }}/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.WINDOWS_TARGET }}.tar.gz 127 | 128 | - name: Create tarball (MacOS) 129 | if: matrix.build == 'macos' 130 | working-directory: ${{ env.WORKING_DIR }} 131 | run: | 132 | mv ./target/release/${{ env.RELEASE_BIN }} ./dist/${{ env.RELEASE_BIN }} 133 | 7z a -ttar -so -an ./dist | 7z a -si ./${{ env.RELEASE_DIR }}/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.MACOS_TARGET }}.tar.gz 134 | 135 | - name: Upload Zip 136 | uses: actions/upload-artifact@v1 137 | with: 138 | name: ${{ matrix.build }} 139 | path: ./${{ env.WORKING_DIR }}/${{ env.RELEASE_DIR }} 140 | 141 | release: 142 | name: Github Release 143 | needs: build 144 | runs-on: ubuntu-latest 145 | steps: 146 | - name: Query version number 147 | id: get_version 148 | shell: bash 149 | run: | 150 | echo "using version tag ${GITHUB_REF:15}" 151 | echo ::set-output name=version::"${GITHUB_REF:15}" 152 | 153 | - name: Create Release 154 | id: create_release 155 | uses: actions/create-release@v1 156 | env: 157 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 158 | with: 159 | tag_name: ${{ steps.get_version.outputs.VERSION }} 160 | release_name: ${{ steps.get_version.outputs.VERSION }} 161 | 162 | - name: Download Linux tarball 163 | uses: actions/download-artifact@v1 164 | with: 165 | name: linux 166 | 167 | - name: Download MacOS tarball 168 | uses: actions/download-artifact@v1 169 | with: 170 | name: windows 171 | 172 | - name: Download MacOS tarball 173 | uses: actions/download-artifact@v1 174 | with: 175 | name: macos 176 | 177 | - name: Release Linux tarball 178 | uses: actions/upload-release-asset@v1 179 | env: 180 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 181 | with: 182 | upload_url: ${{ steps.create_release.outputs.upload_url }} 183 | asset_path: ./linux/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.LINUX_TARGET }}.tar.gz 184 | asset_content_type: application/gzip 185 | asset_name: ${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.LINUX_TARGET }}.tar.gz 186 | 187 | - name: Release Windows tarball 188 | uses: actions/upload-release-asset@v1 189 | env: 190 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 191 | with: 192 | upload_url: ${{ steps.create_release.outputs.upload_url }} 193 | asset_path: ./windows/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.WINDOWS_TARGET }}.tar.gz 194 | asset_content_type: application/gzip 195 | asset_name: ${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.WINDOWS_TARGET }}.tar.gz 196 | 197 | - name: Release MacOS tarball 198 | uses: actions/upload-release-asset@v1 199 | env: 200 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 201 | with: 202 | upload_url: ${{ steps.create_release.outputs.upload_url }} 203 | asset_path: ./macos/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.MACOS_TARGET }}.tar.gz 204 | asset_content_type: application/gzip 205 | asset_name: ${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ env.MACOS_TARGET }}.tar.gz 206 | -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | 2 | on: 3 | pull_request: {} 4 | workflow_dispatch: {} 5 | push: 6 | branches: 7 | - main 8 | - master 9 | schedule: 10 | - cron: '0 0 * * *' 11 | name: Semgrep config 12 | jobs: 13 | semgrep: 14 | name: semgrep/ci 15 | runs-on: ubuntu-20.04 16 | env: 17 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 18 | SEMGREP_URL: https://cloudflare.semgrep.dev 19 | SEMGREP_APP_URL: https://cloudflare.semgrep.dev 20 | SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version 21 | container: 22 | image: returntocorp/semgrep 23 | steps: 24 | - uses: actions/checkout@v3 25 | - run: semgrep ci 26 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test binary-install 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | binary-install: 7 | name: Test binary-install 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Install JavaScript dependencies 13 | run: npm i 14 | 15 | - name: Run tests 16 | run: npm test 17 | -------------------------------------------------------------------------------- /.github/workflows/test_rust.yml: -------------------------------------------------------------------------------- 1 | name: Test binary-install-example 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | test: 7 | name: Test 8 | 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | build: 13 | [ 14 | linux-stable, 15 | linux-nightly, 16 | macos-stable, 17 | macos-nightly, 18 | windows-stable, 19 | windows-nightly, 20 | ] 21 | include: 22 | - build: linux-stable 23 | os: ubuntu-latest 24 | rust: stable 25 | - build: macos-stable 26 | os: macos-latest 27 | rust: stable 28 | - build: windows-stable 29 | os: windows-latest 30 | rust: stable 31 | - build: linux-nightly 32 | os: ubuntu-latest 33 | rust: nightly 34 | - build: macos-nightly 35 | os: macos-latest 36 | rust: nightly 37 | - build: windows-nightly 38 | os: windows-latest 39 | rust: nightly 40 | 41 | steps: 42 | - uses: actions/checkout@v1 43 | 44 | - name: Cache Cargo registry 45 | uses: actions/cache@v1 46 | with: 47 | path: ~/.cargo/registry 48 | key: ${{ matrix.build }}-${{ matrix.rust }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 49 | restore-keys: | 50 | ${{ matrix.build }}-${{ matrix.rust }}-cargo-registry- 51 | 52 | - name: Cache Cargo index 53 | uses: actions/cache@v1 54 | with: 55 | path: ~/.cargo/git 56 | key: ${{ matrix.build }}-${{ matrix.rust }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} 57 | restore-keys: | 58 | ${{ matrix.build }}-${{ matrix.rust }}-cargo-index- 59 | 60 | - name: Cache Cargo build 61 | uses: actions/cache@v1 62 | with: 63 | path: target/debug 64 | key: ${{ matrix.build }}-${{ matrix.rust }}-debug-target-${{ hashFiles('**/Cargo.lock') }} 65 | restore-keys: | 66 | ${{ matrix.build }}-${{ matrix.rust }}-debug-target- 67 | 68 | - name: Install Rust 69 | run: | 70 | rustup update ${{ matrix.rust }} --no-self-update 71 | rustup default ${{ matrix.rust }} 72 | 73 | - name: Run Tests 74 | working-directory: ./example-binary 75 | run: cargo test 76 | env: 77 | RUST_LOG: warn,wrangler=info 78 | RUST_BACKTRACE: 1 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # binary-install 2 | 3 | Install .tar.gz binary applications via npm 4 | 5 | ## Usage 6 | 7 | This library provides a single class `Binary` that takes a download url and some optional arguments. You **must** provide either `name` or `installDirectory` when creating your `Binary`. 8 | 9 | | option | decription | 10 | | ---------------- | --------------------------------------------- | 11 | | name | The name of your binary | 12 | | installDirectory | A path to the directory to install the binary | 13 | 14 | If an `installDirectory` is not provided, the binary will be installed at your OS specific config directory. On MacOS it defaults to `~/Library/Preferences/${name}-nodejs` 15 | 16 | After your `Binary` has been created, you can run `.install()` to install the binary, and `.run()` to run it. 17 | 18 | ### Example 19 | 20 | This is meant to be used as a library - create your `Binary` with your desired options, then call `.install()` in the `postinstall` of your `package.json`, `.run()` in the `bin` section of your `package.json`, and `.uninstall()` in the `preuninstall` section of your `package.json`. See [this example project](/packages/binary-install-example) to see how to create an npm package that installs and runs a binary using the Github releases API. 21 | -------------------------------------------------------------------------------- /example-binary/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /example-binary/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.7.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" 8 | dependencies = [ 9 | "memchr", 10 | ] 11 | 12 | [[package]] 13 | name = "ansi_term" 14 | version = "0.11.0" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 17 | dependencies = [ 18 | "winapi", 19 | ] 20 | 21 | [[package]] 22 | name = "assert_cmd" 23 | version = "0.12.0" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "6283bac8dd7226470d491bc4737816fea4ca1fba7a2847f2e9097fd6bfb4624c" 26 | dependencies = [ 27 | "doc-comment", 28 | "escargot", 29 | "predicates", 30 | "predicates-core", 31 | "predicates-tree", 32 | ] 33 | 34 | [[package]] 35 | name = "atty" 36 | version = "0.2.14" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 39 | dependencies = [ 40 | "hermit-abi", 41 | "libc", 42 | "winapi", 43 | ] 44 | 45 | [[package]] 46 | name = "autocfg" 47 | version = "1.0.0" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 50 | 51 | [[package]] 52 | name = "binary-install-example" 53 | version = "1.0.0" 54 | dependencies = [ 55 | "assert_cmd", 56 | "clap", 57 | "console", 58 | "predicates", 59 | ] 60 | 61 | [[package]] 62 | name = "bitflags" 63 | version = "1.2.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 66 | 67 | [[package]] 68 | name = "cfg-if" 69 | version = "0.1.10" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 72 | 73 | [[package]] 74 | name = "clap" 75 | version = "2.33.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 78 | dependencies = [ 79 | "ansi_term", 80 | "atty", 81 | "bitflags", 82 | "strsim", 83 | "textwrap", 84 | "unicode-width", 85 | "vec_map", 86 | ] 87 | 88 | [[package]] 89 | name = "clicolors-control" 90 | version = "1.0.1" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 93 | dependencies = [ 94 | "atty", 95 | "lazy_static", 96 | "libc", 97 | "winapi", 98 | ] 99 | 100 | [[package]] 101 | name = "console" 102 | version = "0.10.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "6728a28023f207181b193262711102bfbaf47cc9d13bc71d0736607ef8efe88c" 105 | dependencies = [ 106 | "clicolors-control", 107 | "encode_unicode", 108 | "lazy_static", 109 | "libc", 110 | "regex", 111 | "termios", 112 | "unicode-width", 113 | "winapi", 114 | ] 115 | 116 | [[package]] 117 | name = "difference" 118 | version = "2.0.0" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 121 | 122 | [[package]] 123 | name = "doc-comment" 124 | version = "0.3.3" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 127 | 128 | [[package]] 129 | name = "encode_unicode" 130 | version = "0.3.6" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 133 | 134 | [[package]] 135 | name = "escargot" 136 | version = "0.5.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "74cf96bec282dcdb07099f7e31d9fed323bca9435a09aba7b6d99b7617bca96d" 139 | dependencies = [ 140 | "lazy_static", 141 | "log", 142 | "serde", 143 | "serde_json", 144 | ] 145 | 146 | [[package]] 147 | name = "float-cmp" 148 | version = "0.6.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "da62c4f1b81918835a8c6a484a397775fff5953fe83529afd51b05f5c6a6617d" 151 | dependencies = [ 152 | "num-traits", 153 | ] 154 | 155 | [[package]] 156 | name = "hermit-abi" 157 | version = "0.1.8" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" 160 | dependencies = [ 161 | "libc", 162 | ] 163 | 164 | [[package]] 165 | name = "itoa" 166 | version = "0.4.5" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 169 | 170 | [[package]] 171 | name = "lazy_static" 172 | version = "1.4.0" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 175 | 176 | [[package]] 177 | name = "libc" 178 | version = "0.2.68" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" 181 | 182 | [[package]] 183 | name = "log" 184 | version = "0.4.8" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 187 | dependencies = [ 188 | "cfg-if", 189 | ] 190 | 191 | [[package]] 192 | name = "memchr" 193 | version = "2.3.3" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 196 | 197 | [[package]] 198 | name = "normalize-line-endings" 199 | version = "0.3.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" 202 | 203 | [[package]] 204 | name = "num-traits" 205 | version = "0.2.11" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" 208 | dependencies = [ 209 | "autocfg", 210 | ] 211 | 212 | [[package]] 213 | name = "predicates" 214 | version = "1.0.4" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "347a1b6f0b21e636bc9872fb60b83b8e185f6f5516298b8238699f7f9a531030" 217 | dependencies = [ 218 | "difference", 219 | "float-cmp", 220 | "normalize-line-endings", 221 | "predicates-core", 222 | "regex", 223 | ] 224 | 225 | [[package]] 226 | name = "predicates-core" 227 | version = "1.0.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178" 230 | 231 | [[package]] 232 | name = "predicates-tree" 233 | version = "1.0.0" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124" 236 | dependencies = [ 237 | "predicates-core", 238 | "treeline", 239 | ] 240 | 241 | [[package]] 242 | name = "proc-macro2" 243 | version = "1.0.9" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" 246 | dependencies = [ 247 | "unicode-xid", 248 | ] 249 | 250 | [[package]] 251 | name = "quote" 252 | version = "1.0.3" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" 255 | dependencies = [ 256 | "proc-macro2", 257 | ] 258 | 259 | [[package]] 260 | name = "regex" 261 | version = "1.3.5" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048" 264 | dependencies = [ 265 | "aho-corasick", 266 | "memchr", 267 | "regex-syntax", 268 | "thread_local", 269 | ] 270 | 271 | [[package]] 272 | name = "regex-syntax" 273 | version = "0.6.17" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" 276 | 277 | [[package]] 278 | name = "ryu" 279 | version = "1.0.3" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" 282 | 283 | [[package]] 284 | name = "serde" 285 | version = "1.0.105" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" 288 | dependencies = [ 289 | "serde_derive", 290 | ] 291 | 292 | [[package]] 293 | name = "serde_derive" 294 | version = "1.0.105" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" 297 | dependencies = [ 298 | "proc-macro2", 299 | "quote", 300 | "syn", 301 | ] 302 | 303 | [[package]] 304 | name = "serde_json" 305 | version = "1.0.48" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" 308 | dependencies = [ 309 | "itoa", 310 | "ryu", 311 | "serde", 312 | ] 313 | 314 | [[package]] 315 | name = "strsim" 316 | version = "0.8.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 319 | 320 | [[package]] 321 | name = "syn" 322 | version = "1.0.16" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" 325 | dependencies = [ 326 | "proc-macro2", 327 | "quote", 328 | "unicode-xid", 329 | ] 330 | 331 | [[package]] 332 | name = "termios" 333 | version = "0.3.1" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" 336 | dependencies = [ 337 | "libc", 338 | ] 339 | 340 | [[package]] 341 | name = "textwrap" 342 | version = "0.11.0" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 345 | dependencies = [ 346 | "unicode-width", 347 | ] 348 | 349 | [[package]] 350 | name = "thread_local" 351 | version = "1.0.1" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 354 | dependencies = [ 355 | "lazy_static", 356 | ] 357 | 358 | [[package]] 359 | name = "treeline" 360 | version = "0.1.0" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" 363 | 364 | [[package]] 365 | name = "unicode-width" 366 | version = "0.1.7" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" 369 | 370 | [[package]] 371 | name = "unicode-xid" 372 | version = "0.2.0" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 375 | 376 | [[package]] 377 | name = "vec_map" 378 | version = "0.8.1" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 381 | 382 | [[package]] 383 | name = "winapi" 384 | version = "0.3.8" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 387 | dependencies = [ 388 | "winapi-i686-pc-windows-gnu", 389 | "winapi-x86_64-pc-windows-gnu", 390 | ] 391 | 392 | [[package]] 393 | name = "winapi-i686-pc-windows-gnu" 394 | version = "0.4.0" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 397 | 398 | [[package]] 399 | name = "winapi-x86_64-pc-windows-gnu" 400 | version = "0.4.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 403 | -------------------------------------------------------------------------------- /example-binary/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "binary-install-example" 3 | version = "1.0.0" 4 | authors = ["Wrangler Team "] 5 | edition = "2018" 6 | description = "An example binary to test out https://npmjs.com/package/binary-install" 7 | homepage = "https://npmjs.com/package/binary-install" 8 | repository = "https://github.com/cloudflare/binary-install" 9 | 10 | [dependencies] 11 | clap = "2.33.0" 12 | console = "0.10.0" 13 | 14 | [dev-dependencies] 15 | assert_cmd = "0.12.0" 16 | predicates = "1.0.4" 17 | -------------------------------------------------------------------------------- /example-binary/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use console::Emoji; 3 | use std::env; 4 | 5 | fn main() { 6 | let matches = App::new(env!("CARGO_PKG_NAME")) 7 | .version(env!("CARGO_PKG_VERSION")) 8 | .about(env!("CARGO_PKG_DESCRIPTION")) 9 | .author(env!("CARGO_PKG_AUTHORS")) 10 | .arg( 11 | Arg::with_name("c") 12 | .short("c") 13 | .multiple(true) 14 | .help("Counts the number of -c arguments"), 15 | ) 16 | .get_matches(); 17 | 18 | let c_num = matches.occurrences_of("c"); 19 | 20 | if c_num == 0 { 21 | println!("{} you didn't pass any -c arguments ", Emoji("🥺 ", "")) 22 | } else { 23 | println!("{} you passed {} -c arguments!", Emoji("🥰 ", ""), c_num); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example-binary/tests/c.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::prelude::*; 2 | use std::env; 3 | use std::process::Command; 4 | 5 | #[test] 6 | fn it_cannot_c() { 7 | get_bin() 8 | .assert() 9 | .stdout(predicates::str::contains("didn't")) 10 | .success(); 11 | } 12 | 13 | #[test] 14 | fn it_can_c_four() { 15 | get_bin() 16 | .arg("-cccc") 17 | .assert() 18 | .stdout(predicates::str::contains("4")) 19 | .success(); 20 | } 21 | 22 | fn get_bin() -> Command { 23 | Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap() 24 | } 25 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "0.2.0" 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "scripts": { 5 | "postinstall": "lerna bootstrap", 6 | "test": "lerna run test", 7 | "fmt": "lerna run fmt", 8 | "fmt:check": "lerna run fmt:check" 9 | }, 10 | "devDependencies": { 11 | "lerna": "^3.22.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/binary-install-example/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /packages/binary-install-example/binary.js: -------------------------------------------------------------------------------- 1 | // this example uses the binary generated by the rust project in the parent directory 2 | // said project is released on GitHub, and the correct URL is constructed based on 3 | // the target operating system and the version in package.json 4 | 5 | // your binary could be downloaded from any URL and could use any logic you want 6 | // to construct said URL. You could even A/B test two different binary distribution 7 | // solutions! 8 | 9 | const { Binary } = require("@cloudflare/binary-install"); 10 | const os = require("os"); 11 | const { join } = require("path"); 12 | const cTable = require("console.table"); 13 | 14 | const error = msg => { 15 | console.error(msg); 16 | process.exit(1); 17 | }; 18 | 19 | const { version, name, repository } = require("./package.json"); 20 | 21 | const supportedPlatforms = [ 22 | { 23 | TYPE: "Windows_NT", 24 | ARCHITECTURE: "x64", 25 | RUST_TARGET: "x86_64-pc-windows-msvc" 26 | }, 27 | { 28 | TYPE: "Linux", 29 | ARCHITECTURE: "x64", 30 | RUST_TARGET: "x86_64-unknown-linux-musl" 31 | }, 32 | { 33 | TYPE: "Darwin", 34 | ARCHITECTURE: "x64", 35 | RUST_TARGET: "x86_64-apple-darwin" 36 | } 37 | ]; 38 | 39 | const getPlatform = () => { 40 | const type = os.type(); 41 | const architecture = os.arch(); 42 | 43 | for (let index in supportedPlatforms) { 44 | let supportedPlatform = supportedPlatforms[index]; 45 | if ( 46 | type === supportedPlatform.TYPE && 47 | architecture === supportedPlatform.ARCHITECTURE 48 | ) { 49 | return supportedPlatform.RUST_TARGET; 50 | } 51 | } 52 | 53 | error( 54 | `Platform with type "${type}" and architecture "${architecture}" is not supported by ${name}.\nYour system must be one of the following:\n\n${cTable.getTable( 55 | supportedPlatforms 56 | )}` 57 | ); 58 | }; 59 | 60 | const getBinary = () => { 61 | const platform = getPlatform(); 62 | // the url for this binary is constructed from values in `package.json` 63 | // https://github.com/cloudflare/binary-install/releases/download/v1.0.0/binary-install-example-v1.0.0-x86_64-apple-darwin.tar.gz 64 | const url = `${repository.url}/releases/download/v${version}/${name}-v${version}-${platform}.tar.gz`; 65 | return new Binary(url, { name }); 66 | }; 67 | 68 | const run = () => { 69 | const binary = getBinary(); 70 | binary.run(); 71 | }; 72 | 73 | const install = () => { 74 | const binary = getBinary(); 75 | binary.install(); 76 | }; 77 | 78 | const uninstall = () => { 79 | const binary = getBinary(); 80 | binary.uninstall(); 81 | }; 82 | 83 | module.exports = { 84 | install, 85 | run, 86 | uninstall 87 | }; 88 | -------------------------------------------------------------------------------- /packages/binary-install-example/install.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { install } = require("./binary"); 4 | install(); 5 | -------------------------------------------------------------------------------- /packages/binary-install-example/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "binary-install-example", 3 | "version": "0.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "clone": { 8 | "version": "1.0.4", 9 | "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", 10 | "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", 11 | "optional": true 12 | }, 13 | "console.table": { 14 | "version": "0.10.0", 15 | "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", 16 | "integrity": "sha1-CRcCVYiHW+/XDPLv9L7yxuLXXQQ=", 17 | "requires": { 18 | "easy-table": "1.1.0" 19 | } 20 | }, 21 | "defaults": { 22 | "version": "1.0.3", 23 | "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", 24 | "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", 25 | "optional": true, 26 | "requires": { 27 | "clone": "^1.0.2" 28 | } 29 | }, 30 | "easy-table": { 31 | "version": "1.1.0", 32 | "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", 33 | "integrity": "sha1-hvmrTBAvA3G3KXuSplHVgkvIy3M=", 34 | "requires": { 35 | "wcwidth": ">=1.0.1" 36 | } 37 | }, 38 | "prettier": { 39 | "version": "1.19.1", 40 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", 41 | "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", 42 | "dev": true 43 | }, 44 | "wcwidth": { 45 | "version": "1.0.1", 46 | "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", 47 | "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", 48 | "optional": true, 49 | "requires": { 50 | "defaults": "^1.0.3" 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/binary-install-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "binary-install-example", 3 | "version": "1.0.0", 4 | "description": "An example package for binary-install", 5 | "main": "binary.js", 6 | "private": true, 7 | "bin": { 8 | "binary-install-example": "./run.js" 9 | }, 10 | "scripts": { 11 | "postinstall": "node ./install.js", 12 | "preuninstall": "node ./uninstall.js", 13 | "fmt": "prettier --write **/*.js", 14 | "fmt:check": "prettier --check **/*.js" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/cloudflare/binary-install" 19 | }, 20 | "author": "Wrangler Team ", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/cloudflare/binary-install/issues" 24 | }, 25 | "homepage": "https://github.com/cloudflare/binary-install#readme", 26 | "dependencies": { 27 | "@cloudflare/binary-install": "^0.2.0", 28 | "console.table": "^0.10.0" 29 | }, 30 | "devDependencies": { 31 | "prettier": "^1.19.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/binary-install-example/run.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { run } = require("./binary"); 4 | run(); 5 | -------------------------------------------------------------------------------- /packages/binary-install-example/uninstall.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { uninstall } = require("./binary"); 4 | uninstall(); 5 | -------------------------------------------------------------------------------- /packages/binary-install/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /node_modules 3 | -------------------------------------------------------------------------------- /packages/binary-install/.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /packages/binary-install/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Cloudflare 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/binary-install/index.js: -------------------------------------------------------------------------------- 1 | module.exports.Binary = require("./src/binary"); 2 | -------------------------------------------------------------------------------- /packages/binary-install/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "binary-install", 3 | "version": "0.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "axios": { 8 | "version": "0.21.1", 9 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", 10 | "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", 11 | "requires": { 12 | "follow-redirects": "^1.10.0" 13 | } 14 | }, 15 | "balanced-match": { 16 | "version": "1.0.0", 17 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 18 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 19 | }, 20 | "brace-expansion": { 21 | "version": "1.1.11", 22 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 23 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 24 | "requires": { 25 | "balanced-match": "^1.0.0", 26 | "concat-map": "0.0.1" 27 | } 28 | }, 29 | "chownr": { 30 | "version": "2.0.0", 31 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", 32 | "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" 33 | }, 34 | "concat-map": { 35 | "version": "0.0.1", 36 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 37 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 38 | }, 39 | "follow-redirects": { 40 | "version": "1.13.1", 41 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", 42 | "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" 43 | }, 44 | "fs-minipass": { 45 | "version": "2.1.0", 46 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", 47 | "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", 48 | "requires": { 49 | "minipass": "^3.0.0" 50 | } 51 | }, 52 | "fs.realpath": { 53 | "version": "1.0.0", 54 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 55 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 56 | }, 57 | "glob": { 58 | "version": "7.1.6", 59 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 60 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 61 | "requires": { 62 | "fs.realpath": "^1.0.0", 63 | "inflight": "^1.0.4", 64 | "inherits": "2", 65 | "minimatch": "^3.0.4", 66 | "once": "^1.3.0", 67 | "path-is-absolute": "^1.0.0" 68 | } 69 | }, 70 | "inflight": { 71 | "version": "1.0.6", 72 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 73 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 74 | "requires": { 75 | "once": "^1.3.0", 76 | "wrappy": "1" 77 | } 78 | }, 79 | "inherits": { 80 | "version": "2.0.4", 81 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 82 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 83 | }, 84 | "minimatch": { 85 | "version": "3.0.4", 86 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 87 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 88 | "requires": { 89 | "brace-expansion": "^1.1.7" 90 | } 91 | }, 92 | "minipass": { 93 | "version": "3.1.3", 94 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", 95 | "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", 96 | "requires": { 97 | "yallist": "^4.0.0" 98 | } 99 | }, 100 | "minizlib": { 101 | "version": "2.1.0", 102 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz", 103 | "integrity": "sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA==", 104 | "requires": { 105 | "minipass": "^3.0.0", 106 | "yallist": "^4.0.0" 107 | } 108 | }, 109 | "once": { 110 | "version": "1.4.0", 111 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 112 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 113 | "requires": { 114 | "wrappy": "1" 115 | } 116 | }, 117 | "path-is-absolute": { 118 | "version": "1.0.1", 119 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 120 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 121 | }, 122 | "prettier": { 123 | "version": "1.19.1", 124 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", 125 | "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", 126 | "dev": true 127 | }, 128 | "rimraf": { 129 | "version": "3.0.2", 130 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 131 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 132 | "requires": { 133 | "glob": "^7.1.3" 134 | } 135 | }, 136 | "tar": { 137 | "version": "6.0.2", 138 | "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.2.tgz", 139 | "integrity": "sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg==", 140 | "requires": { 141 | "chownr": "^2.0.0", 142 | "fs-minipass": "^2.0.0", 143 | "minipass": "^3.0.0", 144 | "minizlib": "^2.1.0", 145 | "mkdirp": "^1.0.3", 146 | "yallist": "^4.0.0" 147 | }, 148 | "dependencies": { 149 | "mkdirp": { 150 | "version": "1.0.4", 151 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 152 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" 153 | } 154 | } 155 | }, 156 | "wrappy": { 157 | "version": "1.0.2", 158 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 159 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 160 | }, 161 | "yallist": { 162 | "version": "4.0.0", 163 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 164 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /packages/binary-install/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cloudflare/binary-install", 3 | "version": "0.2.0", 4 | "description": "Install binary applications via npm", 5 | "main": "./index.js", 6 | "scripts": { 7 | "fmt": "prettier --write **/*.js", 8 | "fmt:check": "prettier --check **/*.js" 9 | }, 10 | "engines": { 11 | "node": ">=10" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/cloudflare/binary-install.git" 16 | }, 17 | "keywords": [ 18 | "install", 19 | "binary", 20 | "global" 21 | ], 22 | "author": "Wrangler Team ", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/cloudflare/binary-install/issues" 26 | }, 27 | "homepage": "https://github.com/cloudflare/binary-install#readme", 28 | "devDependencies": { 29 | "prettier": "^1.19.1" 30 | }, 31 | "dependencies": { 32 | "axios": "^0.21.1", 33 | "rimraf": "^3.0.2", 34 | "tar": "^6.0.2" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/binary-install/src/binary.js: -------------------------------------------------------------------------------- 1 | const { existsSync, mkdirSync } = require("fs"); 2 | const { homedir } = require("os"); 3 | const { join } = require("path"); 4 | const { spawnSync } = require("child_process"); 5 | 6 | const axios = require("axios"); 7 | const tar = require("tar"); 8 | const rimraf = require("rimraf"); 9 | 10 | const error = msg => { 11 | console.error(msg); 12 | process.exit(1); 13 | }; 14 | 15 | class Binary { 16 | constructor(url, data) { 17 | if (typeof url !== "string") { 18 | errors.push("url must be a string"); 19 | } else { 20 | try { 21 | new URL(url); 22 | } catch (e) { 23 | errors.push(e); 24 | } 25 | } 26 | let errors = []; 27 | if (data.name && typeof data.name !== "string") { 28 | errors.push("name must be a string"); 29 | } 30 | if (data.installDirectory && typeof data.installDirectory !== "string") { 31 | errors.push("installDirectory must be a string"); 32 | } 33 | if (!data.installDirectory && !data.name) { 34 | errors.push("You must specify either name or installDirectory"); 35 | } 36 | if (errors.length > 0) { 37 | let errorMsg = "Your Binary constructor is invalid:"; 38 | errors.forEach(error => { 39 | errorMsg += error; 40 | }); 41 | error(errorMsg); 42 | } 43 | this.url = url; 44 | this.name = data.name || -1; 45 | this.installDirectory = data.installDirectory || join(__dirname, "bin"); 46 | this.binaryDirectory = -1; 47 | this.binaryPath = -1; 48 | } 49 | 50 | _getInstallDirectory() { 51 | if (!existsSync(this.installDirectory)) { 52 | mkdirSync(this.installDirectory, { recursive: true }); 53 | } 54 | return this.installDirectory; 55 | } 56 | 57 | _getBinaryDirectory() { 58 | const installDirectory = this._getInstallDirectory(); 59 | const binaryDirectory = join(this.installDirectory, "bin"); 60 | if (existsSync(binaryDirectory)) { 61 | this.binaryDirectory = binaryDirectory; 62 | } else { 63 | error(`You have not installed ${this.name ? this.name : "this package"}`); 64 | } 65 | return this.binaryDirectory; 66 | } 67 | 68 | _getBinaryPath() { 69 | if (this.binaryPath === -1) { 70 | const binaryDirectory = this._getBinaryDirectory(); 71 | this.binaryPath = join(binaryDirectory, this.name); 72 | } 73 | 74 | return this.binaryPath; 75 | } 76 | 77 | install() { 78 | const dir = this._getInstallDirectory(); 79 | if (!existsSync(dir)) { 80 | mkdirSync(dir, { recursive: true }); 81 | } 82 | 83 | this.binaryDirectory = join(dir, "bin"); 84 | 85 | if (existsSync(this.binaryDirectory)) { 86 | rimraf.sync(this.binaryDirectory); 87 | } 88 | 89 | mkdirSync(this.binaryDirectory, { recursive: true }); 90 | 91 | console.log(`Downloading release from ${this.url}`); 92 | 93 | return axios({ url: this.url, responseType: "stream" }) 94 | .then(res => { 95 | res.data.pipe(tar.x({ strip: 1, C: this.binaryDirectory })); 96 | }) 97 | .then(() => { 98 | console.log( 99 | `${this.name ? this.name : "Your package"} has been installed!` 100 | ); 101 | }) 102 | .catch(e => { 103 | error(`Error fetching release: ${e.message}`); 104 | }); 105 | } 106 | 107 | uninstall() { 108 | if (existsSync(this._getInstallDirectory())) { 109 | rimraf.sync(this.installDirectory); 110 | console.log( 111 | `${this.name ? this.name : "Your package"} has been uninstalled` 112 | ); 113 | } 114 | } 115 | 116 | run() { 117 | const binaryPath = this._getBinaryPath(); 118 | const [, , ...args] = process.argv; 119 | 120 | const options = { cwd: process.cwd(), stdio: "inherit" }; 121 | 122 | const result = spawnSync(binaryPath, args, options); 123 | 124 | if (result.error) { 125 | error(result.error); 126 | } 127 | 128 | process.exit(result.status); 129 | } 130 | } 131 | 132 | module.exports = Binary; 133 | -------------------------------------------------------------------------------- /packages/test/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /packages/test/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | 3 | process.stdin.on("data", function(data) { 4 | assert(data.toString().includes(4)); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/test/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "prettier": { 8 | "version": "1.19.1", 9 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", 10 | "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", 11 | "dev": true 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "tests for binary-install", 5 | "main": "binary.js", 6 | "bin": { 7 | "binary-install-example": "./run.js" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "test": "binary-install-example -cccc | node ./index.js", 12 | "fmt": "prettier --write **/*.js", 13 | "fmt:check": "prettier --check **/*.js" 14 | }, 15 | "author": "Wrangler Team ", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "binary-install-example": "^1.0.0", 19 | "prettier": "^1.19.1" 20 | } 21 | } 22 | --------------------------------------------------------------------------------