From 0577f5fd15e06a8e932a1bd36395e043a95afe39 Mon Sep 17 00:00:00 2001 From: pxseu <57842793+pxseu@users.noreply.github.com> Date: Wed, 3 Aug 2022 18:12:39 +0200 Subject: [PATCH] feat: windows installer --- .github/workflows/release.yml | 39 ++- rustfmt.toml => .rustfmt.toml | 0 .vscode/settings.json | 4 + Cargo.lock | 208 ++++++++++++++-- Cargo.toml | 79 +++--- LICENSE | 373 +++++++++++++++++++++++++++++ build.rs | 35 +++ build/windows/main.wxs | 238 ++++++++++++++++++ build/windows/resources/Banner.bmp | Bin 0 -> 114514 bytes build/windows/resources/Dialog.bmp | Bin 0 -> 615402 bytes build/windows/resources/hop.ico | Bin 0 -> 107473 bytes scripts/build.ps1 | 7 + src/commands/update/parse.rs | 23 ++ 13 files changed, 955 insertions(+), 51 deletions(-) rename rustfmt.toml => .rustfmt.toml (100%) create mode 100644 .vscode/settings.json create mode 100644 LICENSE create mode 100644 build.rs create mode 100644 build/windows/main.wxs create mode 100644 build/windows/resources/Banner.bmp create mode 100644 build/windows/resources/Dialog.bmp create mode 100644 build/windows/resources/hop.ico create mode 100644 scripts/build.ps1 create mode 100644 src/commands/update/parse.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bbf4704..6a50bb1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -99,6 +99,13 @@ jobs: profile: minimal override: true + - name: Install Wix [Windows] + if: matrix.os == 'windows-latest' + uses: actions-rs/cargo@v1 + with: + command: install + args: cargo-wix + - name: Build release binary uses: actions-rs/cargo@v1 with: @@ -106,14 +113,6 @@ jobs: args: --release --locked --target ${{ matrix.target }} use-cross: ${{ matrix.os == 'ubuntu-latest' }} - - name: Prepare binaries [Windows] - if: matrix.os == 'windows-latest' - run: | - cd target/${{ matrix.target }}/release - strip hop.exe - 7z a ../../../hop-${{ matrix.platform }}.zip hop.exe - cd - - - name: Prepare binaries [*nix] if: matrix.os != 'windows-latest' run: | @@ -122,12 +121,34 @@ jobs: tar czvf ../../../hop-${{ matrix.platform }}.tar.gz hop cd - - - name: Upload artifacts + - name: Prepare binaries [Windows] + if: matrix.os == 'windows-latest' + run: | + cd target/${{ matrix.target }}/release + strip hop.exe + 7z a ../../../hop-${{ matrix.platform }}.zip hop.exe + cd - + + - name: Build installer [Windows] + if: matrix.os == 'windows-latest' + uses: actions-rs/cargo@v1 + with: + command: wix + args: -I .\build\windows\main.wxs -v --no-build --nocapture --target ${{ matrix.target }} --output target/wix/hop-${{ matrix.platform }}.msi + + - name: Upload binaries uses: actions/upload-artifact@v3 with: name: hop-${{ matrix.platform }}.${{ matrix.os == 'windows-latest' && 'zip' || 'tar.gz' }} path: hop-${{ matrix.platform }}.${{ matrix.os == 'windows-latest' && 'zip' || 'tar.gz' }} + - name: Upload installer [Windows] + if: matrix.os == 'windows-latest' + uses: actions/upload-artifact@v3 + with: + name: hop-${{ matrix.platform }}.msi + path: target/wix/hop-${{ matrix.platform }}.msi + publish-release: name: Publish Release needs: ["draft-release", "build-release"] diff --git a/rustfmt.toml b/.rustfmt.toml similarity index 100% rename from rustfmt.toml rename to .rustfmt.toml diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..dfe5a3f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "rust-analyzer.checkOnSave.command": "clippy", + "editor.defaultFormatter": "rust-lang.rust-analyzer", +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index f3dcbe7..084a4d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,9 +203,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.15" +version = "3.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bbe24bbd31a185bc2c4f7c2abe80bea13a20d57ee4e55be70ac512bdc76417" +checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9" dependencies = [ "atty", "bitflags", @@ -275,6 +275,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "cpufeatures" version = "0.2.2" @@ -470,6 +486,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.0.1" @@ -535,9 +566,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -637,12 +668,15 @@ dependencies = [ "serde_json", "serde_repr", "serde_yaml", + "static_vcruntime", "sys-info", "tabwriter", "tokio", "tokio-tar", "tokio-tungstenite", "webbrowser", + "winapi", + "winres", ] [[package]] @@ -716,6 +750,19 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -911,6 +958,24 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk" version = "0.6.0" @@ -1043,6 +1108,51 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +[[package]] +name = "openssl" +version = "0.10.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_str_bytes" version = "6.2.0" @@ -1255,12 +1365,14 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "lazy_static", "log", "mime", "mime_guess", + "native-tls", "percent-encoding", "pin-project-lite", "rustls", @@ -1269,6 +1381,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls", "tower-service", "url", @@ -1324,9 +1437,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ "base64", ] @@ -1346,6 +1459,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1362,20 +1485,43 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "7af873f2c95b99fcb0bd0fe622a43e29514658873c8ceba88c4cb88833a22500" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "75743a150d003dd863b51dc809bcad0d73f2102c53632f1e954e738192a3413f" dependencies = [ "proc-macro2", "quote", @@ -1418,9 +1564,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f1e71f8401ef389565b7d16731f3cd181cccd07e2e995f37beb1fd2304ffe1" +checksum = "79b7c9017c64a49806c6e8df8ef99b92446d09c92457f85f91835b01a8064ae0" dependencies = [ "indexmap", "itoa", @@ -1480,6 +1626,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "static_vcruntime" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "954e3e877803def9dc46075bf4060147c55cd70db97873077232eae0269dc89b" + [[package]] name = "strsim" version = "0.10.0" @@ -1642,6 +1794,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.23.4" @@ -1687,8 +1849,10 @@ checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" dependencies = [ "futures-util", "log", + "native-tls", "rustls", "tokio", + "tokio-native-tls", "tokio-rustls", "tungstenite", "webpki", @@ -1762,6 +1926,7 @@ dependencies = [ "http", "httparse", "log", + "native-tls", "rand", "rustls", "sha-1", @@ -1815,9 +1980,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unsafe-libyaml" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dc1c637311091be28e5d462c07db78081e5828da80ba22605c81c4ad6f7f813" +checksum = "931179334a56395bcf64ba5e0ff56781381c1a5832178280c7d7f91d1679aeb0" [[package]] name = "untrusted" @@ -1843,6 +2008,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -2090,6 +2261,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "winres" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +dependencies = [ + "toml", +] + [[package]] name = "xattr" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index a54ef1f..40b8450 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,46 +1,69 @@ -# `hop-` serves as a "namespace" [package] name = "hop-cli" version = "0.1.12" edition = "2021" +license = "MPL-2.0" +authors = ["Hop Inc."] +description = "Interact with Hop in your terminal" -# override binary name [[bin]] name = "hop" path = "./src/main.rs" +[package.metadata.winres] +ProductName = "Hop CLI" +OriginalFilename = "hop.exe" +LegalCopyright = "© 2022 Hop Inc." +FileDescription = "Interact with Hop in your terminal" + [dependencies] -log = "0.4" -dirs = "4.0" -regex = "1.5" -runas = "0.2" -ignore = "0.4" -console = "0.15" -sys-info = "0.9" -tabwriter = "1.2" -tokio-tar = "0.3" -dialoguer = "0.10" -webbrowser = "0.7" -portpicker = "0.1" -serde_yaml = "0.9" -serde_json = "1.0" -serde_repr = "0.1" -futures-util = "0.3" -clap = { version = "3.2", features = ["derive"] } -fern = { version = "0.6", features = ["colored"] } -tokio = { version = "1", features = ["full"] } -serde = { version = "1.0", features = ["derive"] } -hyper = { version = "0.14", features = ["server"] } -ctrlc = { version = "3.0", features = ["termination"] } -async-compression = { version = "0.3", features = ["tokio", "gzip", "zlib"] } -reqwest = { version = "0.11", features = [ +log = "0.4.17" +dirs = "4.0.0" +regex = "1.6.0" +runas = "0.2.1" +ignore = "0.4.18" +console = "0.15.1" +sys-info = "0.9.1" +tabwriter = "1.2.1" +tokio-tar = "0.3.0" +dialoguer = "0.10.2" +webbrowser = "0.7.1" +portpicker = "0.1.1" +serde_yaml = "0.9.4" +serde_json = "1.0.82" +serde_repr = "0.1.8" +futures-util = "0.3.21" +clap = { version = "3.2.16", features = ["derive"] } +fern = { version = "0.6.1", features = ["colored"] } +tokio = { version = "1.20.1", features = ["full"] } +serde = { version = "1.0.141", features = ["derive"] } +hyper = { version = "0.14.20", features = ["server"] } +ctrlc = { version = "3.2.2", features = ["termination"] } +async-compression = { version = "0.3.14", features = ["tokio", "gzip", "zlib"] } + +# *nix only deps +[target.'cfg(not(windows))'.dependencies] +reqwest = { version = "0.11.11", features = [ "json", "multipart", "rustls-tls-webpki-roots", ], default-features = false } -tokio-tungstenite = { version = "0.17", features = ["rustls-tls-webpki-roots"] } +tokio-tungstenite = { version = "0.17.2", features = [ + "rustls-tls-webpki-roots", +] } -# windows only +# windows only deps [target.'cfg(windows)'.dependencies] async_zip = "0.0.8" +reqwest = { version = "0.11.11", features = [ + "json", + "multipart", + "native-tls", +] } +tokio-tungstenite = { version = "0.17.2", features = ["native-tls"] } + +[target.'cfg(windows)'.build-dependencies] +winapi = { version = "0.3.9", features = ["winuser"] } +static_vcruntime = "2.0.0" +winres = "0.1.12" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7861856 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..c73578e --- /dev/null +++ b/build.rs @@ -0,0 +1,35 @@ +include!("src/commands/update/parse.rs"); + +#[cfg(windows)] +fn main() { + extern crate winapi; + extern crate winres; + + // add the resource to the executable + let mut resource = winres::WindowsResource::new(); + resource.set_icon("build/windows/resources/hop.ico"); + resource.set_language(winapi::um::winnt::MAKELANGID( + winapi::um::winnt::LANG_ENGLISH, + winapi::um::winnt::SUBLANG_ENGLISH_US, + )); + + // write the version to the resource + let (major, minor, patch, release) = version(env!("CARGO_PKG_VERSION")).unwrap(); + + resource.set_version_info( + winres::VersionInfo::PRODUCTVERSION, + (major as u64) << 48 + | (minor as u64) << 32 + | (patch as u64) << 16 + | (release.unwrap_or(0) as u64 + 1), + ); + + // compile the resource file + resource.compile().unwrap(); + + // fix VCRUNTIME140.dll + static_vcruntime::metabuild(); +} + +#[cfg(not(windows))] +fn main() {} diff --git a/build/windows/main.wxs b/build/windows/main.wxs new file mode 100644 index 0000000..d7db329 --- /dev/null +++ b/build/windows/main.wxs @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + + + + + + + + + + + + + + + + diff --git a/build/windows/resources/Banner.bmp b/build/windows/resources/Banner.bmp new file mode 100644 index 0000000000000000000000000000000000000000..171992f48cfdfa4f52a0117747b5d7300c49f2e8 GIT binary patch literal 114514 zcmeI5d2CJT8^>Gw5;OQ&A~C{@C6*CuGKvHt2n|6bmOsS4jKq?vOpKlKGej&6Q~OdB zBk{BRP+RF(S|irB{LtzYL5mi}l;`(;-Jh4ksm?|MBtQZrKmsK2

zMjjf^Guhi>o)w5JjS3OO2=ysgy(W*zO9LqycycsGa=smu?yH`x`UTaGs?J6NBtQZrKmvYC0Cw`zr%&at zzhJ`p)}YawH*c1ppdcAMc(7c$bjfF1J0~Ycva_=Vl0`OmB4mv(QUgpf1BlG9amz0zg zuX+oc7~N<%4{UAd{_Weh<;4q3HNR`-*sBgSm@?Afw(=~8W1d)nLP z??C%6Uc9Ka7&biYXRGG{#F<0W;akTzFdjTV;93}`mu98gUcSQJBtQZrKmsICFbF`C z;SUcD4SlQE(8}7iYis{B{M6=(4kth4c&&l4V|}phVVF#S+_lQ@g)h6011!)2^35MuyZl* zjQMN$!=aC!{imOPlBA@hT=C=3?EClc%gmWGB``2hnl^1J8#Zik)KmE0!^6X+e*OAV zp+W^&v}lozaWnhJ;RD~keY<`R@Ei;L)hQ!ZFfCNZ@1W2Gj z5P%LJI&?_7b?cT(8x74aU%tG|n>SBx-MaN&Y&dQZnwgrKDhCf9l$e+pfe+oO<{9?E zHa~jwsMc;gFPM+VnD+1AFTugVwqwF`#DN0`EdA;Q0z3yv0wh2JBtQZ_5J0UI_`ESk zZ0NJy7Mczng>T#J$A)e{d-hEG#LfC^H5?p+`DlE{Y$wA{f91**nKEUHo+Gy#4?dqT zVS@JQe@M+2t8wu&5+DH*AORA{j|8B*sFkv1%NBvJ*-0C*4|C6xCr{RSUrxU7kGWUq zH*&cVm)5*_bFX7+(4c{?we}h7qJGTn@Vg{H0wh2JB=AWHz&5>l^{NaRGQ_Jk8hYNS zQ6q_rjMV;bv#tHHgTnb9KYlE`ckh;36KB@ zkU)MQfVk|fTerHhu?@|vT)DDr+O+AjX*TR-oWE+-s;-|SU~A(!!bPo>{D7TfAOR8} z0TLhqp9sJQjhbaY{`jMmD_737KKAe5Uw;4nck#tHj=5_$bKJNAg0M% z82{+eqb=j(e1gJ*Nq_`MfCNY&9}+;m)$!xUrCqyruC)>K*{E}tmX_vPgW>PKd-txO z2B{m}#gx^?Ti z)<)!CA3Ju;CtXDDHuA{Ot#Z4~BZS7oKaRRAM(tELnvMIw^8~)jMgk;20wh2J{zL$= z*&|1ebgheDef5?6^2;werrV9Z3|2S}HuLo9({*mQo3+94J^05@oH!wU`}TGHJOOJ?mIQ#cbR5=+Q&hOhG=i+lCl$)EA}zVCvmQcgXUv!(*RNmCRb$kShfx=$ zOP4P1)kSI1qJ_?*M*N$%hFCPzAz!?Bv0yIUJT9yExF5`EvylJ^kN^pgfIksHoiR6Y z*~pXLwQHBISK{XWk!ywgZLE2Xbwxb2_3N*{mN8?-=$d72Y;DAx!@h_1d!EPcHGKG( zJ7*&S5+DH*AOU|OfZQlIwNxfen&etz;m?Ne8@bhXHvA7i{GjWDyRo&Q>sTvf;>3xr zG#gru=MXj$AOR8}0TS>h0&Z;Vpr9bxxN)OAeE87ots~|vAt6D>syVGUg6D)0BSy%D z3m06)kYmkGtQYd#ci*|zZLfpn0VF^IBtQZrP=E-yv9qyu2y()_)hWe(tTnP=!2(xn zaUu5Y*I$3t&jOgYc528ii;j+#K7IPQ(rnt36KB@kbplCz}g^obI#D!4jnq^{Ajy*XJ{#W=BV+FId81dX%`!2^?B{uwPp6~ z*}86-x4LTZkFQ+0QojHGd&g_weufVp?oU4x?}Y?NfCNZ@1jJi@HfoC>K72S=ZEeb8fI+#a?Z-9*iNPq-L zfCT)Bz|NgJbzYR6o_6ovU3Tx@t?QP-{|((tPfyozW~iYS5)vY9+O&~UrAj&KsNMPT zIo1h7PFQSgtfP+{&k2_=U)Jk}I-L)7&`>*#jRZ)51W14c{E0wZT%2RQal~oEf4+J1 zX4$`gzt%#m5rVp8?c2APs#U9guvUBOZk;-H^co_FId{t0PEAeKHO{J4t7dy$)*JVy z|4`lw36KB@kbpq|8aQgyDBC!+B1MV_;?R)q)v;qofenjT^U|eD+iIq#7Q20o>$Ggy zQkE@SCK!|5+&1RU*R5M8ty;CRyguUTFqe(B!`MiG1W14cNWh;6U=BGvJlv=Cv)$^j zugAf^j(TgDA4k1XE8Wh_%+$Vm*wR+#$MXbq-!5j(pME>u3ki?_36MbHB9NV(Eio}M zIycHn1HbfVsB4O~NH%TSBxz}Bx%}jqPlt~_I5^l+vr)73*s)`|V&)3hugbe60TLhq z67WX?i0evDPL{D_$J+YG^Fp^#TRb8nLXwh_1oc!fPT1Y>jc?hq#qt>gdD)nIzopjP z#_?<%lC*&t5m6ywyDRB8z)nz zPL)A}21&ho^(@DUeOOBbHP6{dfCNZ@1W3Ri3BV>r%oggJzHb$mc?QIC8Kt9ySsn0TLhq5+DI<0*K2- z9$0jAw2u8kjuqDAFnrdZYm4iIgoMbULx*%e7vsaNe;d6wE!hZQEAItRc=DdTjX7vBi6Qj+inWhvV_R<;$1r zwKlPyH_i(`IOEKG`Biu<36KB@kN^od6UfQQk?ibjdHndX+`fHV;^N|D=gyt7aN$C2 zGk5LURol?DYSq$PyoW7~{W$LI*|Yk4u&Hq#oR5tJNPq-LfCNZ@1W14cNPq-LfCNaO HU=a8}vEDa+ literal 0 HcmV?d00001 diff --git a/build/windows/resources/Dialog.bmp b/build/windows/resources/Dialog.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8cd023b9aaeb5186167d2daa00bc2240f111cea2 GIT binary patch literal 615402 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 z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 r009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0+V5`q5%UoEDG literal 0 HcmV?d00001 diff --git a/build/windows/resources/hop.ico b/build/windows/resources/hop.ico new file mode 100644 index 0000000000000000000000000000000000000000..fdf5e8197e31cfefc6a8357133f5eb2fb154b4a4 GIT binary patch literal 107473 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 literal 0 HcmV?d00001 diff --git a/scripts/build.ps1 b/scripts/build.ps1 new file mode 100644 index 0000000..5a470ac --- /dev/null +++ b/scripts/build.ps1 @@ -0,0 +1,7 @@ +# powershell -ExecutionPolicy Bypass -File .\scripts\build.ps1 + +cargo build --release --target x86_64-pc-windows-msvc + +cargo wix -I .\build\windows\main.wxs -v --nocapture --target x86_64-pc-windows-msvc --output target/wix/hop-x86_64-pc-windows-msvc.msi + +target/wix/hop-x86_64-pc-windows-msvc.msi \ No newline at end of file diff --git a/src/commands/update/parse.rs b/src/commands/update/parse.rs new file mode 100644 index 0000000..60cf1da --- /dev/null +++ b/src/commands/update/parse.rs @@ -0,0 +1,23 @@ +use std::num::ParseIntError; + +pub fn version(version: &str) -> Result<(u16, u16, u16, Option), ParseIntError> { + let tag = if let Some(stripped) = version.strip_prefix('v') { + stripped + } else { + version + }; + + let mut pre = tag.split('-'); + let mut parts = pre.next().unwrap_or(tag).split('.'); + + let major = parts.next().unwrap_or("0").parse()?; + let minor = parts.next().unwrap_or("0").parse()?; + let patch = parts.next().unwrap_or("0").parse()?; + + let prelease = match pre.next() { + Some(prelease) => Some(prelease.parse()?), + None => None, + }; + + Ok((major, minor, patch, prelease)) +}