diff --git a/Cargo.toml b/Cargo.toml index be50f6a..360923f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ env_logger = "0.11" indoc = "2.0" log = "0.4" node-semver = "2.1" -sysinfo = "0.31" +sysinfo = "0.32" tar = "0.4" tempfile = "3.13" thiserror = "1.0" @@ -42,7 +42,7 @@ flate2 = "1.0" walkdir = "2.5" indicatif = { version = "0.17", features = ["improved_unicode"] } regex = "1.11" - +xz2 = "0.1" [dev-dependencies] pretty_assertions = "1.4" duct = "0.13" @@ -75,3 +75,8 @@ strip = true [package.metadata.cargo-shear] ignored = ["csv", "junction"] + +[package.metadata.binstall] +pkg-url = "{ repo }/releases/download/pactup_v{ version }/{ name }-{ target-family }-{ target-arch }-{ target-libc }{ archive-suffix }" +bin-dir = "{ name }-{ target-family }-{ target-arch }-{ target-libc }{ binary-ext }" +pkg-fmt = "tar.gz" diff --git a/README.md b/README.md index c642a00..41e1ee5 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Where `` can be one of the supported shells: - `bash` - `zsh` - `fish` -- `power-shell` +- `powershell` Please follow your shell instructions to install them. @@ -143,7 +143,7 @@ pactup env --use-on-cd --shell fish | source Add the following to the end of your profile file: ```powershell -pactup env --use-on-cd --shell power-shell | Out-String | Invoke-Expression +pactup env --use-on-cd --shell powershell | Out-String | Invoke-Expression ``` - For macOS/Linux, the profile is located at `~/.config/powershell/Microsoft.PowerShell_profile.ps1` @@ -155,7 +155,7 @@ pactup env --use-on-cd --shell power-shell | Out-String | Invoke-Expression #### Windows Command Prompt aka Batch aka WinCMD -pactup is also supported but is not entirely covered. [You can set up a startup script](https://superuser.com/a/144348) and append the following lines: +pactup is also supported but is not entirely covered. You can set up a startup script for [cmd.exe](https://superuser.com/a/144348) or [Windows Terminal](https://superuser.com/a/1855283) and append the following lines: ```batch @echo off diff --git a/package.json b/package.json index 2603926..f8dfc2b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "url": "git@github.com:kadena-community/pactup.git" }, "author": "Salama Ashoush ", - "packageManager": "pnpm@9.12.0", + "packageManager": "pnpm@9.12.2", "license": "MIT", "description": "Linter for the JavaScript Oxidation Compiler", "keywords": [ @@ -45,18 +45,28 @@ "devDependencies": { "@changesets/changelog-github": "0.5.0", "@changesets/cli": "2.27.9", - "@types/node": "^22.7.4", + "@types/node": "^22.7.9", "@types/shell-escape": "^0.2.3", "chalk": "^5.3.0", "cmd-ts": "0.13.0", "cross-env": "^7.0.3", - "execa": "9.4.0", + "execa": "9.4.1", "lerna-changelog": "2.2.0", "prettier": "3.3.3", "pv": "1.0.1", "shell-escape": "^0.2.0", "svg-term-cli": "2.1.1", "tsx": "^4.19.1", - "typescript": "^5.6.2" + "typescript": "^5.6.3" + }, + "pnpm": { + "overrides": { + "xmldom@<0.5.0": ">=0.5.0", + "node-fetch@<2.6.7": ">=2.6.7", + "trim-newlines@<3.0.1": ">=3.0.1", + "plist@<3.0.5": ">=3.0.5", + "nth-check@<2.0.1": ">=2.0.1", + "micromatch@<4.0.8": ">=4.0.8" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index edac1f3..3792b05 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,14 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + xmldom@<0.5.0: '>=0.5.0' + node-fetch@<2.6.7: '>=2.6.7' + trim-newlines@<3.0.1: '>=3.0.1' + plist@<3.0.5: '>=3.0.5' + nth-check@<2.0.1: '>=2.0.1' + micromatch@<4.0.8: '>=4.0.8' + importers: .: @@ -15,8 +23,8 @@ importers: specifier: 2.27.9 version: 2.27.9 '@types/node': - specifier: ^22.7.4 - version: 22.7.4 + specifier: ^22.7.9 + version: 22.7.9 '@types/shell-escape': specifier: ^0.2.3 version: 0.2.3 @@ -30,8 +38,8 @@ importers: specifier: ^7.0.3 version: 7.0.3 execa: - specifier: 9.4.0 - version: 9.4.0 + specifier: 9.4.1 + version: 9.4.1 lerna-changelog: specifier: 2.2.0 version: 2.2.0 @@ -46,13 +54,13 @@ importers: version: 0.2.0 svg-term-cli: specifier: 2.1.1 - version: 2.1.1 + version: 2.1.1(encoding@0.1.13) tsx: specifier: ^4.19.1 version: 4.19.1 typescript: - specifier: ^5.6.2 - version: 5.6.2 + specifier: ^5.6.3 + version: 5.6.3 packages: @@ -374,8 +382,8 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@22.7.4': - resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} + '@types/node@22.7.9': + resolution: {integrity: sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==} '@types/node@8.10.66': resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} @@ -386,6 +394,10 @@ packages: '@types/shell-escape@0.2.3': resolution: {integrity: sha512-xZWkMuQkn1I20gEzhYRa4/t1pwZ8XiIkqGA1Iee1D2IgAUIRLr57nrgJgF2QmHEfkfVzOM59gi/4xp6V+Aq+4A==} + '@xmldom/xmldom@0.8.10': + resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} + engines: {node: '>=10.0.0'} + abcq@1.0.2: resolution: {integrity: sha512-Fjk/LXe1aHL7zQcjqDoKhYuIdB3iyv1S3/YJNPe6D0QjJuKXKq+N6ei5kVZtsr0Rp6ueTmhW4yZlLQaIKptyFg==} @@ -457,8 +469,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - base64-js@1.2.0: - resolution: {integrity: sha512-hURVuTTGLOppKhjSe9lZy4NCjnvaIAF/juwazv4WtHwsk5rxKrU1WbxN+XtwKDSvkrNbIIaTBQd9wUsSwruZUg==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} @@ -764,8 +776,8 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - execa@9.4.0: - resolution: {integrity: sha512-yKHlle2YGxZE842MERVIplWwNH5VYmqqcPFgtnlU//K8gxuFFXu0pwd/CrfXTumFpeEiufsP7+opT/bPJa1yVw==} + execa@9.4.1: + resolution: {integrity: sha512-5eo/BRqZm3GYce+1jqX/tJ7duA2AnE39i88fuedNFUV8XxGxUpF3aWkBRfbUcjV49gCkvS/pzc0YrCPhaIewdg==} engines: {node: ^18.19.0 || >=20.5.0} extendable-error@0.1.7: @@ -1215,8 +1227,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} mimic-fn@2.1.0: @@ -1287,9 +1299,6 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - node-fetch@1.7.3: - resolution: {integrity: sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==} - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -1318,8 +1327,8 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} - nth-check@1.0.2: - resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -1476,8 +1485,9 @@ packages: resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} engines: {node: '>=0.10.0'} - plist@2.1.0: - resolution: {integrity: sha512-yirJ+8SSb8o7pkfyNv+fTzUP0GbK52HMvh0MjMycCxvpL8rHiAfKhXU/3R5znSJnrGakV0WNZhr8yTR4//PjyA==} + plist@3.1.0: + resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} + engines: {node: '>=10.4.0'} possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} @@ -1866,9 +1876,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - trim-newlines@1.0.0: - resolution: {integrity: sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==} - engines: {node: '>=0.10.0'} + trim-newlines@5.0.0: + resolution: {integrity: sha512-kstfs+hgwmdsOadN3KgA+C68wPJwnZq4DN6WMDCvZapDWEF34W2TyPKN2v2+BJnZgIz5QOfxFeldLyYvdgRAwg==} + engines: {node: '>=14.16'} tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -1894,8 +1904,8 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - typescript@5.6.2: - resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true @@ -1969,14 +1979,9 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - xmlbuilder@8.2.2: - resolution: {integrity: sha512-eKRAFz04jghooy8muekqzo8uCSVNeyRedbuJrp0fovbLIi7wlsYtdUn3vBAAPq2Y3/0xMz2WMEUQ8yhVVO9Stw==} - engines: {node: '>=4.0'} - - xmldom@0.1.31: - resolution: {integrity: sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==} - engines: {node: '>=0.1'} - deprecated: Deprecated due to CVE-2021-21366 resolved in 0.5.0 + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} @@ -2094,7 +2099,7 @@ snapshots: '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 - micromatch: 4.0.7 + micromatch: 4.0.8 '@changesets/errors@0.2.0': dependencies: @@ -2130,7 +2135,7 @@ snapshots: '@changesets/errors': 0.2.0 '@manypkg/get-packages': 1.1.3 is-subdir: 1.2.0 - micromatch: 4.0.7 + micromatch: 4.0.8 spawndamnit: 2.0.0 '@changesets/logger@0.1.1': @@ -2366,7 +2371,7 @@ snapshots: '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.7.4 + '@types/node': 22.7.9 '@types/globby@6.1.0': dependencies: @@ -2382,7 +2387,7 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@22.7.4': + '@types/node@22.7.9': dependencies: undici-types: 6.19.8 @@ -2392,6 +2397,8 @@ snapshots: '@types/shell-escape@0.2.3': {} + '@xmldom/xmldom@0.8.10': {} + abcq@1.0.2: dependencies: tslib: 1.14.1 @@ -2472,7 +2479,7 @@ snapshots: balanced-match@1.0.2: {} - base64-js@1.2.0: {} + base64-js@1.5.1: {} better-path-resolve@1.0.0: dependencies: @@ -2652,7 +2659,7 @@ snapshots: boolbase: 1.0.0 css-what: 3.4.2 domutils: 1.7.0 - nth-check: 1.0.2 + nth-check: 2.1.1 css-tree@1.0.0-alpha.37: dependencies: @@ -2741,6 +2748,7 @@ snapshots: encoding@0.1.13: dependencies: iconv-lite: 0.6.3 + optional: true enquirer@2.4.1: dependencies: @@ -2892,7 +2900,7 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - execa@9.4.0: + execa@9.4.1: dependencies: '@sindresorhus/merge-streams': 4.0.0 cross-spawn: 7.0.3 @@ -2921,7 +2929,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 fastq@1.17.1: dependencies: @@ -3115,6 +3123,7 @@ snapshots: iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + optional: true ignore@5.3.1: {} @@ -3360,13 +3369,13 @@ snapshots: object-assign: 4.1.1 read-pkg-up: 1.0.1 redent: 1.0.0 - trim-newlines: 1.0.0 + trim-newlines: 5.0.0 merge-stream@2.0.0: {} merge2@1.4.1: {} - micromatch@4.0.7: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -3434,11 +3443,6 @@ snapshots: negotiator@0.6.3: {} - node-fetch@1.7.3: - dependencies: - encoding: 0.1.13 - is-stream: 1.1.0 - node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -3469,7 +3473,7 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 - nth-check@1.0.2: + nth-check@2.1.1: dependencies: boolbase: 1.0.0 @@ -3598,11 +3602,11 @@ snapshots: pinkie@2.0.4: {} - plist@2.1.0: + plist@3.1.0: dependencies: - base64-js: 1.2.0 - xmlbuilder: 8.2.2 - xmldom: 0.1.31 + '@xmldom/xmldom': 0.8.10 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 possible-typed-array-names@1.0.0: {} @@ -3924,7 +3928,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svg-term-cli@2.1.1: + svg-term-cli@2.1.1(encoding@0.1.13): dependencies: '@marionebl/sander': 0.6.1 chalk: 2.4.2 @@ -3934,13 +3938,15 @@ snapshots: guess-terminal: 1.0.0 macos-app-config: 1.0.1 meow: 3.7.0 - node-fetch: 1.7.3 - plist: 2.1.0 + node-fetch: 2.7.0(encoding@0.1.13) + plist: 3.1.0 svg-term: 1.3.1 svgo: 1.3.2 tempfile: 2.0.0 tempy: 0.2.1 term-schemes: 1.2.1 + transitivePeerDependencies: + - encoding svg-term@1.3.1: dependencies: @@ -4011,7 +4017,7 @@ snapshots: hex-rgb: 1.0.0 ini: 1.3.8 lodash: 4.17.21 - plist: 2.1.0 + plist: 3.1.0 require-from-string: 2.0.2 resolve-from: 4.0.0 terminal-default-colors: 1.0.2 @@ -4043,7 +4049,7 @@ snapshots: tr46@0.0.3: {} - trim-newlines@1.0.0: {} + trim-newlines@5.0.0: {} tslib@1.14.1: {} @@ -4086,7 +4092,7 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typescript@5.6.2: {} + typescript@5.6.3: {} unbox-primitive@1.0.2: dependencies: @@ -4170,9 +4176,7 @@ snapshots: wrappy@1.0.2: {} - xmlbuilder@8.2.2: {} - - xmldom@0.1.31: {} + xmlbuilder@15.1.1: {} xtend@4.0.2: {} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index bbf217f..bd40c68 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,4 @@ [toolchain] -channel = "1.81.0" +channel = "1.82" +components = ["rustfmt", "clippy"] profile = "default" diff --git a/scripts/install.sh b/scripts/install.sh index 32c331b..8da2c1c 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -214,7 +214,7 @@ setup_shell() { echo 'PACTUP_PATH="'"$INSTALL_DIR"'"' echo 'if [ -d "$PACTUP_PATH" ]; then' echo ' export PATH="$PACTUP_PATH:$PATH"' - echo ' eval "`fnm env --use-on-cd`"' + echo ' eval "`pactup env --use-on-cd`"' echo 'fi' } | tee -a "$CONF_FILE" diff --git a/src/archive/extract.rs b/src/archive/extract.rs index 537c59a..47e126a 100644 --- a/src/archive/extract.rs +++ b/src/archive/extract.rs @@ -48,29 +48,5 @@ impl From for Error { } } pub trait Extract { - fn extract_into>(self, path: P) -> Result<(), Error>; -} - -pub enum ArchiveType { - TarGz, - Zip, -} - -impl ArchiveType { - pub fn from(url: &url::Url) -> Result { - let archive_type = url - .path_segments() - .and_then(std::iter::Iterator::last) - .and_then(|last| last.split('.').last()) - .ok_or(Error::UnknownArchiveType { - content_type: "unknown".to_string(), - })?; - match archive_type { - "gz" => Ok(Self::TarGz), - "zip" => Ok(Self::Zip), - _ => Err(Error::UnknownArchiveType { - content_type: archive_type.to_string(), - }), - } - } + fn extract_into(self: Box, path: &Path) -> Result<(), Error>; } diff --git a/src/archive/mod.rs b/src/archive/mod.rs index 757fa8d..e7022e3 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -1,7 +1,51 @@ pub mod extract; -pub mod tar_gz; +pub mod tar; pub mod zip; +use std::io::Read; +use std::path::Path; + pub use self::extract::{Error, Extract}; -pub use self::tar_gz::TarGz; -pub use self::zip::Zip; +use self::tar::Tar; +use self::zip::Zip; + +pub enum Archive { + Zip, + TarXz, + TarGz, +} +impl Archive { + pub fn extract_archive_into(path: &Path, response: impl Read, url: &str) -> Result<(), Error> { + let extractor: Box = match Archive::from_url(url) { + Some(Self::Zip) => Box::new(Zip::new(response)), + Some(Self::TarXz) => Box::new(Tar::Xz(response)), + Some(Self::TarGz) => Box::new(Tar::Gz(response)), + None => { + return Err(Error::UnknownArchiveType { + content_type: url.to_string(), + }) + } + }; + extractor.extract_into(path)?; + Ok(()) + } + + pub fn from_url(url: &str) -> Option { + if url.ends_with(".tar.xz") { + Some(Self::TarXz) + } else if url.ends_with(".tar.gz") { + Some(Self::TarGz) + } else if std::path::Path::new(url) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("zip")) + { + Some(Self::Zip) + } else { + None + } + } + + pub fn supported() -> &'static [Self] { + &[Self::TarXz, Self::TarGz, Self::Zip] + } +} diff --git a/src/archive/tar_gz.rs b/src/archive/tar.rs similarity index 71% rename from src/archive/tar_gz.rs rename to src/archive/tar.rs index b6353e8..ed61442 100644 --- a/src/archive/tar_gz.rs +++ b/src/archive/tar.rs @@ -1,3 +1,5 @@ +use log::debug; + use super::extract::{Error, Extract}; use std::{io::Read, path::Path}; @@ -5,33 +7,38 @@ use std::{io::Read, path::Path}; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; -pub struct TarGz { - response: R, -} - -impl TarGz { - #[allow(dead_code)] - pub fn new(response: R) -> Self { - Self { response } - } +pub enum Tar { + /// Tar archive with XZ compression + Xz(R), + /// Tar archive with Gzip compression + Gz(R), } - -impl Extract for TarGz { - fn extract_into>(self, path: P) -> Result<(), Error> { - let gz_stream = flate2::read::GzDecoder::new(self.response); - let mut tar_archive = tar::Archive::new(gz_stream); +impl Tar { + fn extract_into_impl>(self, path: P) -> Result<(), Error> { + debug!("Decompressing tar archive"); + let stream: Box = match self { + Self::Xz(response) => Box::new(xz2::read::XzDecoder::new(response)), + Self::Gz(response) => Box::new(flate2::read::GzDecoder::new(response)), + }; + let mut tar_archive = tar::Archive::new(stream); tar_archive.set_preserve_permissions(false); tar_archive.set_preserve_ownerships(false); tar_archive.set_overwrite(true); + debug!("Extracting tar archive into {:?}", path.as_ref()); // First, extract everything, even if the permissions are restrictive tar_archive.unpack(&path)?; + debug!("Fixing permissions for extracted files and directories"); // Now recursively set permissions for all directories and files fix_permissions_recursively(path.as_ref())?; - Ok(()) } } +impl Extract for Tar { + fn extract_into(self: Box, path: &Path) -> Result<(), Error> { + self.extract_into_impl(path) + } +} // Helper function to recursively fix permissions cross-platform fn fix_permissions_recursively>(path: P) -> Result<(), Error> { diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 226a9e6..e826298 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -18,8 +18,7 @@ impl Zip { } impl Extract for Zip { - fn extract_into>(mut self, path: P) -> Result<(), Error> { - let path = path.as_ref(); + fn extract_into(mut self: Box, path: &Path) -> Result<(), Error> { let mut tmp_zip_file = tempfile().expect("Can't get a temporary file"); debug!("Created a temporary zip file"); @@ -87,13 +86,13 @@ mod tests { #[test_log::test] fn test_zip_extraction() { - let temp_dir = tempfile::tempdir().expect("Can't create a temp directory"); + let temp_dir = &tempfile::tempdir().expect("Can't create a temp directory"); let response = crate::http::get( "https://github.com/kadena-io/pact/releases/download/v4.12.0/pact-4.12.0-linux-20.04.zip", ) .expect("Can't make request to pact v4.12.0 zip file"); - Zip::new(response) - .extract_into(&temp_dir) + Box::new(Zip::new(response)) + .extract_into(temp_dir.as_ref()) .expect("Can't unzip files"); let node_file = temp_dir.as_ref().join("pact"); assert!(node_file.exists()); diff --git a/src/cli.rs b/src/cli.rs index ae57ea2..6a40fdd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -14,7 +14,7 @@ pub enum SubCommand { LsLocal(commands::ls_local::LsLocal), /// Install a new Pact version - #[clap(name = "install", bin_name = "install")] + #[clap(name = "install", bin_name = "install", visible_aliases = &["i"])] Install(commands::install::Install), /// Change Pact version @@ -67,7 +67,7 @@ pub enum SubCommand { /// /// > Warning: when providing an alias, it will remove the Pact version the alias /// > is pointing to, along with the other aliases that point to the same version. - #[clap(name = "uninstall", bin_name = "uninstall")] + #[clap(name = "uninstall", bin_name = "uninstall", visible_aliases = &["uni"])] Uninstall(commands::uninstall::Uninstall), /// Print the path to installed Pact version diff --git a/src/config.rs b/src/config.rs index 4818913..3bb355a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -79,8 +79,12 @@ pub struct PactupConfig { version_file_strategy: VersionFileStrategy, /// Resolve `engines.pact` field in `package.json` whenever a `.pact-version` or `.pactrc` file is not present. - /// Experimental: This feature is subject to change. + /// This feature is enabled by default. To disable it, provide `--resolve-engines=false`. + /// /// Note: `engines.pact` can be any semver range, with the latest satisfying version being resolved. + /// Note 2: If you disable it, please open an issue on GitHub describing _why_ you disabled it. + /// In the future, disabling it might be a no-op, so it's worth knowing any reason to + /// do that. #[clap( long, env = "PACTUP_RESOLVE_ENGINES", @@ -88,7 +92,11 @@ pub struct PactupConfig { hide_env_values = true, verbatim_doc_comment )] - resolve_engines: bool, + #[expect( + clippy::option_option, + reason = "clap Option> supports --x and --x=value syntaxes" + )] + resolve_engines: Option>, #[clap(skip)] directories: Directories, @@ -105,7 +113,7 @@ impl Default for PactupConfig { arch: PlatformArch::default(), version_file_strategy: VersionFileStrategy::default(), directories: Directories::default(), - resolve_engines: false, + resolve_engines: None, } } } @@ -116,7 +124,7 @@ impl PactupConfig { } pub fn resolve_engines(&self) -> bool { - self.resolve_engines + self.resolve_engines.flatten().unwrap_or(true) } pub fn log_level(&self) -> LogLevel { diff --git a/src/directories.rs b/src/directories.rs index 5d6f4db..1a7e4c7 100644 --- a/src/directories.rs +++ b/src/directories.rs @@ -25,7 +25,7 @@ fn cache_dir(basedirs: &impl BaseStrategy) -> PathBuf { xdg_dir("XDG_CACHE_HOME").unwrap_or_else(|| basedirs.cache_dir()) } -/// A helper struct for directories in fnm that uses XDG Base Directory Specification +/// A helper struct for directories in pactup that uses XDG Base Directory Specification /// if applicable for the platform. #[derive(Debug)] pub struct Directories( diff --git a/src/downloader.rs b/src/downloader.rs index a4e4ad8..69c21e1 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -1,13 +1,10 @@ -use crate::archive; -use crate::archive::extract::ArchiveType; -use crate::archive::{Error as ExtractError, Extract}; +use crate::archive::{Archive, Error as ExtractError}; use crate::directory_portal::DirectoryPortal; use crate::progress::ResponseProgress; use crate::system_info::PlatformArch; use crate::version::Version; use indicatif::ProgressDrawTarget; use log::debug; -use std::io::Read; use std::path::Path; use std::path::PathBuf; use thiserror::Error; @@ -30,8 +27,8 @@ pub enum Error { #[from] source: ExtractError, }, - // #[error("The downloaded archive is empty")] - // TarIsEmpty, + #[error("The downloaded archive is empty")] + TarIsEmpty, #[error("{} for {} not found upstream.\nYou can `pactup ls-remote` to see available versions or try a different `--arch`.", version, arch)] VersionNotFound { version: Version, @@ -41,18 +38,6 @@ pub enum Error { VersionAlreadyInstalled { path: PathBuf }, } -fn extract_archive_into( - path: impl AsRef, - response: impl Read, - download_url: &Url, -) -> Result<(), Error> { - let _ = match ArchiveType::from(download_url)? { - ArchiveType::TarGz => archive::TarGz::new(response).extract_into(path), - ArchiveType::Zip => archive::Zip::new(response).extract_into(path), - }; - Ok(()) -} - /// Install a pact asset from a URL into a directory pub fn install_pact_dist>( version: &Version, @@ -89,40 +74,38 @@ pub fn install_pact_dist>( debug!("Creating directory portal"); let portal = DirectoryPortal::new_in(&temp_installations_dir, version_installation_dir); - debug!("Going to call for {}", download_url); - let response = crate::http::get(download_url.as_str())?; - - if response.status() == 404 { - return Err(Error::VersionNotFound { - version: version.clone(), - arch, - }); - } + for _ in Archive::supported() { + debug!("Going to call for {}", download_url); + let response = crate::http::get(download_url.as_str())?; - debug!("Extracting response..."); - if show_progress { - extract_archive_into( - &portal, - ResponseProgress::new(response, ProgressDrawTarget::stderr()), - download_url, - )?; - } else { - extract_archive_into(&portal, response, download_url)?; - } - // extract_archive_into(&portal, response, download_url)?; - debug!("Extraction completed"); + if !response.status().is_success() { + continue; + } - // let installed_directory = std::fs::read_dir(&portal)? - // .next() - // .ok_or(Error::TarIsEmpty)??; - // let installed_directory = installed_directory.path(); + debug!("Extracting response..."); + if show_progress { + Archive::extract_archive_into( + portal.as_ref(), + ResponseProgress::new(response, ProgressDrawTarget::stderr()), + download_url.as_str(), + )?; + } else { + Archive::extract_archive_into(portal.as_ref(), response, download_url.as_str())?; + } + debug!("Extraction completed"); + std::fs::read_dir(&portal)? + .next() + .ok_or(Error::TarIsEmpty)??; - // let renamed_installation_dir = portal.join("installation"); - // std::fs::rename(installed_directory, renamed_installation_dir)?; + portal.teleport()?; - portal.teleport()?; + return Ok(()); + } - Ok(()) + Err(Error::VersionNotFound { + version: version.clone(), + arch, + }) } #[cfg(test)] diff --git a/src/shell/bash.rs b/src/shell/bash.rs index f99d325..7f9433e 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -1,7 +1,7 @@ use crate::version_file_strategy::VersionFileStrategy; use super::shell::Shell; -use indoc::{formatdoc, indoc}; +use indoc::formatdoc; use std::path::Path; #[derive(Debug)] @@ -26,15 +26,21 @@ impl Shell for Bash { } fn use_on_cd(&self, config: &crate::config::PactupConfig) -> anyhow::Result { + let version_file_exists_condition = if config.resolve_engines() { + "-f .pact-version || -f .pactrc || -f package.json" + } else { + "-f .pact-version || -f .pactrc" + }; let autoload_hook = match config.version_file_strategy() { - VersionFileStrategy::Local => indoc!( - r" - if [[ -f .pact-version || -f .pactrc ]]; then + VersionFileStrategy::Local => formatdoc!( + r#" + if [[ {version_file_exists_condition} ]]; then pactup use --silent-if-unchanged fi - " + "#, + version_file_exists_condition = version_file_exists_condition, ), - VersionFileStrategy::Recursive => r"pactup use --silent-if-unchanged", + VersionFileStrategy::Recursive => String::from(r"pactup use --silent-if-unchanged"), }; Ok(formatdoc!( r#" diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 3f2a1eb..4ff00cc 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -1,7 +1,7 @@ use crate::version_file_strategy::VersionFileStrategy; use super::shell::Shell; -use indoc::{formatdoc, indoc}; +use indoc::formatdoc; use std::path::Path; #[derive(Debug)] @@ -26,15 +26,21 @@ impl Shell for Fish { } fn use_on_cd(&self, config: &crate::config::PactupConfig) -> anyhow::Result { + let version_file_exists_condition = if config.resolve_engines() { + "test -f .pact-version -o -f .pactrc -o -f package.json" + } else { + "test -f .pact-version -o -f .pactrc" + }; let autoload_hook = match config.version_file_strategy() { - VersionFileStrategy::Local => indoc!( - r" - if test -f .pact-version -o -f .pactrc + VersionFileStrategy::Local => formatdoc!( + r#" + if {version_file_exists_condition} pactup use --silent-if-unchanged - end - " + fi + "#, + version_file_exists_condition = version_file_exists_condition, ), - VersionFileStrategy::Recursive => r"pactup use --silent-if-unchanged", + VersionFileStrategy::Recursive => String::from(r"pactup use --silent-if-unchanged"), }; Ok(formatdoc!( r#" diff --git a/src/shell/powershell.rs b/src/shell/powershell.rs index a8e4c10..2569f91 100644 --- a/src/shell/powershell.rs +++ b/src/shell/powershell.rs @@ -1,7 +1,7 @@ use crate::version_file_strategy::VersionFileStrategy; use super::Shell; -use indoc::{formatdoc, indoc}; +use indoc::formatdoc; use std::path::Path; #[derive(Debug)] @@ -26,13 +26,19 @@ impl Shell for PowerShell { } fn use_on_cd(&self, config: &crate::config::PactupConfig) -> anyhow::Result { + let version_file_exists_condition = if config.resolve_engines() { + "(Test-Path .pactrc) -Or (Test-Path .pact-version) -Or (Test-Path package.json)" + } else { + "(Test-Path .pactrc) -Or (Test-Path .pact-version)" + }; let autoload_hook = match config.version_file_strategy() { - VersionFileStrategy::Local => indoc!( - r" - If ((Test-Path .pactrc) -Or (Test-Path .pact-version)) { & pactup use --silent-if-unchanged } - " + VersionFileStrategy::Local => formatdoc!( + r#" + If ({version_file_exists_condition}) {{ & pactup use --silent-if-unchanged }} + "#, + version_file_exists_condition = version_file_exists_condition, ), - VersionFileStrategy::Recursive => r"pactup use --silent-if-unchanged", + VersionFileStrategy::Recursive => String::from(r"pactup use --silent-if-unchanged"), }; Ok(formatdoc!( r#" diff --git a/src/shell/shell.rs b/src/shell/shell.rs index 9e81923..483eb60 100644 --- a/src/shell/shell.rs +++ b/src/shell/shell.rs @@ -18,6 +18,7 @@ pub enum Shells { Bash, Zsh, Fish, + #[clap(name = "powershell", alias = "power-shell")] PowerShell, #[cfg(windows)] Cmd, diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 6b3657b..62ec0fe 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -1,7 +1,7 @@ use crate::version_file_strategy::VersionFileStrategy; use super::shell::Shell; -use indoc::{formatdoc, indoc}; +use indoc::formatdoc; use std::path::Path; #[derive(Debug)] @@ -30,15 +30,21 @@ impl Shell for Zsh { } fn use_on_cd(&self, config: &crate::config::PactupConfig) -> anyhow::Result { + let version_file_exists_condition = if config.resolve_engines() { + "-f .pact-version || -f .pactrc || -f package.json" + } else { + "-f .pact-version || -f .pactrc" + }; let autoload_hook = match config.version_file_strategy() { - VersionFileStrategy::Local => indoc!( - r" - if [[ -f .pact-version || -f .pactrc ]]; then - pactup use --silent-if-unchanged - fi - " + VersionFileStrategy::Local => formatdoc!( + r#" + if [[ {version_file_exists_condition} ]]; then + pactup use --silent-if-unchanged + fi + "#, + version_file_exists_condition = version_file_exists_condition, ), - VersionFileStrategy::Recursive => r"pactup use --silent-if-unchanged", + VersionFileStrategy::Recursive => String::from(r"pactup use --silent-if-unchanged"), }; Ok(formatdoc!( r#"