Compare commits

...

699 Commits

Author SHA1 Message Date
renovate[bot]
b71e944797 fix(deps): update rust crate etcetera to v0.11.0 2025-11-15 16:07:27 +00:00
Ehren Bendler
9ec8e83f41 chore(deps): update some dependencies (#1512) 2025-11-15 17:05:48 +01:00
renovate[bot]
c70984d458 chore(deps): update github/codeql-action action to v4.31.3 (#1483)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 13:02:36 +01:00
Gideon
a3503c0c70 refactor: remove unnecessary cfg-if dependency (#1509) 2025-11-15 12:47:54 +01:00
Gideon
ca2d16edfd ci(lint_pr): run on synchronize, and add zizmor ignore (#1508) 2025-11-15 10:56:42 +01:00
pre-commit-ci[bot]
722b1ad09e chore(pre-commit): autoupdate (#1464)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-11-15 10:55:29 +01:00
Gideon
743845a66b fix(elan): skip running elan update on elan >=4.0.0 (#1507) 2025-11-15 10:46:18 +01:00
Gideon
2594f4c0fb docs: improve issue templates (#1235)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-15 10:07:55 +01:00
Gideon
639d055f9a feat: print summary and run post commands when (q)uit is used (#1254) 2025-11-15 10:03:46 +01:00
Gideon
ea2ccdd69f chore(deps): bump mac-notification-sys, use main branch temporarily (#1506) 2025-11-15 08:58:37 +01:00
Gideon
84a50afa83 chore: replace Dependabot with Renovate (#1486) 2025-11-15 08:22:27 +01:00
renovate[bot]
b13c1bd2d7 chore(deps): lock file maintenance (#1481)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: GideonBear <87426140+GideonBear@users.noreply.github.com>
2025-11-14 19:52:50 +01:00
Gideon
7749f41d56 fix(deps): Fix non-locked install on older version of Rust (#1485) 2025-11-14 19:33:56 +01:00
Gideon
593a2a33d9 fix(deps): Fix non-locked install on older version of Rust (#1482) 2025-11-14 19:20:12 +01:00
renovate[bot]
4f693aeaf3 chore(deps): pin dependencies (#1478)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 18:35:35 +01:00
renovate[bot]
c3d34184d0 chore(deps): update actions/dependency-review-action action to v4.8.2 (#1479)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-14 18:34:49 +01:00
Gideon
4aa224de87 chore: Add Renovate (#1477) 2025-11-14 18:23:17 +01:00
Andre Toerien
320b13c06b fix(bun): skip self-update if not installed via official script (#1476)
Co-authored-by: Steve Lau <stevelauc@outlook.com>
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-11-14 08:51:31 +01:00
Izzy Meyer
907d778c55 fix(openbsd): fix compilation on OpenBSD (#1473)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-11-12 18:38:41 +01:00
Stuart Reilly
f3fccb86c0 refactor: Replace main's self update with a proper step call (#1470)
Co-authored-by: Stuart Reilly <sreilly@scottlogic.com>
2025-11-11 17:31:04 +01:00
Andre Toerien
bb4afb71e9 feat: run pre_sudo before pre_commands (#1469) 2025-11-11 16:17:00 +01:00
Gideon
ec8d30f634 ci(release): Fix homebrew releases (#1468) 2025-11-11 16:12:50 +01:00
Rubin Bhandari
50d318641a feat(chezmoi): add exclude_encrypted config (#1453)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-11-10 21:12:40 +01:00
github-actions[bot]
c5267f6087 chore: release v16.2.1 (#1462)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-10 20:07:08 +01:00
Gideon
d80e8f64d1 fix(release): Use bash in Windows to fix powershell issues (#1461) 2025-11-10 19:18:51 +01:00
Gideon
c6f2e0cc44 fix(release): Fix .deb distribution (#1460) 2025-11-10 19:18:29 +01:00
Gideon
99c3e8af26 fix(release): Fix .deb distribution (#1458) 2025-11-10 18:47:55 +01:00
github-actions[bot]
30d3537c0e chore: release v16.2.0 (#1407)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-10 18:31:28 +01:00
Gideon
90cb16e3d0 fix(release): fix homebrew releases by migrating to dawidd6/action-homebrew-bump-formula (#1457) 2025-11-10 18:27:32 +01:00
Gideon
5192a0f1dc fix(mise): fix mise self-update failing when installed via a package manager (#1456) 2025-11-10 18:20:40 +01:00
Gideon
bec7edf1fc fix(release): Add man page to .deb distribution (#1455) 2025-11-10 18:12:49 +01:00
Bodebojo
051784ac0d fix(self-update): fix windows self-update reporting failure on successful self-update (#1452) 2025-11-10 17:04:03 +01:00
PandaMimo
17d715479a feat(mise): run mise self-update (#1450)
Co-authored-by: Milo <milo@example.com>
2025-11-10 14:16:49 +01:00
Bodebojo
39a90f5ebe fix(pkgfile): make pkgfile opt-in (#1449)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-11-10 14:11:03 +01:00
PandaMimo
80c4bd5065 ref: comment run_config_update (#1448)
Co-authored-by: Milo <milo@example.com>
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-11-10 13:44:17 +01:00
Bodebojo
222d800a32 fix(vcpkg): fix permission denied when updating vcpkg if it's installed as root (#1447) 2025-11-10 12:22:44 +01:00
Gideon
b29699fc55 docs: Expand LLM guidelines in CONTRIBUTING.md (#1445) 2025-11-09 09:13:27 +01:00
Oliver Tzeng
fc0e5461eb fix(zh_TW): fixed zh_TW strings (#1446) 2025-11-09 08:58:45 +01:00
Gideon
75da4a709c docs: Add AI guidelines to CONTRIBUTING.md (#1444) 2025-11-08 19:42:04 +01:00
Gideon
02e388122b ref: add comments to Config::allowed_steps (#1291) 2025-11-08 11:12:25 +01:00
Gideon
02fe1087de feat(falconf): add falconf step (#1219)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-08 11:10:45 +01:00
Gideon
34b7943fd1 fix(git): fix shellexpand::tilde in git_repos in topgrade.d/* (#1223) 2025-11-08 11:10:24 +01:00
Gideon
b61886f0f9 ref(nix): Deduplicate run_nix and run_nix_self_upgrade nix --version checking (#1376) 2025-11-08 11:07:01 +01:00
Gideon
d9a8ecfd33 ref: remove commented-out library code and unnecessary bin declaration (#1373) 2025-11-08 11:05:13 +01:00
Gideon
6c68bfaf64 ref: Simplify target cfgs (#1346) 2025-11-08 11:04:52 +01:00
Gideon
5866a0570f feat(hyprpm): add hyprpm step (#1213) 2025-11-08 11:04:19 +01:00
Gideon
28f5754efd feat(doom): add doom.aot option (#1214) 2025-11-08 11:03:08 +01:00
Gideon
ea1b286c98 fix(auto-cpufreq): skip when install script is not used (#1215) 2025-11-08 11:00:03 +01:00
Gideon
22ab77de6d feat: add show_distribution_summary config option (#1259) 2025-11-08 10:58:36 +01:00
Gideon
410bd61c75 ref: tidy up binary-conflict code (#1329) 2025-11-08 10:57:31 +01:00
Gideon
07b422915c docs: Improve installation section (#1442) 2025-11-07 12:12:52 +01:00
SteveCoding125
5b9d387ef3 fix(vim): change nvimrc base_dir for windows (#1433) 2025-11-06 11:07:19 +01:00
Gideon
5b5dd27834 fix(guix): fix overcomplicated Guix step (#1290) 2025-11-06 11:05:38 +01:00
Gideon
79f65981a5 fix(gem): fix incorrectly placed debug message in gem step (#1212) 2025-11-06 11:04:20 +01:00
Gideon
a52c775247 feat(rustup): add rustup.channels config (#1206) 2025-11-06 11:04:00 +01:00
Gideon
549111db3a fix(conda): replace deprecated auto_activate_base (#1158) 2025-11-06 11:03:13 +01:00
Gideon
1572974ec4 fix(containers): fix panic in containers step (#1150) 2025-11-06 10:25:52 +01:00
Gideon
8387468607 fix(jetbrains-toolbox): fix step not dry running (#1253) 2025-11-06 10:22:28 +01:00
Gideon
94979d6b7a chore(deps): Update jetbrains-toolbox-updater (#1438) 2025-11-05 17:32:11 +01:00
Daniel Hast
6652a2aa90 ci: remove template expansion in code contexts (#1434) 2025-11-04 20:54:03 +01:00
Mag Mell
f943b220d9 feat(os): add AOSC OS support (#1424) 2025-11-04 09:10:15 +01:00
dependabot[bot]
0fc7016d68 chore(deps): bump github/codeql-action from 4.31.0 to 4.31.2 (#1427)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 16:41:28 +01:00
Daniel Hast
9e9e6c9d55 ci: don't persist credentials in actions/checkout (#1422) 2025-11-03 12:29:07 +01:00
Gideon
bafa15c8f1 docs: Improve CONTRIBUTING.md (#1420) 2025-11-02 16:40:11 +01:00
Gideon
f669de8272 docs: Update SECURITY.md (#1421) 2025-11-02 15:59:45 +01:00
Gideon
ff26835406 chore(pre-commit): Run pre-commit (#1419) 2025-11-02 15:14:18 +01:00
Stuart Reilly
99892359c7 feat: add damp run type (#1217)
Co-authored-by: Stuart Reilly <sreilly@scottlogic.com>
2025-11-02 15:06:35 +01:00
Gideon
8fc25d7fd4 ci: Enforce conventional commits in PR titles (#1418) 2025-11-02 15:01:22 +01:00
GideonBear
942bfaa708 docs: Improve contributing section 2025-11-02 12:48:28 +01:00
GideonBear
a1fd324e82 docs: Remove roadmap 2025-11-02 12:48:28 +01:00
GideonBear
62bf2c6e90 docs: Reformat README.md 2025-11-02 12:48:28 +01:00
GideonBear
9f1e0c8eef docs: Update installation methods 2025-11-02 12:48:28 +01:00
Gideon
027de7c865 chore(release): Fix dispatch error in create_release_assets.yml (#1406) 2025-11-01 19:38:10 +01:00
github-actions[bot]
266adabd13 chore: release v16.1.2 (#1400)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-01 19:18:37 +01:00
Gideon
7d2e43f83b fix(release): Fix cross-compilation for arm requiring glibc>=2.39 (#1405) 2025-11-01 19:15:54 +01:00
Gideon
294a90a7c3 fix(release): Fix FreeBSD build (#1404) 2025-11-01 16:43:22 +01:00
Gideon
af5def1551 chore(release): Fix cross trying to fmt (#1403) 2025-11-01 16:30:56 +01:00
Gideon
8c63ee6a18 fix(release): Fix FreeBSD build (#1402) 2025-11-01 16:22:00 +01:00
Gideon
ee8ae8623d fix(release): Fix manual workflow trigger (#1401) 2025-11-01 16:19:31 +01:00
Gideon
222e6b55c0 fix(release): Fix FreeBSD build and add manual workflow trigger (#1399) 2025-11-01 16:03:15 +01:00
github-actions[bot]
2050a80665 chore: release v16.1.1 (#1392)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-01 15:12:40 +01:00
Gideon
e01be14041 fix(typst): Skip typst when self-update is disabled (#1397) 2025-11-01 14:53:26 +01:00
Gideon
dd6bc580fa fix(release): Fix winget release workflow (#1395) 2025-11-01 12:18:38 +01:00
Gideon
22ef36a185 chore: Update from deprecated macos-13 to macos-15-intel (#1394) 2025-11-01 12:04:53 +01:00
Gideon
b57ceccbe1 fix(release): Fix FreeBSD release (#1393) 2025-11-01 11:25:02 +01:00
Gideon
e9d430a4e4 fix(release): Fix FreeBSD release (#1391) 2025-11-01 11:22:24 +01:00
github-actions[bot]
8a247fba95 chore: release v16.1.0 (#1389)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-01 10:11:43 +01:00
Gideon
5b6c31bd89 chore(release): switch to release-plz (#1333) 2025-10-31 19:31:37 +01:00
Gideon
c316e2af69 chore(pre-commit): Make pre-commit.ci use conventional commits (#1388) 2025-10-31 17:00:39 +01:00
Gideon
7270aa96f0 feat(deb-get): Skip non-deb-get packages by passing --dg-only (#1386) 2025-10-29 18:43:03 +01:00
pre-commit-ci[bot]
dd823eb489 chore(pre-commit): pre-commit autoupdate (#1383)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: GideonBear <87426140+GideonBear@users.noreply.github.com>
2025-10-28 09:39:19 +01:00
dependabot[bot]
cb29305385 chore(deps): bump actions/upload-artifact from 4.6.2 to 5.0.0 (#1382)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 5.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4.6.2...v5.0.0)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 17:41:59 +01:00
dependabot[bot]
2dfa37dd0c chore(deps): bump github/codeql-action from 4.30.9 to 4.31.0 (#1379)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 17:16:36 +01:00
dependabot[bot]
b3d3284f18 chore(deps): bump actions/download-artifact from 5.0.0 to 6.0.0 (#1380)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 17:16:29 +01:00
dependabot[bot]
73e3e133c6 chore(deps): bump taiki-e/install-action from 2.62.33 to 2.62.38 (#1381)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 17:16:20 +01:00
Gideon
9828af9f03 chore(pre-commit): Fix pre-commit-config.yaml (#1378) 2025-10-27 16:54:55 +01:00
Gideon
48aa6b5ac5 fix(freshclam): run with sudo when running without sudo fails (#1118) 2025-10-27 16:44:53 +01:00
Stef
e5b3ed1461 feat(typst): add typst step (#1374) 2025-10-26 12:57:59 +01:00
Mitchell Berendhuysen
5fad9f0ec6 chore(release): Add .deb auto completion script (#1353)
Co-authored-by: GideonBear <87426140+GideonBear@users.noreply.github.com>
2025-10-25 18:02:04 +02:00
SteveCoding125
f4a5507716 fix(tldr): move tldr to be a generic step (#1370) 2025-10-21 18:51:34 +02:00
dependabot[bot]
2ea9d1d6fd chore(deps): bump github/codeql-action from 4.30.8 to 4.30.9 (#1369)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 17:45:25 +02:00
dependabot[bot]
e393b1f90b chore(deps): bump taiki-e/install-action from 2.62.28 to 2.62.33 (#1368)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 17:43:48 +02:00
Stef
2259e81bb0 feat(step): Add atuin step (#1367) 2025-10-19 14:09:40 +02:00
Jochen Schalanda
65a30292a3 feat(nix): support upgrading Determinate Nix (#1366)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-10-15 09:39:09 +02:00
dependabot[bot]
494eef3472 chore(deps): bump actions/dependency-review-action from 4.8.0 to 4.8.1 (#1362)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-13 18:44:00 +02:00
dependabot[bot]
bee1e865b2 chore(deps): bump softprops/action-gh-release from 2.3.4 to 2.4.1 (#1364)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-13 18:43:53 +02:00
dependabot[bot]
c92b049bbc chore(deps): bump taiki-e/install-action from 2.62.21 to 2.62.28 (#1363)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-13 18:43:48 +02:00
dependabot[bot]
c9985480fe chore(deps): bump github/codeql-action from 3.30.6 to 4.30.8 (#1365)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-13 18:43:45 +02:00
Chinmay Dalal
e1b5b76d8e fix(nix): fix nix upgrade command selection for profiles in XDG_STATE_HOME (#1354) 2025-10-08 18:45:57 +02:00
Peter Storch
762a74f5f9 fix(containers): Docker update fails on M Macs due to platform / (#1360)
Suppresses the `--platform` parameter to docker pull if platform is only '/'.

fixes #1154
2025-10-06 20:10:09 +02:00
dependabot[bot]
a7a2d8493e chore(deps): bump github/codeql-action from 3.30.5 to 3.30.6 (#1355)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 17:29:12 +02:00
dependabot[bot]
bc6538d209 chore(deps): bump softprops/action-gh-release from 2.3.3 to 2.3.4 (#1356)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 17:28:53 +02:00
dependabot[bot]
93d841310e chore(deps): bump taiki-e/install-action from 2.62.13 to 2.62.21 (#1357)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 17:28:49 +02:00
dependabot[bot]
2ac679f17e chore(deps): bump ossf/scorecard-action from 2.4.2 to 2.4.3 (#1358)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 17:28:39 +02:00
dependabot[bot]
9a3ef463f9 chore(deps): bump actions/dependency-review-action from 4.7.3 to 4.8.0 (#1350)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-30 09:15:18 +02:00
dependabot[bot]
affc5fcd75 chore(deps): bump github/codeql-action from 3.30.3 to 3.30.5 (#1349)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-30 09:15:06 +02:00
dependabot[bot]
96bff5e974 chore(deps): bump taiki-e/install-action from 2.62.1 to 2.62.13 (#1351)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-30 09:14:57 +02:00
dependabot[bot]
e828e14fa5 chore(deps): bump actions/cache from 4.2.4 to 4.3.0 (#1352)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-30 09:14:43 +02:00
Nils
4c6dc8ff82 Fix WSL distribution name cleanup (#1348) 2025-09-28 19:35:18 +02:00
Nils
75bd7c90d3 chore(pyproject): mark version as dynamic (#1347) 2025-09-28 19:27:30 +02:00
Andre Toerien
2aa3d94a98 feat(sudo): print warning if Windows Sudo is misconfigured 2025-09-28 19:14:45 +02:00
Andre Toerien
f4ac809dff refactor(deps): replace winapi with windows 2025-09-28 19:14:45 +02:00
Andre Toerien
0dee534f84 fix(sudo): reorder require_sudo() after print_separator() 2025-09-28 15:38:30 +02:00
Andre Toerien
ad9f2c2ccb feat(sudo): print warning if steps were skipped due to missing sudo 2025-09-28 15:38:30 +02:00
AThePeanut4
a886d20a7b refactor(sudo): rename interactive to login_shell 2025-09-28 14:57:40 +02:00
Andre Toerien
791993795a fix(sudo): use require_sudo for windows commands 2025-09-28 14:57:40 +02:00
Andre Toerien
a2afdb821f feat(sudo): add SudoKind::Null 2025-09-28 14:57:40 +02:00
Andre Toerien
47b51a8be0 feat: detect and warn if running as root 2025-09-28 14:57:40 +02:00
Andre Toerien
7c7e7c3ce4 Fix "WSL already reported" panic (#1344) 2025-09-28 08:25:10 +02:00
Andre Toerien
fec08a5ad1 Move step logic out of Powershell struct (#1345) 2025-09-27 19:55:56 +02:00
dependabot[bot]
3961ef61c8 chore(deps): bump taiki-e/install-action from 2.61.5 to 2.62.1 (#1335)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-22 17:27:49 +02:00
dependabot[bot]
84692da9a2 chore(deps): bump Swatinem/rust-cache from 2.8.0 to 2.8.1 (#1336)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-22 17:27:44 +02:00
Andre Toerien
fb7ba52e39 Fixes for #1188; custom_commands broken (#1332)
Co-authored-by: GideonBear <87426140+GideonBear@users.noreply.github.com>
2025-09-20 13:59:19 +02:00
SteveCoding125
898823abb2 use login shell when executing topgrade (#1327) 2025-09-18 17:06:59 +02:00
Rafael Scalet
ccefd0a43a feat: add --no-tmux flag (#1328) 2025-09-18 14:01:19 +02:00
dependabot[bot]
98f0be61ed chore(deps): bump taiki-e/install-action from 2.60.0 to 2.61.5 (#1325)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-15 18:39:56 +02:00
dependabot[bot]
6bb1d54cb0 chore(deps): bump github/codeql-action from 3.30.1 to 3.30.3 (#1324)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-15 18:39:49 +02:00
Nils
69a76e32b7 chore(pre-commit): add typos with conservative excludes; no content changes (#1317)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
Co-authored-by: niStee <52573120+niStee@users.noreply.github.comclear>
2025-09-14 08:20:51 +02:00
Rafael Scalet
99d989d486 feat: add step for mandb - user and system (update man entries) (#1319) 2025-09-14 08:08:52 +02:00
Nils
456d62224e chore: fix simple typos in code and comments (split var, whether, Extensions) (#1318)
Co-authored-by: niStee <52573120+niStee@users.noreply.github.comclear>
2025-09-13 17:12:39 +02:00
Rafael Scalet
b662fae11e feat: support for pkgfile (#1306) 2025-09-10 13:31:27 +02:00
dependabot[bot]
0926bd2f6c chore(deps): bump github/codeql-action from 3.29.11 to 3.30.1 (#1301)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 17:30:51 +02:00
dependabot[bot]
3fb473ae95 chore(deps): bump softprops/action-gh-release from 2.3.2 to 2.3.3 (#1302)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 17:30:45 +02:00
dependabot[bot]
603ed18a4c chore(deps): bump taiki-e/install-action from 2.58.21 to 2.60.0 (#1303)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 17:30:40 +02:00
dependabot[bot]
0307fdd296 chore(deps): bump actions/dependency-review-action from 4.7.2 to 4.7.3 (#1304)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 17:30:34 +02:00
dependabot[bot]
c10dcdbfdb chore(deps): bump actions/attest-build-provenance from 2.4.0 to 3.0.0 (#1305)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 17:30:30 +02:00
Nils
31d8e579c6 Security: update tracing-subscriber to ~0.3.20 (ANSI escape injection fix, GHSA-xwfj-jgwm-7wp5) (#1288)
* Security: pin tracing-subscriber to 0.3.20 (fix ANSI escape injection, GHSA-xwfj-jgwm-7wp5)\n\n- Ensure tracing-subscriber is 0.3.20\n- Document reason near tracing init\n- Windows: enable winapi features (consoleapi, wincon) to fix build\n- Verified build passes locally\n\nRefs:\n- GHSA-xwfj-jgwm-7wp5

* Update src/utils.rs

Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>

* Update Cargo.toml

Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>

---------

Co-authored-by: niStee <52573120+niStee@users.noreply.github.comclear>
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-08-31 20:51:08 +02:00
Rafael Scalet
7b3fec0349 feat: add "show_skipped" option in config file #1280 (#1286) 2025-08-29 11:01:40 +02:00
dependabot[bot]
e32a58f6ff chore(deps): bump github/codeql-action from 3.29.8 to 3.29.11 (#1281)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 17:38:57 +02:00
dependabot[bot]
36cd726676 chore(deps): bump actions/dependency-review-action from 4.7.1 to 4.7.2 (#1282)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 17:38:36 +02:00
dependabot[bot]
8dc08de628 chore(deps): bump taiki-e/install-action from 2.58.9 to 2.58.21 (#1283)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 17:38:04 +02:00
dependabot[bot]
0361954919 chore(deps): bump PyO3/maturin-action from 1.49.3 to 1.49.4 (#1285)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 17:37:39 +02:00
dependabot[bot]
29a62575f4 chore(deps): bump actions/cache from 4.2.3 to 4.2.4 (#1284)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 17:37:10 +02:00
uwuclxdy
547a6df2ae Support "Insiders" versions of VSCode and VSCodium (#1279) 2025-08-25 16:27:02 +02:00
Stuart Reilly
53d08cdf28 Sudo preserve env list argument is --preserve-env (#1276)
Sudo preserve-env

Sudo's preserve env list is `--preserve-env=...` not `--preserve_env=...`.

https://www.man7.org/linux/man-pages/man8/sudo.8.html
2025-08-20 17:33:35 +02:00
Ehren Bendler
a033152c60 Clippy fixes from rust 1.91 nightly (#1267) 2025-08-13 17:01:25 +02:00
dependabot[bot]
9472aaca7a chore(deps): bump actions/checkout from 4.2.2 to 5.0.0 (#1264)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 11:47:45 +02:00
dependabot[bot]
6254b99e02 chore(deps): bump actions/download-artifact from 4.3.0 to 5.0.0 (#1263)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 11:46:33 +02:00
dependabot[bot]
3d17bdb747 chore(deps): bump taiki-e/install-action from 2.58.0 to 2.58.9 (#1261)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 11:45:14 +02:00
dependabot[bot]
d2eeeb9129 chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.2 (#1262)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 11:44:50 +02:00
dependabot[bot]
1d626e0add chore(deps): bump github/codeql-action from 3.29.5 to 3.29.8 (#1265)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 11:44:27 +02:00
Kian-Meng Ang
9f4cb8c1b6 feat: fix typos (#1221)
Co-authored-by: GideonBear <87426140+GideonBear@users.noreply.github.com>
2025-08-11 18:15:21 +02:00
Nils
91fc5e3902 chore(ci): Dependabot, workflow security (#1257)
Co-authored-by: StepSecurity Bot <bot@stepsecurity.io>
Co-authored-by: niStee <52573120+niStee@users.noreply.github.comclear>
Co-authored-by: GideonBear <87426140+GideonBear@users.noreply.github.com>
2025-08-11 10:24:18 +02:00
Falk Woldmann Lu
9048cd8f47 refactor: replace once_cell crate with std equivalent (#1260) 2025-08-11 09:57:32 +02:00
Nils
4f5e8a8836 chore(deps): bump tokio from 1.38 to 1.47 (#1256)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-09 13:55:28 +02:00
Gudsfile
29b05fa50f i18n(app.yml): fix fr language #1248 2025-08-06 20:11:56 +02:00
Andre Toerien
dbe1a5c988 refactor(sudo): add SudoKind::WinSudo 2025-08-06 15:21:51 +02:00
Andre Toerien
b6c1290934 refactor(sudo): add SudoExecuteOpts builder functions and preserve_env enum 2025-08-06 15:21:51 +02:00
Andre Toerien
306ff3c7c5 fix(sudo): prevent sudo_command = "sudo" finding gsudo 2025-08-06 15:21:51 +02:00
Andre Toerien
0e43e0d7fc refactor(yarn): remove unnecessary Yarn::yarn field 2025-08-06 15:21:51 +02:00
Andre Toerien
4da696321a refactor(apt): extract detect_apt() function 2025-08-06 15:21:51 +02:00
Andre Toerien
a95dd1e037 refactor: route sudo usage through Sudo::execute* 2025-08-06 15:21:51 +02:00
Andre Toerien
012a6bbde3 fix(sudo): set sudo flags depending on kind 2025-08-06 15:21:51 +02:00
Andre Toerien
32197f79f3 refactor: move RunType::execute to ExecutionContext 2025-08-06 15:21:51 +02:00
Alwin
257d202646 fix: skip gcloud update step if component manager is disabled (#1237) 2025-07-21 15:21:29 +02:00
Andre Toerien
c00365c19d fix(i18n): use double-quotes for translations with newlines 2025-07-18 09:21:31 +02:00
Andre Toerien
3f9fe845e5 refactor(powershell): store powershell path directly 2025-07-18 09:21:31 +02:00
Andre Toerien
b166aae835 fix(powershell): run microsoft_store command directly 2025-07-18 09:21:31 +02:00
Andre Toerien
31f0097862 fix(powershell): remove mentions of USOClient 2025-07-18 09:21:31 +02:00
Andre Toerien
f78514dbd8 fix(powershell): execution policy check breaks when run in pwsh
When topgrade is run from within pwsh, the execution policy check breaks
for the Windows Update and Windows Store steps, because they use normal
powershell and the inherited PSModulePath environment variable breaks
the Microsoft.PowerShell.Security module import. So we unset that
variable to fix the issue, but also allow for those steps to use pwsh as
neither step actually requires PowerShell 5.

Co-authored-by: nistee <52573120+niStee@users.noreply.github.com>
2025-07-18 09:21:31 +02:00
Andre Toerien
9fc5fe9798 fix(powershell): don't use sudo with Update-Module for pwsh
Co-authored-by: Ao <197966644+ao-xing@users.noreply.github.com>
Co-authored-by: nistee <52573120+niStee@users.noreply.github.com>
2025-07-18 09:21:31 +02:00
Andre Toerien
6d14ac1693 refactor(powershell): cleanup and simplify code 2025-07-18 09:21:31 +02:00
Steve Brown
b8ab573c00 fix(powershell): add -Command to module update cmdline 2025-07-18 09:21:31 +02:00
Stuart Reilly
75ac6808a1 Move step running into enum for dynamic ordering (#1188)
Co-authored-by: Stuart Reilly <sreilly@scottlogic.com>
2025-07-16 11:16:27 +02:00
Max Kapur
6719ff93d8 feat(conda): allow configuring additional envs to update (#1048) 2025-07-15 13:15:42 +02:00
Tom van Dijk
6b8327faad feat(step): nix-helper (#1045) 2025-07-15 11:05:46 +02:00
Andreas Hoornstra
85c8bd2277 feat(winget): winget uses sudo when [windows] winget_use_sudo = true (#1061)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-07-15 09:12:55 +02:00
Axel H.
23fff2a09f fix(tmux): support all default tpm locations (xdg and both hardcoded locations) (#1146) 2025-07-14 10:08:00 +02:00
Ville Skyttä
689db93c99 Generate artifact attestations for release assets (#1216) 2025-07-14 10:05:03 +02:00
Sam Hug
1114556661 windows update, use explicit reboot policy (#1143) 2025-07-14 09:57:00 +02:00
Cthulhux
f8c910a3c2 fixed the German translation for "y/n/s/q" (#1220) 2025-07-14 09:56:26 +02:00
Sam Vente
f18ae089ff feat: suppress pixi release notes by default (#1225)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-07-14 09:51:02 +02:00
SteveLauC
4a64992054 docs: add Discord invite link to README (#1203) 2025-06-26 08:53:25 +08:00
Gideon
9fefb47242 Catch secondary uv self-update error (#1201) 2025-06-25 19:24:07 +08:00
Matt Thomson
fc5cc3c43b Handle another format change in asdf version (#1194)
This now includes a revision part which must be trimmed, e.g.

0.18.0 (revision unknown)
2025-06-19 17:29:11 +08:00
Gideon
27464b795e Preserve custom commmand order from config instead of sorting alphabetically (#1182) 2025-06-17 11:58:23 +08:00
Stuart Reilly
845558c1da Add support for multiple binary names and idea having multiple binaries (#1167)
Add support for tools to have multiple possible binaries because IntellIj IDEA on the AUR can have multiple depending on the edition.

[AUR Ultimate Edition](https://aur.archlinux.org/packages/intellij-idea-ultimate-edition) and [AUR Community Edition](https://aur.archlinux.org/packages/intellij-idea-community-edition-bin) renames the binary to `intellij-idea-ultimate-edition` and `intellij-idea-community-edition` respectively.
2025-06-17 11:52:58 +08:00
SteveLauC
31fe5aa452 ci: fix the invalid action version (#1185) 2025-06-17 11:36:17 +08:00
SteveLauC
b354e07ef3 ci: allow us to re-run AUR CI (#1184)
* ci: allow us to re-run AUR CI

* ci: no need to set shell as it is Linux
2025-06-17 11:32:16 +08:00
slowsage
50a74dac4b Update Yazi upgrade step to use ya pkg. (#1163) 2025-06-17 11:09:14 +08:00
SteveLauC
7558bbfe9b ci: use the new tag name and specify shell to bash (#1183) 2025-06-17 10:44:49 +08:00
SteveLauC
7518676ac9 ci: allow specifying tag when manually run 'create_release_assets.yml' (#1180)
Adds a parameter existing_tag to the workflow_dispatch event of "create_release_assets.yml", which would allow us to re-run a failed release.
2025-06-16 14:39:23 +08:00
SteveLauC
b7b665ff48 ci: fix homebrew ci, remove duplicate trigger event (#1179) 2025-06-16 11:45:48 +08:00
SteveLauC
1be941e815 ci: fix PyPI pipeline duplicate wheel name (#1178) 2025-06-16 11:43:11 +08:00
SteveLauC
d1b7eba44e ci: add event workflow_dispatch to release pipelines (#1177) 2025-06-16 11:36:14 +08:00
SteveLauC
38e2d5663a ci: fix pipeline relase to PyPI (#1176) 2025-06-16 10:52:35 +08:00
Gideon
3db95a3e67 Install rustfmt and clippy where necessary (#1171) 2025-06-16 10:04:06 +08:00
SteveLauC
ef0a0d69bb chore: release v16.0.4 (#1169) 2025-06-13 19:03:17 +08:00
Gideon
4b3a3e74f8 Fix "Only one instance of <IDE> can be run at a a time." error (#1123) 2025-06-13 18:54:07 +08:00
Gideon
2c4751c7b2 Add CachyOS support (#1153)
* Add CachyOS support

* Fix os-release file

* Re-run CI
2025-06-12 14:36:35 +08:00
Stuart Reilly
30941ed26d Drop lazy_static (#1168)
Co-authored-by: Stuart Reilly <sreilly@scottlogic.com>
2025-06-12 14:32:29 +08:00
Gideon
c7163b63db Run uv cache prune in uv step when cleanup is enabled (#1165)
Add uv cache prune
2025-06-10 18:10:18 +08:00
SteveLauC
6e6b3dcbfe ci: add missing rustup components (#1166) 2025-06-10 15:43:21 +08:00
Gideon
1d136a6635 Fix nix version output changed (#1140)
* Fix nix version output changed

* Format
2025-04-24 09:31:02 +08:00
Gideon
0ee67d78ef Fix conflict between hx (hexdump alternative) and Helix (#1135)
* Fix conflict between hx (hexdump alternative) and Helix

* Remove uneccessary unit parameter

* Use helix-centered detection
2025-04-21 18:46:00 +08:00
Gideon
7356b920d4 Update jetbrains-toolbox-updater (#1128)
* Update jetbrains-toolbox-updater

* Update to 5.0.0
2025-04-21 11:59:25 +08:00
Gideon
ce8a325c1f Add Yazi step (#1134) 2025-04-21 11:45:01 +08:00
Alexandre Franke
a2f57e4769 fix: correct GNOME spelling (#1124)
Before this change, the spelling was inconsistent. Now it is consistent and follows the upstream spelling. GNOME is spelled all caps, because it is a trademark. (As an exception, it is spelled all lowercase in technical strings, such as identifiers and commands)
2025-04-16 13:46:26 +08:00
Matt Thomson
751f41bc5e Handle format change in asdf version (#1127)
As of the latest version, this now has the format 0.16.7 - i.e. without the hash part.  This commit makes it so that both formats work.

Fixes #1096
2025-04-16 13:35:30 +08:00
Gideon
fd406f0f82 Add output_changed_message!, replace some .expects (#1110) 2025-04-13 16:43:08 +08:00
Gideon
801dddacd4 Omit deb-get clean output (#1119) 2025-04-13 16:36:22 +08:00
Gideon
397a537eef Fix uv step (#1121) 2025-04-13 16:07:57 +08:00
Gideon
0423c836eb Fix vscodium skipping silently (#1109)
* Fix vscodium skipping silently

* Deduplicate

* Format

* Fix x.x.0 version crashing

* Error instead of skipping when there is no first version line

* Format
2025-04-13 11:50:27 +08:00
Gideon
3250337e70 Add JetBrains IDE plugin update steps (#1103)
* Add JetBrains IDE plugin update steps

* Improve comment consistency

* Add comments for missing Windows-only IDEs

* Fix typo

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* Fix missing "plugins" in Android Studio step name

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* Add breaking change to BREAKINGCHANGES_dev.md

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2025-04-11 10:56:24 +08:00
Nils
9dcd7fffe2 Enhancement: Update Windows Package Manager Indexes (#1085)
* fix(windows): update winget sources and upgrade all packages

* refactor(windows): streamline winget upgrade command execution
2025-04-10 19:50:35 +08:00
Nils
30b727b138 fix(powershell): update command arguments to include execution policy (#1041)
* fix(powershell): update command arguments to include execution policy

* fix(powershell): format command arguments for better readability

* fix(powershell): refactor command arguments for Windows execution policy and common options

* fix(powershell): improve execution policy handling and refactor argument passing

* refactor(powershell): streamline command execution and improve profile handling

* fix(powershell): improve code formatting for better readability and maintainability

* fix(powershell): enhance argument validation for improved error handling

* refactor(powershell): simplify Powershell struct methods and enhance command preparation

* refactor(powershell): streamline command building and enhance argument handling

* refactor(powershell): change add_common_args to use instance method for better encapsulation

* refactor(powershell): enhance command building by introducing build_command method and improving argument handling

* refactor(powershell): update build_command return type to match executor.execute() output

* refactor(powershell): refactor command building by introducing build_command_internal and adding profile getter

* refactor(powershell): improve profile retrieval and command execution logic

* refactor(powershell): add support for Windows update and Microsoft Store commands

* refactor(powershell): change args method to arg for accepting all Windows updates

* refactor(powershell): change arg method to args for accepting all Windows updates

* refactor(powershell): change args method to arg for accepting all Windows updates

* refactor(powershell): streamline command construction for Windows updates

* refactor(powershell): update args method for has_module function

* refactor(powershell): improve execution policy handling and command construction for Windows updates

* refactor(powershell): update Microsoft Store update command execution and streamline output handling

* refactor(powershell): clean up whitespace and improve code readability in execution policy checks

---------

Co-authored-by: nistee <lo9s4b7qp@mozmail.com>
2025-04-10 19:48:53 +08:00
SteveLauC
b86d6981ab fix: uv self update (#1105)
Fix #942, the impl is based on this comment https://github.com/topgrade-rs/topgrade/issues/942#issuecomment-2785749010
2025-04-10 17:35:55 +08:00
Gideon
2bf6a2b100 Update CONTRIBUTING.md to reflect enum Step sort enforcement (#1111)
* Update CONTRIBUTING.md

* Formatting
2025-04-09 10:03:32 +08:00
Gideon
3dc8d31d57 Sort Step enum and keep it sorted in the ci.yml workflow (#1104)
* Add `step-enum-sorted` to `ci.yml` workflow

* Sort `Step` enum

* Sort `Step` enum
2025-04-08 19:13:35 +08:00
SteveLauC
b308fb92c0 ci: merge create_assets_xxx workflows and let AUR binary release workflow wait for it (#1100) 2025-04-08 14:34:48 +08:00
dependabot[bot]
bc9746455e chore(deps): bump tokio from 1.38.0 to 1.38.2 (#1101)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.38.0 to 1.38.2.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.38.0...tokio-1.38.2)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.38.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-08 10:25:58 +08:00
Gideon
109a9c76e3 Downgrade create_release_assets.yml workflow (#1098)
Downgrade `create_release_assets.yml` workflow Ubuntu version to `22.04` from `24.04`
2025-04-07 08:39:56 +08:00
SteveLauC
4488f3d5d3 chore: bump version to 16.0.3 (#1094) 2025-04-03 17:56:01 +08:00
Gideon
5a7958d20e Fix aqua CLI and JetBrains Aqua conflict (#1092) 2025-04-03 17:40:52 +08:00
Gideon
481a942b76 Fix pixi self-update running when pixi is not installed with the … (#1087)
* Fix `pixi self-update` running when `pixi` is not installed with the `self-update` feature

* Format
2025-04-03 17:38:38 +08:00
Red Wizard
a601d8429d added silent install option for winget (#1089)
* added silent install option for winget

* corrected formatting issues.

* Update src/steps/os/windows.rs

Remove code duplication.

Co-authored-by: SteveLauC <stevelauc@outlook.com>

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2025-03-30 21:11:04 +08:00
tdslot
a4a2d52a6d i18n(app.yml): new language lt (#1069)
* i18n(app.yml): new language lt

Lithuanian language.

* 🌐 i18n(app.yml): update translations for WSL error message

- resolve merge conflict in translation strings
- update spanish and french translations for clarity
- add lithuanian translation for WSL error message
- standardize zh_TW translation format

* 🌐 i18n(locales): add missing translations

- add zh_CN translation for "Topgrade not found in any WSL distribution"
- add lt translations for JetBrains Toolbox related messages
- add lt translations for operating system and updater error messages

* 🌐 i18n(locales): update spanish translation for WSL error message

- improve accuracy of spanish translation for "Could not find Topgrade in any WSL distribution"
- change from "Topgrade no se ha instalado dentro de WSL" to "No se pudo encontrar Topgrade en ninguna distribución WSL"
2025-03-30 14:50:37 +08:00
Nils
47fa3ba7de Add German translations to localization file (#1065)
* Add German translations to localization file

* refactor(localization): remove unused/duplicate translations from app.yml

* i18n(app.yml): add German translations for JetBrains Toolbox messages

* chore: Convert locales/app.yml from CRLF to LF line endings

* Update locales/app.yml

* fix: correct German translation for "Breaking changes"

---------

Co-authored-by: nistee <lo9s4b7qp@mozmail.com>
Co-authored-by: SteveLauC <stevelauc@outlook.com>
2025-03-26 08:59:37 +08:00
Gideon
e6bb6709b3 Update jetbrains-toolbox-updater (#1077) 2025-03-25 10:40:04 +08:00
Alexandre Veyrenc
c421742c4f fix:(emacs): fix issue #1075 (#1076) 2025-03-21 17:01:58 +08:00
ZeroDegress
1312cc8f6e i18n(app.yml): new language zh_CN (#1072) 2025-03-19 09:24:10 +08:00
Gideon
ed37763d30 Add JetBrains Toolbox via jetbrains-toolbox-updater (#1064)
* Add jetbrains-toolbox-updater

* Update jetbrains-toolbox-updater

* Update jetbrains-toolbox-updater

* Update jetbrains-toolbox-updater

* Localize prints

* Update jetbrains-toolbox-updater

* Format

* Add localization

* Fix translation
2025-03-18 11:19:37 +08:00
Justin
583bbf65e2 docs: fix --log-filter link in --help (#1073)
docs: fix EnvFilter link
2025-03-17 14:07:40 +08:00
Izzy Meyer
5770a5caa7 FIX: Allow for -beta OR -current detection and use the correct system upgrade command for the OpenBSD step (#1066)
* FIX: Allow for -beta OR -current detection and use the correct system upgrade command for the OpenBSD step

* FIX: Run fmt, clippy, and test
2025-03-13 09:02:45 +08:00
Gijs Key
722903fec3 Create Armv7l debian package (#1068)
* Create Armv7l debian package

* returned inadvertently removed comment.

---------

Co-authored-by: Gijs Keij <gijs.keij@bit-key.nl>
2025-03-12 11:20:19 +08:00
Xarblu
30f1c3c1b4 feat(sudo): add run0 as a sudo variant (#1067) 2025-03-12 09:07:37 +08:00
dependabot[bot]
ef7d146282 chore(deps): bump ring from 0.17.8 to 0.17.13 (#1062)
Bumps [ring](https://github.com/briansmith/ring) from 0.17.8 to 0.17.13.
- [Changelog](https://github.com/briansmith/ring/blob/main/RELEASES.md)
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-09 10:47:33 +08:00
Andreas02-dev
20667a23d3 fix(sudo): fix sudo detection & pre-sudo for GSudo (#1058) 2025-03-06 08:51:40 +08:00
JaRoSchm
26f05827ae feat(pixi): add support for pixi global (#1037)
feat(pixi): add support for pixi global
2025-03-05 08:58:21 +08:00
Max Kapur
b1ffe7d553 Run conda clean after conda update if cleanup = true (#1047)
* Run `conda clean` after `conda upgrade` if `cleanup = true`

* Also run `mamba clean`
2025-03-04 09:15:02 +08:00
yggdr
368a060529 Add pipxu step (#1052) 2025-03-04 09:11:57 +08:00
Gideon
b40bffb1f2 Add "Cinnamon spices" step (#1055)
* Add "Cinnamon spices" step

* Format

* Move step to Linux
2025-03-04 08:57:12 +08:00
Andre Toerien
488ae149f7 fix(poetry): parse arg in script shebang line (#1028)
* fix(poetry): parse arg in script shebang line

* fix(poetry): improved shebang line parsing on windows
2025-02-25 20:00:53 +08:00
Tom van Dijk
fa3e4726b7 fix: uBlue OS should be detected as FedoraImmutable (#1043)
* refactor(parse_os_release): Don't rely on specific `ID`s for Fedora Immutable

Instead match `ID=fedora` or `ID_LIKE=fedora` and decide wether or not
the distro is immutable by `VARIANT`.

* feat: add aurora,bluefin,coreos support

The `os_release`s came from the following images:

- ghcr.io/ublue-os/aurora:93f0fd9f20b3
- ghcr.io/ublue-os/bluefin:5d37394a5d4b
- ghcr.io/ublue-os/ucore:63cd1200c344

* fix: bazzite should be detected as FedoraImmutable

* squash me: cargo fmt

---------

Co-authored-by: Steve Lau <stevelauc@outlook.com>
2025-02-17 09:41:34 +08:00
Ivan Andre Scheel
66a12cc8bf feat(vscode): updated extensions for a given profile (#1022)
* [feat] select user profile for vscode

* [feat] Update example config file

* [fix] Remove unneeded imports

* [feat] PR comments

* [fix] formatting
2025-02-11 12:51:52 +08:00
Alex Böhm
3e0c21e981 docs: fix typo in description (#1032) 2025-02-08 20:03:32 +08:00
Laura Demkowicz-Duffy
da270ae7d9 Add zigup step (#1030)
* feat: add zigup step

* feat(zigup): add various configuration options

* feat(zigup): add cleanup option

* feat(zigup): multiple version support and cleanup

* refactor(zigup): remove set_default and simplify execution

* fix(zigup): always pass path args to zigup for consistent behaviour

* refactor(zigup): use shellexpand to expand tildes
2025-02-08 14:25:10 +08:00
Laura Demkowicz-Duffy
4624f11ba5 Run juliaup gc if cleanup is enabled (#1031)
refactor(juliaup): run juliaup gc if cleanup is enabled
2025-02-08 14:15:25 +08:00
Dan Sully
224bb96a98 chore: update toolchain to 1.84.1. apply clippy fixes & rustfmt (#1026)
* chore: update to stable toolchain. apply clippy fixes & rustfmt

* Bump MSRV

* Try MSRV without the patch version

* fix: pin toolchain to MSRV

* trying again

* fix dead code warning

---------

Co-authored-by: Dan Sully <dsully@users.noreply.github.com>
2025-02-03 11:24:57 +08:00
SteveLauC
9a6fe8eea9 feat: support VSCodium (#788) 2025-01-09 10:35:45 +08:00
SteveLauC
aebc035ec0 fix: do not run asdf update if version >= 0.15.0 (#1008) 2024-12-20 13:31:29 +08:00
LILAY
bd348c328e Add Fedora Copr to Readme.md (#1005)
Update README.md
2024-12-12 10:01:10 +08:00
Samuel Grahn
c5f2d7b473 Detect Elan self update disabled (e.g. installed from distro repos) (#998)
* Add config option for Elan self-update

* Format & Config

* Revert "Format & Config"

This reverts commit 9eedecce8b312f8ad60563488c98cccfd50c0173.

* Revert "Add config option for Elan self-update"

This reverts commit 8c80c7a7d63ecd0936e0bd5cb07c2cbb1452c1fd.

* Allow self-update to fail when disabled

* Formatting

* Don't print in case of failed self-update

* Formatting

* Use the code suggested :)

* Follow the recommendations by Clippy
2024-12-12 09:19:03 +08:00
SteveLauC
dc9d8d55f2 fix: Executor::spawn()/output() should not use their _checked() variants (#1002) 2024-12-11 09:12:57 +08:00
Steve Lau
b172ba7f03 fix: Executor::spawn()/output() should not use their _checked() variants 2024-12-11 08:59:19 +08:00
SteveLauC
8227890808 refactor(uv step): check self update result if self-update feat is available (#1000)
refactor: check self update result if self-update feat is available
2024-12-10 20:55:32 +08:00
befanyt
a0963fe3fc fix: dont ignore rpm-ostree when bootc is found (#999) 2024-12-10 13:00:37 +08:00
SteveLauC
4df30c2587 chore: release v16.0.2 (#995) 2024-12-07 15:21:19 +08:00
Andre Toerien
305a5fbcae fix(poetry): skip if not installed with official script (#989)
* fix(poetry): skip if not installed with official script

* feat(poetry): add poetry_force_self_update config option

* docs: give this config a more detailed explanation

---------

Co-authored-by: Steve Lau <stevelauc@outlook.com>
2024-12-07 15:09:52 +08:00
Tulip Blossom
4f4dcbb643 feat: add bootc support to Fedora atomic distros
* feat(bootc): add Bootc support + docs

Co-authored-by: Steve Lau <stevelauc@outlook.com>

* docs(bootc): specify that itll supercede rpm-ostree if enabled :p

---------

Co-authored-by: Steve Lau <stevelauc@outlook.com>
2024-11-19 11:07:12 +08:00
Laura Demkowicz-Duffy
202897ba35 refactor: disable julia startup file for julia package update (#983)
* refactor(julia): disable julia startup file for julia package update

* feat(julia): add configuration option for julia startup file

* fix: deny unknown fields on JuliaConfig deserialisation

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* doc(julia): clarify startup_file option purpose

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-11-19 09:17:51 +08:00
Youn Mélois
444689c899 feat: allow version specification for deno (#970)
* feat: allow version specification for deno

* fix: missing quotes for string in toml file

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* fix: deno upgrade for different executable versions

* fix: tell apart the two cases for v1.x in SkipStep reason

* docs: add comments and documentation on version method for deno

* chore: add explanatory comment on stable channel that does nothing

Co-authored-by: SteveLauC <stevelauc@outlook.com>

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-10-29 18:09:47 +08:00
Gudsfile
98ec13f8db i18n(app.yml): new language fr (#969)
Apply suggestions from code review

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-10-29 16:34:44 +08:00
Lucas Parzianello
39f76a3a71 uv step: checking self subcommand exits; fixes #942 (#971)
* uv step: checking self subcommand exits; fixes #942

* uv: fixing return behavior

---------

Co-authored-by: Lucas Parzianello <lucaspar@users.noreply.github.com>
2024-10-29 15:40:31 +08:00
Ricardo Torres
f181a795a6 refactor: flip order of mise upgrade and mise plugins update (#968)
flip order of mise plugins update and mise upgrade to attempt updating plugins first.
2024-10-28 09:59:22 +08:00
Andreas02-dev
ea2f3e07e9 feat(microsoft_store): Add Microsoft Store step for Windows (#963)
* feat(microsoft_store): Add Microsoft Store step for Windows

Add Microsoft Store Apps update step for Windows as Winget cannot update all Microsoft Store apps yet.

Closes #912

* style(translation): modify `zh_TW` translation
2024-10-23 08:15:46 +08:00
SteveLauC
8aad6eae0d refactor: add missing i18n for OpenBSD steps (#965) 2024-10-22 08:47:15 +08:00
SteveLauC
e86e5fe3e7 docs: document that we need to translate user-facing texts (#966) 2024-10-22 08:46:59 +08:00
λP.(P izzy)
2c2569c4f8 Improve OpenBSD -CURRENT detection and Dry-run feedback (#954)
* Improve OpenBSD -CURRENT detection and Dry-run feedback

This commit improves the -CURRENT detection by way of parsing `/etc/motd`. This change is more future-proof as when OpenBSD nears a stable release, `uname` will temporarily report like -STABLE.

This commit *also* adds feedback if -CURRENT is found to make debugging this feature easier with `--dry-run`, or, just a regular run as well.

* Make OpenBSD step less talky and improve verbiage.

This commit removes the command flag feedback. This commit also swaps the output "update", for "upgrade", making this step closer to other steps for consistency.
2024-10-18 08:26:27 +08:00
Rebecca Turner
9ffdc9649e Add support for Lix (Nix fork) (#952)
Add support for Lix

Lix is a fork of Nix 2.18 focused on maintainability and user
experience. It has a different format for the version, to distinguish it
from CppNix:

    $ nix --version
    nix (Lix, like Nix) 2.91.0

See: <https://lix.systems/>
2024-10-18 08:23:25 +08:00
Rikiub%
a5d4f2eec9 i18n (app.yml): Add Spanish localization (es) (#955)
* Update app.yml

* "es" localization added

* Grammar fixes

* Fix YAML syntax errors

* Fix YAML syntax errors

* Fix duplicated

* Fix duplicate

* Grammar fix

* Grammar fix

* Fix duplicate

* Improve grammar

* Update locales/app.yml

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* Improve Grammar

* Improve Grammar

* Improve Grammar

* Improve Grammar

* Improve Grammar

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-10-17 08:04:49 +08:00
Nils
a5df40e01d Refactor config.rs and vagrant.rs files (#949)
* Refactor config.rs and vagrant.rs files

* Refactor config.rs and vagrant.rs files
2024-10-15 17:56:03 +08:00
SteveLauC
0573fc97c6 docs: update release procedure that SECURITY.md should be updated in major release (#946)
docs: update release procedure that SECURITY.md should be updated in major releases
2024-10-14 17:01:22 +08:00
Nils
1ae95f41a1 Update SECURITY.md (#945) 2024-10-14 16:37:15 +08:00
λP.(P izzy)
8a7af2e14d [FIXES #922] properly check for -CURRENT in OpenBSD steps and pass the correct flags to the respective commands (#923)
* [FIXES #922] properly check for -CURRENT in openbsd steps and pass the correct flags

* un-break ctx.config().dry_run() on OpenBSD Step
2024-10-14 08:29:51 +08:00
Nicolas Lorin
c36da89933 ci: add bin pkg to aur (#944) 2024-10-13 21:14:28 +08:00
SteveLauC
bbb84c2ee7 chore: release v16.0.1 (#940) 2024-10-11 10:46:50 +08:00
Tobias Micheler
36fd4b13c0 fix: pypi-release-action: downgrade upload-artifact and download-artifact to v3 (#938)
Since there are breaking changes between the upload-artifact and download-artifact versions v3 and v4, this workflow was broken, and no releases were uploaded to pypi.
A downgrade should make this work again
2024-10-10 07:26:29 +08:00
SteveLauC
49327000fc fix: tmux unknown cmd: attach-client (#937) 2024-10-08 21:33:53 +08:00
Oliver Tzeng
9c25cd7426 i18n(app.yml): new language zh_TW (#931)
* i18n(app.yml): new language zh_TW

translated topgrade to zh_TW

* Update app.yml

* Update app.yml

* fix(i18n): Fixed "self-upgrade" translation

thanks @SteveLauC
2024-10-08 19:11:11 +08:00
Alexandre Veyrenc
9767e4169c Fix typo in exit_status (#934)
fix: typo in exit_status
2024-10-08 08:52:36 +08:00
SteveLauC
0854f9c559 revert: PR 866 (#927) 2024-10-06 21:39:47 +08:00
SteveLauC
e4a068d808 chore: release v16.0.0 (#925)
* chore: release v16.0.0

* chore: it should be containers.runtime
2024-10-06 21:23:00 +08:00
SteveLauC
4c793b0df8 ci: correct checker binary name (#926)
* ci: correct checker binary name

* ci: correct checker binary name
2024-10-06 21:13:25 +08:00
SteveLauC
a021441135 fix: use single quotes for locale keys with new line char (#920) 2024-10-04 12:33:19 +08:00
Florian Nagel
29c555c394 Add i18n by using rust i18n (#807)
* feat: initial i18n setup

* style: fmt

* feat: i18n support for new steps

* fix: build on Linux

* fix: build on Linux

* refactor: rm unused translation keys

---------

Co-authored-by: Steve Lau <stevelauc@outlook.com>
2024-10-03 18:47:35 +08:00
SteveLauC
c33d396489 docs: --only is no longer experimental (#919) 2024-09-29 09:03:26 +08:00
⑆ Neveda ⑈
f6d2ba4dae feat(brew): Add greedy-auto-updates option to Brew (#914) 2024-09-26 18:29:11 +08:00
SteveLauC
a88574204d docs: don't call execute("bin_name_str") (#916) 2024-09-26 15:05:45 +08:00
Marcelo Duarte Trevisani
9435bc4b7d Add Pixi to topgrade (#915)
* Add Pixi

* make linter happy

* Fix args
2024-09-26 14:19:32 +08:00
tomaszn
27245cbd7b feat(brew): use sudo if Homebrew owned by another user on Linux (#904)
feat(brew): use sudo if Homebrew owned by another user

On Linux, run "brew update" with sudo if the Homebrew installation directory
is owned by a different user. This is typically the user who installed
Homebrew, but can also be a dedicated user account. This change ensures that
Homebrew updates can proceed smoothly even when its directory ownership does
not match the current user's UID. Proper sudo configuration is assumed for
this to work properly.
2024-09-22 21:00:52 +08:00
wetfloo
21751aa8a5 feat: tmux session attach mode (#901)
* feat: tmux session attach mode

* feat: example config update

* feat: move the comment down to be relevant

* feat: fix tmux not attaching from non-tmux env when using create_and_switch_client

* feat: make matching on tmux modes as described in suggestions

* feat: make tmux_session_attach_mode private

* feat: remove tmux mode cli option

* feat: wrap default value in quotation marks for tmux session mode

* feat: renames for tmux session management options

* feat: try to make tmux session mode description better
2024-09-17 21:06:39 +08:00
Marcel Coetzee
ad41948450 Remove check for whether conda config contains auto_activate_base (#905)
Signed-off-by: Marcel Coetzee <marcel@mooncoon.com>
2024-09-17 09:14:52 +08:00
SteveLauC
e32246f172 feat: clean scoop cache if cleanup is enabled (#909) 2024-09-16 15:27:01 +08:00
SteveLauC
25d3a816b4 fix: aura since v4.0.6 does not need sudo (#908)
* fix: aura since v4.0.6 does not need sudo

* fix: remove 'aura ' from version str
2024-09-16 13:01:05 +08:00
SteveLauC
05b1a565e0 chore: pin toolchain to MSRV(1.76) (#900)
* chore: pin toolchain to MSRV(1.76)

* chore: remove more toolchain action & update readme
2024-09-04 21:40:09 +08:00
Kreeblah
7b2623ea3c Add Debian-based system builds (#898)
* Add Debian-based system builds

* Address feedback

* Remove git as a listed dependency for Debian package
2024-09-04 11:50:39 +08:00
SteveLauC
983c5243ba fix: a panic introduced by improper unwrap() (#899)
fix: an panic introduced by improper unwrap()
2024-09-03 15:26:41 +08:00
Lucas Parzianello
1958fe1e5b Containers step: new runtime option to configuration (#896)
* pyenv: fixes #849

* feat: adds `uv` python manager step

* moved new uv step from unix to generic

* containers step: added container runtime option to config

* documented breaking change

---------

Co-authored-by: Lucas Parzianello <lucaspar@users.noreply.github.com>
2024-09-01 15:35:23 +08:00
SteveLauC
ca8558d9b4 feat: support step Bun on Windows (#893) 2024-08-26 22:21:17 +08:00
Lucas Parzianello
1b534800a9 Adds uv step (#890)
* pyenv: fixes #849

* feat: adds `uv` python manager step

* moved new uv step from unix to generic

---------

Co-authored-by: Lucas Parzianello <lucaspar@users.noreply.github.com>
2024-08-25 10:22:27 +08:00
Boris Smidt
e91c00c9c0 Add aqua tool installer cli (#889)
* Add aqua cli

* Move aqua cli to generic.rs

* Add a dry-run support to aqua

* style: format code

---------

Co-authored-by: Steve Lau <stevelauc@outlook.com>
2024-08-20 09:18:27 +08:00
Nils
a2375b4820 chore: update winget-releaser to use main branch (#888)
Update the winget-releaser action in the release_to_winget.yml workflow to use the main branch instead of v2. This ensures that the latest version of the action is being used for publishing.
2024-08-18 10:29:17 +08:00
Patrick J. Roddy
2e0c8e9e17 Fix RubyGems issues for mise regarding sudo (#887) 2024-08-18 10:28:22 +08:00
Nils
dc0ddcf9f0 Update README.md (#882)
* Update README.md

Added Chocolatey

* chore: fix broken Chocolatey link in README.md
2024-08-18 10:22:23 +08:00
Diogo Ribeiro
a1f3c86a39 feat: add volta packages (#883)
add print_info when no packages found

apply review feedback
2024-08-01 18:26:22 +08:00
Daniel Horecki
55f672eff7 Allow Nix unfree packages to be upgraded (#881)
Allow unfree packages to be upgraded

Fixes #611.

Co-authored-by: Daniel Horecki <morr@morr.pl>
2024-08-01 09:52:03 +08:00
Nils
8ece0346d8 chore: improve Windows Update step and add PSWindowsUpdate Module (#842)
* chore: improve Windows Update step and add PSWindowsUpdate Module

Refactor the `windows_update` function in `windows.rs` to improve the Windows Update step. Added a prompt for administrator privileges and updated the warning message. Also, added support for installing the PSWindowsUpdate Module as an alternative to using USOClient for Windows Update.

still see warning:
The installer will request to run as administrator, expect a prompt.
Start-Process : A parameter cannot be found that matches parameter name 'Command'.
At line:1 char:74
+ ... ath powershell -Verb runAs -ArgumentList  -NoProfile -Command Import- ...
+                                                          ~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Process], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand

VERBOSE: MSI-THIN-GF36 (6/30/2024 4:48:48 PM): Connecting to Microsoft Update server. Please wait...
VERBOSE: Found [0] Updates in pre search criteria

but as the verbose shows it works

* trying

* fix
2024-08-01 09:50:48 +08:00
Nicolas Lorin
b1fe1d201a ci: fix release_to_aur.yml (#879) 2024-07-29 16:13:33 +08:00
Nils
5010abdc22 Update SECURITY.md (#878) 2024-07-29 10:01:46 +08:00
SteveLauC
e4441d5021 refactor: fix Windows clippy (#880)
Refactor: fix Windows clippy
2024-07-29 09:01:04 +08:00
dashmoho
5af0c6a7e5 Fix nix upgrades (#874)
Nix version 2.21 changed how packages are upgraded.
Fixes #782.

Co-authored-by: Daniel Horecki <morr@morr.pl>
2024-07-24 07:37:22 +08:00
SteveLauC
b8da17106a feat: support ZVM (#777) 2024-07-23 07:26:08 +08:00
Tommaso Melacarne
fdf40dbf43 Fix nightly clippy warnings (#872) 2024-07-22 07:33:42 +08:00
Ryan Zoeller
f3b6530969 feat(os): support NI Linux Real-Time's opkg package manager (#870)
NI Linux Real-Time is a Yocto Linux-based distribution used with
NI's embedded and real-time controllers.

Related links:
- https://www.ni.com/en/shop/linux/introduction-to-ni-linux-real-time.html
- https://github.com/ni/nilrt
- https://github.com/ni/nilrt-docs
2024-07-21 09:09:36 +08:00
Lazerbeak12345
cbc5fc94f9 feat(linux.rs): Add support for Funtoo (#868)
* feat(linus.rs): Add support for Funtoo

* style(linux.rs): fix clippy reccomendations

* test(funtoo support): add funtoo test
2024-07-20 11:04:26 +08:00
SteveLauC
dceb697355 feat: don't run reboot with sudo on Linux with systemd (#866) 2024-07-20 10:13:14 +08:00
Lucas Parzianello
07118fa0d2 Fix pyenv: no such command 'update' (#860)
pyenv: fixes #849

Co-authored-by: Lucas Parzianello <lucaspar@users.noreply.github.com>
2024-07-11 07:52:09 +08:00
dependabot[bot]
16e6db0def chore(deps): bump zerovec-derive from 0.10.2 to 0.10.3 (#858)
Bumps [zerovec-derive](https://github.com/unicode-org/icu4x) from 0.10.2 to 0.10.3.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits/ind/zerovec-derive@0.10.3)

---
updated-dependencies:
- dependency-name: zerovec-derive
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 07:44:46 +08:00
dependabot[bot]
64d8f6d632 chore(deps): bump zerovec from 0.10.2 to 0.10.4 (#856)
Bumps [zerovec](https://github.com/unicode-org/icu4x) from 0.10.2 to 0.10.4.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits/ind/zerovec@0.10.4)

---
updated-dependencies:
- dependency-name: zerovec
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-09 07:59:04 +08:00
SteveLauC
180b5cba58 docs: document that maintenance continues (#855) 2024-07-08 09:26:57 +08:00
Steve Lau
bac416e907 docs: document that it is currently unmaintained 2024-07-07 16:23:23 +08:00
NAKASHIMA, Makoto
cb674a1572 fix: traverse symbolic links under $CONIG_DIR/topgrade.d (#852) (#853) 2024-07-07 13:47:53 +08:00
SteveLauC
960b14fa20 feat: support Poetry (#790) 2024-07-07 10:37:07 +08:00
tranzystorekk
a9f57d4205 Small clap adjustments (#846)
* style(cli): use new clap keywords

* fix(cli): use lowercase command name
2024-07-01 17:06:04 +08:00
SteveLauC
13330b6950 docs: update release procedure (#845) 2024-07-01 10:21:35 +08:00
SteveLauC
1ebcc9beee chore: prepare for v15.0.0 (#843) 2024-07-01 09:45:20 +08:00
SteveLauC
55e1bbf2b9 feat: new step Lensfun's database update (#839)
* feat: new step Lensfun's database update

* refactor: take 1 as a success exit code
2024-06-30 22:41:09 +08:00
SteveLauC
f2dfa1e475 fix: consider TMUX_PLUGIN_MANAGER_PATH when searching tpm binary (#835)
* fix: consider TMUX_PLUGIN_MANAGER_PATH when searching tpm binary

* fix: correct update_plugins path when env var is present
2024-06-30 19:17:30 +08:00
SteveLauC
fcd53e772a chore: collect --dry-run and --yes opts info in feature request template (#838)
chore: collect --dry-run and --yes opts info in feature request template
2024-06-30 14:17:45 +08:00
dependabot[bot]
8b9d7ef8f3 chore(deps): bump curve25519-dalek from 4.1.2 to 4.1.3 (#827)
Bumps [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/dalek-cryptography/curve25519-dalek/releases)
- [Commits](https://github.com/dalek-cryptography/curve25519-dalek/compare/curve25519-4.1.2...curve25519-4.1.3)

---
updated-dependencies:
- dependency-name: curve25519-dalek
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 09:49:20 +08:00
SteveLauC
d8406a8cfe style: allow unused ExecutorChild (#829)
* style: allow unused ExecutorChild

* style: remove duplicate cfg on windows
2024-06-19 09:43:26 +08:00
SteveLauC
4a9ef581e5 chore: bump deps (#823) 2024-06-13 09:21:42 +08:00
Tamás Demeter-Haludka
a52db1f261 Run MasonUpdate as part of the vim updates (#821)
feat(vim): add mason update
2024-06-13 09:00:15 +08:00
Yaroslav Markin
8e16174ce7 fix(RubyGems): support no-sudo updating for rbenv and rvm (#820) 2024-06-06 19:37:06 +08:00
huajingyun
c748bb5d7a deps: bump libc from 0.2.153 to 0.2.155 (#818) 2024-05-28 09:23:10 +08:00
lachsdachs
3cc8f0d818 Add linux mint support (#817)
Update linux.rs
2024-05-26 16:26:11 +08:00
SteveLauC
f96eeeda6b chore: build binary for both macOS aarch64 and amd64 (#816) 2024-05-25 20:26:21 +08:00
SteveLauC
d1d8904376 ci: replace deprecated gh actions with alternatives (#814) 2024-05-25 19:29:17 +08:00
SteveLauC
3b329fe687 chore: update PR template (#815) 2024-05-25 17:35:46 +08:00
SteveLauC
9eb1b4ac9f ci: remove code coverage test & uniform file names (#811) 2024-05-24 09:02:05 +08:00
lachsdachs
c4c0bd7383 add upgrade stuff for bedrock linuxmint strata (#813) 2024-05-24 09:01:46 +08:00
alice
1e9de5832d feat: add support for chimera linux (#808)
since it also uses apk the update/upgrade is identical to alpine/wolfi
2024-05-19 18:48:51 +08:00
dependabot[bot]
f2b17cdd9d chore(deps): bump mio from 0.8.10 to 0.8.11 (#729)
Bumps [mio](https://github.com/tokio-rs/mio) from 0.8.10 to 0.8.11.
- [Release notes](https://github.com/tokio-rs/mio/releases)
- [Changelog](https://github.com/tokio-rs/mio/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/mio/compare/v0.8.10...v0.8.11)

---
updated-dependencies:
- dependency-name: mio
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-19 09:55:30 +08:00
dependabot[bot]
7bfd6c2439 chore(deps): bump h2 from 0.3.24 to 0.3.26 (#766)
Bumps [h2](https://github.com/hyperium/h2) from 0.3.24 to 0.3.26.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/v0.3.26/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.24...v0.3.26)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-19 09:55:05 +08:00
dependabot[bot]
0e8d5f0266 chore(deps): bump rustls from 0.21.10 to 0.21.12 (#804)
Bumps [rustls](https://github.com/rustls/rustls) from 0.21.10 to 0.21.12.
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.21.10...v/0.21.12)

---
updated-dependencies:
- dependency-name: rustls
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-19 09:54:27 +08:00
Nils
32add8f046 Dependatbot Updates (#802)
* chore(deps): bump actions/checkout from 3 to 4

Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): bump github/codeql-action from 2 to 3

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): bump softprops/action-gh-release from 1 to 2

Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 19:48:09 +08:00
SteveLauC
f661f00277 feat: support auto-cpufreq (#800) 2024-05-18 16:34:03 +08:00
Alok Singh
2a1999fe20 Add rye support (#799)
Rye is a new cargo-like package manager for python by @mitsuhiko.
2024-05-13 20:52:13 +08:00
SteveLauC
4d66431aad fix: Fedora Sway Atomic should be recognized as FedoraImmutable (#795)
* fix: Fedora Sway Atomic should be recognized as FedoraImmutable

* style: fmt
2024-05-11 11:20:43 +08:00
SteveLauC
767f0d91f4 refactor: 2 clippy warnings (#789) 2024-05-06 20:37:55 +08:00
edi
a3428e3477 Always display windows update step (#781)
* always display windows update step

* remove extra comma

* i guess format wants the comma
2024-05-06 20:24:57 +08:00
David C
614131b7bf fix(os): detect Fedora IoT Edition as immutable Fedora variant (#774)
Without this change, it is detected as a regular Fedora variant and
updating fails because neither `dnf` nor `yum` is found.
2024-04-17 09:05:54 +08:00
Dan Sully
9b0681f3b8 Add config flag to toggle verbose Git repository output. (#763)
* Add config flag to toggle verbose Git repository output.

If `true`: the default, no change.

If `false`: Only show repositories that have been updated or have an error.

Minor tweak to output (removed colon) so that copy and paste for 'cd' is nicer.
2024-04-14 10:28:03 +08:00
Andre Toerien
ecf8fb7a47 fix: better dotnet tool list header parsing (#772)
fix: better dotnet tool list header parsing
2024-04-14 09:10:08 +08:00
Andrew Barchuk
04bfb45a97 Fix local host detection for remotes with user (#755) 2024-04-08 19:43:32 +08:00
SteveLauC
d90ce30452 feat: support update PlatformIO Core (#759) 2024-04-07 11:03:33 +08:00
Ricardo Torres
ab21600ca6 feat: add support for mise (#757)
Add support for mise-en-place (or mise). Mise is a tool like asdf (already supported). https://mise.jdx.dev/
2024-03-30 18:40:16 +08:00
λP.(P izzy)
728ea26204 FIXES #708: add config directive for pkg_* cleanup on OpenBSD (#753)
FIXEs #708: add config directive for pkg_* cleanup on OpenBSD
2024-03-26 11:07:39 +08:00
SteveLauC
373cd3b3ae fix: don't use Command::new(bin_name) as it won't work on Windows (#750) 2024-03-24 11:48:17 +08:00
SteveLauC
f4e0258b09 style: fix 2 clippy lint unless_vec & unused_io_amount (#751) 2024-03-24 11:24:39 +08:00
SteveLauC
d50360a69a feat: support update ClamAV databases (#747) 2024-03-19 14:10:47 +08:00
SteveLauC
351922c81f feat: put step logs in a span (#746) 2024-03-16 14:17:19 +08:00
Alok Singh
9518f43866 Add support for Lean 4's elan (#742) 2024-03-16 09:35:47 +08:00
SteveLauC
2c1ce3d4e6 refactor: make GitSteps a dedicated step (#737) 2024-03-09 17:57:33 +08:00
SteveLauC
12116c3261 fix: use env BUN_INSTALL to locate package.json (#734) 2024-03-07 14:12:16 +08:00
Gerald Chen
fbc84e8aa1 fix(pipx): adds --include-injected argument to pipx (#726) 2024-03-01 15:06:23 +08:00
Brent Monning
6dab1e4f37 feat: adds xcodes step (#643) 2024-03-01 07:58:24 +08:00
Lucas Parzianello
650a143602 Adds pyenv step (#724) 2024-02-27 09:25:18 +08:00
Nils
9b6027fe78 Update GitHub Actions workflow for Codecov integration (#718)
- Refine the testing matrix to include only stable and nightly versions of Rust
- Add 'fail_ci_if_error' option to Codecov step for stricter CI checks
- Ensure newline at end of file
2024-02-25 11:19:09 +08:00
Nils
0e30e05ce8 Add GitHub Actions Workflow for Build and Test (#717)
* "Add *.profraw files to .gitignore

*.profraw files are generated by LLVM's Clang compiler when using the -fprofile-instr-generate option for Profile Guided Optimization. These files contain raw profiling data and should not be version controlled."

* Remove redundant import of TryFrom trait

The TryFrom trait was being imported explicitly in src\steps\os\windows.rs, even though it's already part of the Rust prelude and automatically imported into every Rust program. This was causing a compiler warning. This commit comments out the redundant import to resolve the warning.

* Add GitHub Actions workflow for Rust build and test

This commit adds a new GitHub Actions workflow for building and testing the Rust project across multiple operating systems (Ubuntu, Windows, macOS) and Rust versions (stable, beta, nightly). It also includes caching for dependencies and build artifacts, and uploads code coverage reports to Codecov.

* Update Codecov action and add token for coverage report upload

This commit updates the version of the Codecov GitHub Action used to upload coverage reports from v4 to v4.0.1. It also adds a token from the repository secrets to authenticate the upload. This ensures secure and authorized communication with the Codecov service.

* "Fix misuse of --jobs flag in cargo test command"

* "Fix grcov command in GitHub Actions workflow

The grcov command was previously prefixed with './', which caused an error because grcov was not found in the current directory. This commit removes the './' prefix to call grcov from the global path, where it is installed."

* Update GitHub Actions workflow for cross-platform compatibility

This commit modifies the 'build-and-test.yml' GitHub Actions workflow to ensure it works correctly across different operating systems (Ubuntu, Windows, MacOS). The RUSTFLAGS environment variable is now set in a cross-platform compatible way. The workflow will run the build and test process on every pull request and push to the main branch, generate a coverage report, and upload it to Codecov.

* Changed workflow trigger event to 'workflow_run' completion of 'Build and test' workflow

* "Updated GitHub Actions workflow to correctly set environment variables for code coverage"

* Renamed build and test workflow

* Update GitHub Actions workflow trigger

Change the trigger of the 'Test with Code Coverage' workflow to run when the 'build-and-test' workflow is completed. This ensures that code coverage is only calculated after successful build and test runs.

* Update workflow_run trigger in code-coverage.yml

* Fix CODECOV_TOKEN in code-coverage.yml workflow

* Update code-coverage workflow to trigger on pull requests and pushes to main branch

* Update .gitignore file to exclude LLVM profiling output

* Add empty line at the end

* Remove unused import in windows.rs

* Update .github/workflows/build-and-test.yml

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* Update .github/workflows/build-and-test.yml

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* Remove code coverage workflow

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-02-25 10:35:56 +08:00
Nils
eea952fa78 Create devskim.yml to enable GitHub code scanning for this repository (#700) 2024-02-24 18:53:10 +08:00
SteveLauC
6071a1ee3b chore: git ignore more (#715) 2024-02-24 13:45:53 +08:00
SteveLauC
a801b7b9f4 chore: bump deps (#714) 2024-02-24 13:14:53 +08:00
SteveLauC
c6e3f0ae0a revert: revert 614 to remove the -p option (#713) 2024-02-24 11:26:41 +08:00
SteveLauC
a43b03d3db feat: also detect Helix step with bin name hx (#710) 2024-02-23 07:39:31 +08:00
Md Isfarul Haque
12b0fa57ad fix: fetch and build Helix grammar as a regular user (#698) 2024-02-23 07:26:08 +08:00
Nils
d9e304f0ef Add .vs to .gitignore (#706)
* Added .vs vode to .gitignore

* Adjust .vs to .vs/
2024-02-22 09:47:37 +08:00
dependabot[bot]
842b92cca7 chore(deps): bump actions/download-artifact from 3 to 4 (#704)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 09:39:05 +08:00
dependabot[bot]
485f0ec9c8 chore(deps): bump EnricoMi/publish-unit-test-result-action from 1 to 2 (#705)
Bumps [EnricoMi/publish-unit-test-result-action](https://github.com/enricomi/publish-unit-test-result-action) from 1 to 2.
- [Release notes](https://github.com/enricomi/publish-unit-test-result-action/releases)
- [Commits](https://github.com/enricomi/publish-unit-test-result-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: EnricoMi/publish-unit-test-result-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 09:38:40 +08:00
λP.(P izzy)
5e3b5fc9a7 Fix OpenBSD Step failing to build with E0599 (#707)
* fix openbsd support failing with error E0599

* clean up a little formatting in src/os/openbsd.os
2024-02-21 21:10:34 +08:00
SteveLauC
7c63541cad fix: zinit default install location (#625) 2024-02-17 13:15:53 +08:00
SteveLauC
238e089d74 docs: document brew config entries[skip ci] (#696) 2024-02-17 13:14:39 +08:00
luciodaou
8991bc9f62 feat(brew): adds "greedy-latest" option to Brew (#636) 2024-02-17 11:45:57 +08:00
SteveLauC
7a3f3a8905 feat: support waydroid (#687) 2024-02-16 11:57:53 +08:00
dependabot[bot]
e4085e03eb chore(deps): bump actions/checkout from 2 to 4 (#688)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-15 16:19:58 +08:00
dependabot[bot]
4b0c366e5f chore(deps): bump actions/upload-artifact from 3 to 4 (#689)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-15 16:19:18 +08:00
dependabot[bot]
ea97240d09 chore(deps): bump actions/cache from 1 to 4 (#690)
Bumps [actions/cache](https://github.com/actions/cache) from 1 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v1...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-15 16:18:47 +08:00
dependabot[bot]
12de531abb chore(deps): bump codecov/codecov-action from 1 to 4 (#691)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-15 16:18:24 +08:00
dependabot[bot]
c3876ce3bf chore(deps): bump katyo/publish-crates from 1 to 2 (#692)
Bumps [katyo/publish-crates](https://github.com/katyo/publish-crates) from 1 to 2.
- [Release notes](https://github.com/katyo/publish-crates/releases)
- [Commits](https://github.com/katyo/publish-crates/compare/v1...v2)

---
updated-dependencies:
- dependency-name: katyo/publish-crates
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-15 16:18:00 +08:00
SteveLauC
cbbfc3a114 docs: update install doc with Winget (#693) 2024-02-15 16:17:11 +08:00
Nils
ad2bfc9abd Keeping actions up to date with Dependabot (#685) 2024-02-15 16:04:51 +08:00
Nils
528461412e Publish new releases of topgrade to the Windows Package Manager with WinGet Releaser
Publish new releases of topgrade to the Windows Package Manager with WinGet Releaser (GitHb Action).
2024-02-15 16:04:11 +08:00
SteveLauC
64db679390 ci: add macOS aarch64 check (#680) 2024-02-06 16:28:01 +08:00
Wallunen
77a8b3b7d2 feat: add fetch_head configuration option into brew (#679) 2024-02-06 16:17:27 +08:00
Nils
7007e76ab5 Fix/winget (#670)
* cargo update

* Remove the check for 'winget_enable' set to 'true'. On my Windows 10 and 11 machines, there are no issues with Winget anymore. As far as I remember, it was disabled by default because it was buggy back then.

* remove print_warning

* Revert "cargo update"

This reverts commit 5f4e532bc1.

* Removed the `enable_winget = true` configuration as winget is now enabled by default.

* Removed the #[cfg(windows)] flag.

* Revised as Recommended

* Wrapping at 80
2024-02-03 09:09:47 +08:00
Andy Piper
3c970063a9 fix: correct typos in output (#677)
Corrects a grammatical issue and a typo in two of the step output messages.
2024-01-31 09:07:38 +08:00
SteveLauC
b70830015e docs: fix a wrong preposition[skip ci] (#676) 2024-01-30 11:06:32 +08:00
SteveLauC
b43f2c8b3a ci: run cargo test in ci (#674) 2024-01-29 10:36:30 +08:00
RJ Trujillo
c311da16f3 feat: Add support for Wolfi (#672)
* feat: Add support for Wolfi

This adds support for updating Wolfi via Topgrade

* chore(wolfi): Add os release info and unit test

* chore(wolfi): Don't check ID_LIKE as it is unique
2024-01-29 09:11:53 +08:00
Nils
37608a338c Fix/usoclient (#669)
* cargo update

* Implementing a check for Windows 11 and, if detected, skipping Windows Update via usoclient.exe. It is suggested to install PSWindowsUpdate.

* Revert "cargo update"

This reverts commit 43a4d321cf.

* Revert "Implementing a check for Windows 11 and, if detected, skipping Windows Update via usoclient.exe. It is suggested to install PSWindowsUpdate."

This reverts commit e1ef2e4bc5.

* Removed the usoclient step and added an error message.

* cargo fmt
2024-01-29 09:02:40 +08:00
Nils
b07288e674 Fix/pswindowsupdate (#671)
* cargo update

* An elevated PowerShell is required to run Install-WindowsUpdate on my system.

* Revert "cargo update"

This reverts commit fb58ce761a.
2024-01-29 09:01:38 +08:00
Nils
707698faab Update Cargo.lock (#673)
cargo update
2024-01-29 09:00:08 +08:00
SteveLauC
2e70d132d0 feat: certbot renew (#665) 2024-01-28 13:03:30 +08:00
Brent Monning
30c5b31e21 fix: softwareupdate under dry run (#668) 2024-01-27 14:57:10 +08:00
SteveLauC
77ff6cb714 feat: support wildcard in ignored_containers (#666) 2024-01-27 10:54:55 +08:00
SteveLauC
ea13c51b7d chore: release v14.0.1 (#662) 2024-01-25 15:40:52 +08:00
Cat Core
3ed763b884 Fix system updates for Nobara (#661)
* Fix system updates for Nobara

* fmt

* Add os-release test for Nobara

* Make requested changes

* cargo fmt
2024-01-24 19:29:20 +08:00
samhanic
10e1e170b7 fix vscode extensions update step (#650)
* fix vscode extensions update using the new update-extensions cli

* fix non-linux compilation
2024-01-24 10:32:00 +08:00
Sandro
ffa62afc66 Follow up to the follow up in #616 (#660) 2024-01-24 10:22:36 +08:00
SteveLauC
f794329913 feat: skip breaking changes notification with env var (#659)
* feat: skip breaking changes notification with env var

* ci: apply that env in ci
2024-01-23 14:50:35 +08:00
SteveLauC
f9a35c7661 docs: add doc on how to do a new release (#658) 2024-01-23 11:58:09 +08:00
SteveLauC
ed496f3462 chore: fix file name typo[skip ci] (#657)
chore: fix file name typo
2024-01-23 11:50:02 +08:00
Rui Chen
6accdae232 workflows(homebrew): replace Homebrew/actions/bump-formulae with Homebrew/actions/bump-packages (#656)
Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-01-23 10:29:48 +08:00
SteveLauC
96efcc6c0d chore: release v14.0.0 (#652) 2024-01-22 11:13:33 +08:00
SteveLauC
bf72d7bb5a fix: oh-my-zsh step issue #646 (#647) 2024-01-22 09:18:27 +08:00
dependabot[bot]
dadffb1081 chore(deps): bump h2 from 0.3.22 to 0.3.24 (#645)
Bumps [h2](https://github.com/hyperium/h2) from 0.3.22 to 0.3.24.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/v0.3.24/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.22...v0.3.24)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-20 12:13:19 +08:00
Ned Wolpert
78dc567226 Added an Audit step for FreeBSD and DragonFly packagees. (#640)
* Added an Audit step for FreeBSD and DragonFly.

Allows for auditing the packages to be disabled since they are breaking steps.
Current behaivor is the default, where if the audit fails topgrade stops. Can
be disabled in the [misc] section independenly from other sections
2024-01-08 09:40:01 +08:00
Mike Wood
362ce4f4f9 fix(os) consider Fedora Kinoite and other immutable distros to be the FedoraImmutable (#638)
* fix(os) consider Fedora Kinoite to be the Fedora Silverblue distribution

* fix(os) support additional Fedora immutable variants

Rename FedoraSilverblue Distribution to FedoraImmutable.  Add test cases for Onyx, Sericea and Silverblue.  Rename upgrade method to match distribution.

Fixes #637
2024-01-08 08:48:48 +08:00
Carrol Cox
ab35cd7b10 feat(pipx-update): add quiet flag for pipx upgrade-all on version 1.4.0+ (#635)
This commit introduces conditional logic to the `run_pipx_update` function that checks the installed version of pipx. If the version is 1.4.0 or higher, the `--quiet` argument is added to the `pipx upgrade-all` command to suppress non-critical output during the upgrade process, adhering to the new feature introduced in pipx 1.4.0 as per the documentation (https://pipx.pypa.io/stable/docs/#pipx-upgrade-all). This change aims to make the upgrade process less verbose and more manageable in automated scripts or CI/CD pipelines where log brevity is beneficial.
2023-12-31 11:38:39 +08:00
SteveLauC
15f4ad7cd1 refactor: update pip if extern managed and global.break-system-packages is true (#634)
refactor: update pip if extern managed and global.break-system-packages is true
2023-12-30 18:23:33 +08:00
Rebecca Turner
cbfb92041f Skip nix upgrade-nix when Nix is installed in a nix profile (#622)
Make `nix upgrade-nix` a separate step

Also check that Nix can be upgraded before running `nix upgrade-nix` to
work around a bug.

See: <https://github.com/NixOS/nix/issues/5473>
2023-12-21 08:55:32 +08:00
SteveLauC
a506c67cac fix: remove deprecated brew option '--ignore-pinned' (#629) 2023-12-19 17:09:32 +08:00
SteveLauC
788e0412f6 feat: inform users of breaking changes on first run (#619) 2023-12-03 09:52:35 +08:00
Nils
18b37ce3e3 Update config.example.toml (#621)
Added WinGet setting:
enable_winget = true
2023-11-26 08:06:17 +08:00
Jakob Fels
a15e6748c7 Add option to ignore containers to pull (#613) 2023-11-24 16:44:52 +08:00
SteveLauC
c6d0539fd2 chore(deps): bump all deps (#618) 2023-11-24 07:50:41 +08:00
LeSnake
3eb3867944 Bun packages fixes (#617)
* fix running with --only

* fix error when no packages installed
2023-11-23 06:36:00 +08:00
DomGlusk
810315b0e2 Make zinit and zi use parallel updates (#614)
* Update zsh.rs to make zinit and zi use parallel

* run cargo fmt

---------

Co-authored-by: Dominic Gluskin <rhinoarmyleader@gmail.com>
2023-11-22 11:18:41 +08:00
SteveLauC
b461fc2536 refactor: cleanup for #615 (#616) 2023-11-22 09:34:21 +08:00
Sam Vente
7e63977ba0 revert git pushing functionalities (#615) 2023-11-22 09:04:19 +08:00
SteveLauC
78dec892cf docs: migration and breaking changes (#606) 2023-11-12 11:43:58 +08:00
pacjo
9ea6628b5c docs: fix typo in config.example.toml (#603)
docs(config): fix typo (dfault -> default)
2023-11-10 10:32:15 +08:00
LeSnake
465df2e9be feat: add Bun packages step (#599) 2023-11-05 10:34:21 +08:00
SteveLauC
61ef926849 chore: update issue template label (#596) 2023-11-01 08:57:57 +08:00
SteveLauC
7fa38c593e fix: omz remote execution if ZSH is not present (#592) 2023-10-29 18:05:20 +08:00
SteveLauC
41c6d1cd9a chore: release v13.0.0 (#579) 2023-10-20 08:07:11 +08:00
dependabot[bot]
cf3893dc49 chore(deps): bump rustix from 0.37.20 to 0.37.25 (#586) 2023-10-19 08:38:28 +08:00
SteveLauC
a2fbe92a25 refactor: make SelfUpdate a step (#585) 2023-10-18 12:19:53 +08:00
SteveLauC
e1754707d8 refactor: remove legacy deprecated macros (#583) 2023-10-18 11:13:14 +08:00
SteveLauC
cd380a53b3 docs: new demo video (#584) 2023-10-18 09:33:37 +08:00
SteveLauC
a8c29fd1a2 fix: make logger work while loading config file (#581) 2023-10-17 11:19:47 +08:00
Sam Vente
6b871e7949 switch git push and pull order (#578) 2023-10-15 17:06:40 +08:00
SteveLauC
1b5fdb6645 fix: shellexpand git.pull_only_repos & git.push_only_repos (#576) 2023-10-13 18:54:42 +08:00
Sam Vente
fe9d877cdf Add support for pushing custom git repositories (#574) 2023-10-13 17:01:35 +08:00
SteveLauC
60e7aa8f03 fix: disable dotnet greeting msg with DOTNET_NOLOGO=true (#573) 2023-10-12 14:37:52 +08:00
SteveLauC
18e2d3e59c chore: always use the latest stable toolchain for CI (#571) 2023-10-11 09:46:36 +08:00
Mylloon
d68fcb08b2 fix: Support yes option for opam upgrade (#570) 2023-10-10 08:08:46 +08:00
Zach Crownover
1f6baefdc3 Fix builds and runs on DragonFly BSD (#569) 2023-10-08 08:13:26 +08:00
SteveLauC
71efce32c1 chore: bump CI toolchain to 1.73.0 (#567) 2023-10-06 12:05:44 +08:00
dependabot[bot]
3626c9cdc8 chore(deps): bump webpki from 0.22.1 to 0.22.2 (#564)
Bumps [webpki](https://github.com/briansmith/webpki) from 0.22.1 to 0.22.2.
- [Commits](https://github.com/briansmith/webpki/commits)

---
updated-dependencies:
- dependency-name: webpki
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-03 08:21:00 +08:00
SteveLauC
a23b761304 fix: --yes option for protonup (#560) 2023-09-30 16:44:20 +08:00
SteveLauC
3fd27e4913 chore: add the check for the --yes opt in PR template (#561) 2023-09-30 12:46:01 +08:00
Sohum
b3f152b716 feat(wsl): pass verbose to topgrade-in-wsl (#556)
Closes #521
2023-09-26 11:11:19 +08:00
PabloMarcendo
df381f3a79 feat: add option for nix-env arguments (#555) 2023-09-21 09:05:03 +08:00
dependabot[bot]
2dec9db310 chore(deps): bump webpki from 0.22.0 to 0.22.1 (#554)
Bumps [webpki](https://github.com/briansmith/webpki) from 0.22.0 to 0.22.1.
- [Commits](https://github.com/briansmith/webpki/commits)

---
updated-dependencies:
- dependency-name: webpki
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-20 16:04:27 +08:00
SteveLauC
d50dc4c9f6 chore: bump CI toolchain (#553) 2023-09-20 15:57:35 +08:00
SteveLauC
ed8b563f20 fix: remote oh-my-zsh env var export issue (#528)
* fix: fix remove oh-my-zsh env export issue
2023-09-19 09:15:34 +08:00
Rebecca Turner
2a73aa731d Make error messages nicer (#551)
* Remove unhelpful information from errors

Before:

```
Git repositories failed:
   0: error: cannot pull with rebase: You have unstaged changes.
      error: Please commit or stash them.
   0:

Location:
   src/steps/git.rs:39

Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it.
Run with RUST_BACKTRACE=full to include source snippets.
```

After:

```
Git repositories failed:
   0: Failed to pull /Users/wiggles/.dotfiles
   1: error: cannot pull with rebase: You have unstaged changes.
      error: Please commit or stash them.

Location:
   src/steps/git.rs:39
```

* Improve git_repos errors

This removes the extra blank "0:" line at the end of the error, doesn't
print the error message twice, and provides the repo path in the error
message.
2023-09-19 09:09:58 +08:00
Rebecca Turner
4dd1c13bd8 fix: fix "Nix" step to use nix upgrade-nix in more situations (#550)
`nix upgrade-nix` can be used on any platform except NixOS where `nix`
is available.

Also use `nix profile upgrade --verbose` because the non-verbose mode
doesn't print anything on stdout.
2023-09-17 15:40:04 +08:00
Rebecca Turner
c1c9fe22df feat: allow setting misc.log_filters in config.toml (#552)
Allow setting `log_filters` in `config.toml`

This allows setting a list of `log_filters` in the `[misc]` section in
the `config.toml`. These filters are prepended to any filters listed
with `--log-filters`. Finally, `--verbose` can now be used with
`--log-filters`, and it will append `debug` to the list of filters
rather than replacing it entirely.
2023-09-17 15:04:46 +08:00
SteveLauC
06a6b7a2eb fix: skip needrestart when using nala on debian-based distro (#548) 2023-09-14 18:15:45 +08:00
SteveLauC
b814dd824f chore: bump ci toolchain (#544) 2023-09-01 14:42:12 +08:00
dependabot[bot]
ce234bdb59 chore(deps): bump rustls-webpki from 0.100.1 to 0.100.2 (#542)
Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.100.1 to 0.100.2.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.100.1...v/0.100.2)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-23 09:29:05 +08:00
SteveLauC
13a46a44a8 refactor: deprioritize please-sudo (#541)
refactor: deprioritze please-sudo
2023-08-22 09:14:29 +08:00
SteveLauC
dc78b00c3c feat: support LURE (#537) 2023-08-15 08:36:20 +08:00
samhanic
48ae4bf813 feat: support Vscode packages updates (#536)
feat: support vscode extensions update
2023-08-14 09:22:26 +08:00
SteveLauC
a50040e2d5 chore: add check for dry-run opt in PR template (#538)
chore: add test for dry-run opt in PR template
2023-08-13 10:24:39 +08:00
samhanic
2c9a56a8df feat: support miktex packages update (#535) 2023-08-13 10:05:07 +08:00
Sujay R
021320b292 Prioritize sudo steps to prevent sudo timeout (#532) 2023-08-06 11:32:20 +08:00
SteveLauC
9d3662c3ea chore: add ssh-related questions in issue template (#523) 2023-07-29 09:20:39 +08:00
SteveLauC
8e580457a5 chore: release v12.0.2 (#518) 2023-07-25 14:22:14 +08:00
SteveLauC
5350658dab fix: WSL detection (#508)
* fix: wSL detection
2023-07-25 14:02:13 +08:00
SteveLauC
1ec0ac50a5 fix: fix Linux and DragonFlyBSD yes option (#513) 2023-07-25 08:37:03 +08:00
SteveLauC
635bfce198 feat: extra arguments for Home Manager (#507)
* feat: extra arguments for Home Manager
2023-07-24 13:07:55 +08:00
6543
1307d2d7e8 feat: better error message on wrong os-release file (#511)
* enhancement: better error message when os-release parsing fails
2023-07-24 08:27:13 +08:00
SteveLauC
d21141fefe chore: release v12.0.1 (#510) 2023-07-23 20:06:31 +08:00
SteveLauC
0ec0e5a9dd chore: bump ci toolchain and MSRV (#506)
* chore: bump ci toolchain and MSRV

* fix clippy on macOS
2023-07-19 10:54:34 +08:00
SteveLauC
9415d7c61f fix(oh-my-zsh): fix remote oh-my-zsh issue (#496)
* fix(oh-my-zsh): fix remote oh-my-zsh issue
2023-07-18 13:59:55 +08:00
SteveLauC
42188af02b CI: release to PyPI (#500) 2023-07-18 08:11:36 +08:00
signed-log
e9581bcf15 feat: add assume-yes to more Linux managers (#501)
* Add assume-yes options to most Linux managers

Add `assume-yes` to :
- SUSE (Micro) - TW (`zypper`)
- PCLinux OS (`apt`)
- Solus (`eopkg`)
- `pacdef`
- Clear Linux (`swupd`)
2023-07-17 15:47:13 +08:00
SteveLauC
6afe4f51c6 test: unit test for Solus (#504) 2023-07-17 13:31:46 +08:00
signed-log
f623746d6c Fix clippy warning about non_minimal_cfg (#505)
Fix clippy::non_minimal_cfg warning
2023-07-17 13:30:55 +08:00
signed-log
1ce4d66e74 Ass assume-yes to DragonflyBSD (#502)
Add assume-yes to DragonflyBSD
2023-07-17 11:40:00 +08:00
har7an
3735d5c537 steps/toolbx: Don't self-update and don't send notifications (#503)
steps/toolbx: Don't send notification

after finishing execution in the toolbx step, and don't perform another
self-update (because the application will already have done that).
2023-07-17 09:08:44 +08:00
SteveLauC
f3b1d2dfb3 Merge pull request from GHSA-f2wx-xjfw-xjv6
chore: bump tempfile to ~3.6
2023-07-15 09:24:08 +08:00
Steve Lau
7f7d2633cd chore: bump tempfile to ~3.6 2023-07-15 09:17:47 +08:00
Harsh Shandilya
afd95e3d5c fix(generic): add alternate binary name for spicetify (#486) 2023-07-14 16:14:06 +00:00
SteveLauC
8f72545894 docs(config): document 4 missing sections in example config file (#485) 2023-07-14 16:13:44 +00:00
SteveLauC
d0d447deac fix: fix wrong path in oh-my-bash (#478) 2023-07-14 16:13:28 +00:00
SteveLauC
53a8683788 ci: separate code-coverage and test-config-creation (#488) 2023-07-14 16:12:53 +00:00
Janek
81491a8d03 docs: apply corrections in config.example.toml (#492)
* Fix Issues in config.example.toml

* Update config.example.toml
2023-07-14 16:12:32 +00:00
Janek
83504754ac docs: add Karma commit messages to CONTRIBUTING.md (#493)
Add Karma commit messages to CONTRIBUTING.md
2023-07-14 16:11:59 +00:00
Marcelo Duarte Trevisani
2068c2c169 Update only base conda env (#495) 2023-07-14 16:11:18 +00:00
SteveLauC
dbac121a90 refactor(config): move sudo_command to section misc (#484) 2023-07-01 13:58:39 +00:00
Thomas Schönauer
b974938a33 v12 Cargo files update (#441) 2023-06-27 10:02:27 +00:00
SteveLauC
06cb88a1a1 test: test for config file creation and default config file parsing (#459) 2023-06-23 09:04:05 +00:00
SteveLauC
a6195d284c feat: support Bob (#461) 2023-06-23 09:03:57 +00:00
SteveLauC
5b8850e8a3 chore: update bug report issue template (#474) 2023-06-23 09:03:29 +00:00
SteveLauC
57546a07fc fix(pip3): prefer python when available (#471) 2023-06-23 09:02:58 +00:00
slowsage
d7709490ce fix: Run AstroUpdate before Lazy sync (#473) 2023-06-23 09:01:55 +00:00
slowsage
3e6c6e513b fix: handle no topgrade.toml but files in topgrade.d (#460) 2023-06-13 14:17:27 +00:00
SteveLauC
30858780cf refactor: unify the behavior of the steps that require sudo (#467) 2023-06-13 14:15:57 +00:00
SteveLauC
a7ddf4575a fix: fix Mist (#466) 2023-06-05 06:38:14 +00:00
Thomas Schönauer
470231c9d1 Revert "fix: fix mist" (#465)
Revert "fix: fix mist (#464)"

This reverts commit 282e336ac4.
2023-06-03 21:22:23 +00:00
SteveLauC
282e336ac4 fix: fix mist (#464) 2023-06-03 21:20:57 +00:00
SteveLauC
658829e4ff refactor: make update fn take &ExectionContext & put update fn together (#457) 2023-06-02 20:20:42 +00:00
SteveLauC
a0ff565220 docs: update CONTRIBUTING.md & config.example.toml (#458) 2023-06-01 11:02:39 +00:00
SteveLauC
7e48c5dedc fix: warn user about bad pattern paths before skipping step git (#456) 2023-06-01 07:16:01 +00:00
slowsage
03436b7f8f fix: Handle '# [include]'. Update default config (#450) 2023-06-01 07:15:49 +00:00
SteveLauC
3f5eedb83d fix: run AM without sudo (#454) 2023-05-31 07:01:45 +00:00
SteveLauC
234ad4bdd7 docs: add config-related CONTRIBUTING doc (#452) 2023-05-30 10:03:22 +00:00
slowsage
c7923393be fix: Write to correct config path when none exists. (#449) 2023-05-30 07:07:02 +00:00
slowsage
d4548b2f9a feat: Add arguments to pipupgrade and fix enable_pipupgrade check (#448) 2023-05-30 07:04:23 +00:00
SteveLauC
f6e8af186c feat: support Vanilla Linux (#447) 2023-05-29 11:45:11 +00:00
SteveLauC
58153635da refactor: remove Anarchy and Antergos as they are discontinued (#446) 2023-05-28 12:44:49 +00:00
SteveLauC
5358509825 fix: fix panic during container update (#445) 2023-05-27 14:12:45 +00:00
SteveLauC
1ab0232d96 feat: support deepin OS (#444) 2023-05-27 09:41:51 +00:00
SteveLauC
66860f1848 refactor: remove unnecessary qualification (#443) 2023-05-27 09:41:42 +00:00
SteveLauC
625f823f46 refactor: rename update fn name & some cleanup (#442) 2023-05-27 09:37:51 +00:00
Thomas Schönauer
6263ab7e10 Allow apt-get update to continue to apt-get upgrade with error code 100 (#440)
Allow apt-get update to continue with error code 100
2023-05-26 19:57:05 +00:00
Kevin Gavrois
7db991db9d Merge code for desktop notification between MacOS and Linux (#438) 2023-05-26 10:07:14 +02:00
SteveLauC
d75782892e docs: CONTRIBUTING.md (#439) 2023-05-26 09:34:20 +02:00
PolpOnline
cb7adc8ced Added ability to include directories as an extension of the config file (#421) 2023-05-25 12:22:11 +02:00
SteveLauC
7c3ba80270 fix: fix .NET language issue (#437)
Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2023-05-25 09:24:53 +02:00
SteveLauC
76c39edc8b refactor: make all step functions take &ExectutionContext (#436) 2023-05-25 09:09:23 +02:00
SteveLauC
c20a300eea fix: use --platform opt when pulling containers (#435) 2023-05-23 08:47:47 +02:00
SteveLauC
de3902a9c9 fix: use env ZSH to compose oh-my-zsh install dir (#434) 2023-05-22 14:06:19 +02:00
SteveLauC
8bca671e9f fix: run deb-get without sudo (#430) 2023-05-20 19:35:17 +02:00
MonstrousOgre
54301a6a17 Adding local pip-review (#433) 2023-05-20 19:33:59 +02:00
Cat Core
f06b7c0807 Differentiate NPM and PNPM steps in name (#431) 2023-05-20 11:33:41 +02:00
SteveLauC
43c02cf7a7 feat: support maza (#427) 2023-05-17 19:18:03 +02:00
SteveLauC
3a1568e884 feat: support oh-my-bash (#425) 2023-05-17 19:17:37 +02:00
SteveLauC
14753a14e7 feat: support AppMan (#423) 2023-05-09 08:03:06 +02:00
Sourajyoti Basak
227e8dcc8d feat(shell): add packer.nu (#414)
* feat(shell): add `packer.nu`

* dependency update (#413)

* fix(main): move `packer.nu` step before linux package managers

---------

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2023-05-05 11:01:24 +02:00
signed-log
97fd2b2718 Make zypper dist-upgrade opt-in on SLE/Leap (#417)
Make zypper dist-upgrade opt-in on SLE/Leap

- Create a `suse_dup` config option
- Create a new `Distribution::OpenSuseTumbleweed` object along with `upgrade_opensuse_tumbleweed()`
    * The purpose of it is to ignore the config option on Tumblweed as
      zypper `dup` is the only way to update a Tumbleweed
2023-05-05 10:24:01 +02:00
SteveLauC
f30e36d7bb feat: support stew (#422) 2023-05-05 10:17:42 +02:00
SteveLauC
d640bc66f5 docs: update README for alternative config path (#419) 2023-05-04 08:36:36 +00:00
PolpOnline
a2331a2575 Add the ability to have the config file in $XDG_CONFIG_HOME/topgrade/topgrade.toml (#418) 2023-05-03 19:53:52 +00:00
Thomas Schönauer
26a2c3c266 v11.0.2 version bump (#416)
* dependency update

* Cargo.toml version bump
2023-05-01 18:26:18 +00:00
Thomas Schönauer
ceafcba88f dependency update (#413) 2023-05-01 15:02:16 +00:00
Thomas Schönauer
d7182b5a6e v11.0.0 bump (#410) 2023-04-30 19:02:26 +00:00
Thomas Schönauer
93ec1172fe Update README.md 2023-04-30 18:58:22 +00:00
Thomas Schönauer
609477a373 Update README.md 2023-04-30 18:57:23 +00:00
Thomas Schönauer
1d49af10a7 Update README.md 2023-04-30 18:57:07 +00:00
Utkarsh Gupta
327ed837c2 Replace directories with home & etcetera (#407)
* Use global lazy HOME_DIR

* Remove unused base_dirs

* Use `etcetera` instead of `directories`

---------

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2023-04-30 18:32:13 +00:00
Thomas Schönauer
d406e2aeab Assume Fedora Silverblue based on os-release and not on existence of rpm-ostree (#393)
* Do not assume silverblue if rpm-ostree is available

* Fix typo

* Fix config error
2023-04-30 18:22:08 +00:00
dependabot[bot]
0991cc8a6f Bump enumflags2 from 0.7.5 to 0.7.7 (#408) 2023-04-24 20:37:00 +00:00
Brian Riccardi
ac6330fac8 Added support to 'mamba' (alternative to 'conda' with the exact same commands/interface) (#395) 2023-04-17 14:19:59 +00:00
dependabot[bot]
29f0d229d3 Bump h2 from 0.3.16 to 0.3.17 (#404) 2023-04-17 14:19:48 +00:00
Roey Darwish Dror
3dd11f7b52 No need to run self-update in Rustup (#403) 2023-04-05 12:42:47 +00:00
Roey Darwish Dror
ddb1a021bb Display the preamble in Linux only if notify-send is installed (#401) 2023-04-05 12:34:47 +00:00
PolpOnline
565aa405be Add no-self-update config and flag (#388) 2023-03-22 21:05:21 +00:00
Utkarsh Gupta
907465f891 run_custom_command: allow using interactive shell on unix (#383) 2023-03-17 16:28:58 +00:00
Trevor Sullivan
250485c826 Add Scoop manifest link for Windows installation (#384) 2023-03-15 07:40:31 +00:00
Thomas Schönauer
3a3f22b4e5 V10 3 2 bugfix + revert #347 (#382)
* Revert "run_custom_command: use interactive shell on unix (#347)"

This reverts commit d767ef31a5.

* v10-3-3 + revert of #347
2023-03-13 19:27:33 +00:00
Thomas de Queiroz Barros
a3628d0d49 Add sudo_command option (#379)
This allows the user to specify the preferred sudo command to be used
instead of the command chosen by Sudo::detect
2023-03-13 19:23:37 +00:00
Thomas Schönauer
462016e51e 10.3.2 patch (#378)
* 10.3.2 patch

* Clippy
2023-03-12 20:37:41 +00:00
Thomas Schönauer
199b81183b Update check-and-lint.yaml to use Rust version 1.68.0 2023-03-12 20:22:58 +00:00
Thomas Schönauer
342d7f7209 skip skip-notify warning on Win (#362) 2023-03-03 11:58:58 +00:00
Isaac Tay
9c2d121fc9 cargo: add cleanup step (using cargo-cache) (#371) 2023-03-03 11:58:15 +00:00
Roey Darwish Dror
7728819133 Support antidote (#368) 2023-02-26 21:45:43 +00:00
arctic-penguin
a5d5d987d2 pacdef: support new version 1.x (#364) 2023-02-23 22:01:53 +00:00
TGRCDev
fae5d80f0a pip3: Check for EXTERNALLY-MANAGED (PEP 668) (#367) 2023-02-23 22:01:26 +00:00
Thomas Schönauer
2369e371be apt: Recognise mist (#351) 2023-02-18 21:22:02 +00:00
Jason Stelzer
e3b71b647f Silence misleading warning on other platforms. (#353)

2023-02-07 17:21:15 +00:00
Guilherme Silva
e224ea38b3 CI: Update cross to v0.2.5 (#354) 2023-02-07 17:19:46 +00:00
Thomas Schönauer
8ec37bcd44 vim: Adds Astrovim support (#352) 2023-02-03 13:46:09 +00:00
Thomas Schönauer
6b7f6f4cc7 ruby_gems: Fixes asdf (#350) 2023-02-02 21:48:48 +00:00
Utkarsh Gupta
d767ef31a5 run_custom_command: use interactive shell on unix (#347) 2023-02-02 19:46:11 +00:00
Dan Sully
fcf776fe07 Add support for please (access elevation) (#310)
* Add support for please (access elevation)

Please is a sudo-like tool written in Rust.

https://gitlab.com/edneville/please

* Fixes code typo

---------

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
Co-authored-by: Thomas Schönauer <t.schoenauer@hgs-wt.at>
2023-02-02 19:22:56 +00:00
edi
58060dda09 use documented way of updating (#344) 2023-01-31 22:19:01 +00:00
Thomas Schönauer
8cfc8d66be v10.3.1 patch (#342) 2023-01-30 21:24:06 +00:00
edi
9dcc8fdd0d (neo)vim: topgrade should only invoke plugin managers not plugins (#341)
* fix upgrade order of (n)vim plugins

* treesitter should use the synchronous cmd

* add lazy pkg manager for neovim

* fix lazy cmd

* change calls

* add autocmd, remove ts and coc

* fix vimscript err invalid range

---------

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2023-01-30 18:42:13 +00:00
Thomas Schönauer
828477b255 Update README.md 2023-01-30 18:41:48 +00:00
arctic-penguin
4eae1fedf7 fix ignored config display_preamble = false (#340)
Bug was introduced in f1e4009. Fixes #337.
2023-01-30 18:41:00 +00:00
Thomas Schönauer
1051e4cf47 AM fix + version bump (#335) 2023-01-29 21:53:26 +00:00
Thomas Schönauer
80a95cb404 Clippy (#331) 2023-01-29 19:31:37 +00:00
Thomas Schönauer
ab630cfbc6 v10.2.5 release (#330)
* Don't show desktop notification on error (if `skip_notify = true`) (#275)

* Use ─ (U+2500) to draw borders (#282)

* Adds Pclinuxos support (#283)

* Add Devkitpro Pacman support (#291)

* Added support for Neovim package manager lazy.nvim (#293)

* Added support for lazy.nvim

From https://github.com/folke/lazy.nvim
Authored-by: Jacob Lane Ledbetter <jledbetter460@gmail.com>

* Make garuda-update update AUR packages by default (#296)

* fix(#298): Don't throw error if no Helm repository found (#305)

* Skip .NET when `dotnet tool list` is not successful (#302)

* feat(pacstall): add `-y` flag variant (#312)

* Add openSUSE MicroOS support (#315)

* Adds notify-send timeout of 10s (#318)

* Don't run yum when rpm-ostree is available (#313)

* don't run yum when rpm-ostree is available

* Clippy fix

* rpm-ostree: set default value to true

* Fixes if loop error

* Fixes gem update --system requires sudo now (#317)

* Fixes gem update --system requires sudo now

* rubygem: Adds arg -EH to sudo

* Use fixed nala path instead of which(nala) (#314)

* Adds notify-send bug warning when topgrade is run (#324)

* Adds notify-send bug warning when topgrade is run

* fix typo + clippy

* notify-send warning respects skip_notify flag

* nix: Adds additional arguments support (#325)

* Adds pip-review and pipupgrade support (#316)

* Adds pip-review and pipupgrade support

* Python: fixes pip_review and pipupgrade

* v10.2.5 patch (#329)

* WSL: Adds new wsl --update flags (#327)

* wsl: Updates available flags

* Clippy fix

* Add WslUpdate runner

* wsl: Code Typo

* wsl: Code Typos

* wsl: Code Typos

* wsl: Code Typo

* Adds AM Package Manager (#328)

* Adds AM Package Manager

* Clippy fixes

* Cargo fmt

* Moves am to linux only in main file

---------

Co-authored-by: Guilherme Silva <626206+guihkx@users.noreply.github.com>
Co-authored-by: Gabriel Augendre <gabriel@augendre.info>
Co-authored-by: Cat Core <34719527+arthurbambou@users.noreply.github.com>
Co-authored-by: Hugo Haas <hugoh@hugoh.net>
Co-authored-by: Baptiste <32563450+BapRx@users.noreply.github.com>
Co-authored-by: bbx0 <39773919+bbx0@users.noreply.github.com>
Co-authored-by: Sourajyoti Basak <wiz28@protonmail.com>
2023-01-29 19:19:27 +00:00
edi
c13e14080c Add Lazy, a Neovim plugin manager (#326)
* fix upgrade order of (n)vim plugins

* treesitter should use the synchronous cmd

* add lazy pkg manager for neovim

* fix lazy cmd

---------

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2023-01-29 18:49:56 +00:00
edi
4abbee99cc fix upgrade order of (n)vim plugins (#322)
* fix upgrade order of (n)vim plugins

* treesitter should use the synchronous cmd

---------

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2023-01-27 21:41:48 +00:00
Giovanni Merlino
45d935eda3 Fix missing separator for Pkgin (pkgsrc) (#307)
* Fix missing separator for Pkgin (pkgsrc)

* Fix whitespace (giving issues with cargo fmt?)

---------

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2023-01-27 21:34:27 +00:00
pwygab
b4c5efde50 Fix small typo in warning when notify-send fails (#319)
Fix small typo
2023-01-27 20:52:20 +00:00
Roey Darwish Dror
cba9dc1c2c Fix windows build (#303) 2023-01-09 08:50:21 +01:00
dependabot[bot]
938647123c Bump tokio from 1.8.5 to 1.18.4 (#301) 2023-01-06 23:13:01 +00:00
Jacob Lane Ledbetter
9f24f6474e Add dnf config to config example (#292) 2022-12-30 22:52:04 +00:00
Thomas Schönauer
814e39644c fixes dotnet update + version bump 10.2.4 (#274) 2022-12-18 15:37:10 +00:00
Thomas Schönauer
eb51be0732 10.2.3 release (#272) 2022-12-18 14:20:00 +00:00
Thomas Schönauer
56a717dcc6 Fixes dotnet if dotnet tool is not available (#229)
* Fixes dotnet if dotnet tool si not available

* dotnet: multi-lang support

* Fixes dotnet for non-english terminals
2022-12-18 14:12:36 +00:00
Thomas Schönauer
ee353ccb66 adds fish_update_completions to fish step (#270) 2022-12-18 14:11:36 +00:00
Thomas Schönauer
33cea0e5b6 10.2.3 release (#271)
10.2.3
2022-12-18 14:07:31 +00:00
Thomas Schönauer
78a491a976 Fixes rubygems on .deb distros (#268)
Fixes rubygem on systems with the .deb ruby package
2022-12-15 20:27:27 +00:00
Thomas Schönauer
9553be04e4 Fixes vcpkg when installed as root (#266) 2022-12-15 11:39:25 +00:00
Thomas Schönauer
81928f55a2 Fix notify not available (#257) 2022-12-15 11:34:18 +00:00
Mark Nefedov
4e56bf07f3 Add options to disable Yarn and Pnpm individually. (#260)
* Add options to disable Yarn and Pnpm individualy.

* cargo fmt

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-12-14 21:42:48 +00:00
sandal
9f424f03c3 Added a step for fetching and building treesitter grammars for helix (#263) 2022-12-14 08:12:39 +00:00
Thomas Kosiewski
1e14b3bf28 Add helm (#255) (#256)
* Add `helm` (#255)

Signed-off-by: Thomas Kosiewski <thoma471@googlemail.com>

* Sorted steps alphabetically

Signed-off-by: Thomas Kosiewski <thoma471@googlemail.com>

Signed-off-by: Thomas Kosiewski <thoma471@googlemail.com>
2022-12-08 21:47:57 +00:00
Thomas Schönauer
51e7a31f48 10.2.2 (#253) 2022-12-06 19:48:46 +00:00
Thomas Schönauer
9847fd9d4d Merge branch 'master' into dev 2022-12-06 19:23:45 +00:00
Thomas Schönauer
24ef44291f 10.2.2 version bump (#252) 2022-12-06 19:22:06 +00:00
Julien ITARD
ebb0c5a6d8 Fix RubyGems step (#251)
* Bump tokio from 1.5.1 to 1.8.4 (#245)

Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.5.1 to 1.8.4.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.5.1...tokio-1.8.4)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix RubyGems step

* Fix style

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-06 19:13:07 +00:00
Armel Soro
1dee462175 Fix misleading log message when detecting rbenv (#249) 2022-12-05 17:42:26 +00:00
Armel Soro
dc82b8b766 Fix issue with RubyGems update command (#248) 2022-12-05 13:16:03 +00:00
dependabot[bot]
73888e7669 Bump tokio from 1.5.1 to 1.8.4 (#245)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.5.1 to 1.8.4.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.5.1...tokio-1.8.4)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-30 21:56:52 +00:00
dependabot[bot]
46a010cc8f Bump tokio from 1.5.1 to 1.8.4 (#147)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.5.1 to 1.8.4.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.5.1...tokio-1.8.4)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-30 21:29:39 +00:00
Thomas Schönauer
96e4de4594 10.2.1 release (#244) 2022-11-30 21:08:15 +00:00
Thomas Schönauer
70616b2ec5 Version bump (#237) 2022-11-29 15:17:20 +00:00
Thomas Schönauer
22ab07d88e Fixes paru/yay -Pw return code error (#228) 2022-11-29 06:49:26 +00:00
Guilherme Silva
70045fca29 CI: Force color support for Rustfmt (#230)
Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-27 00:21:29 +01:00
Marcin Puc
f6ec6c76db Add shell completion and manpage generation (#233) 2022-11-26 19:42:35 +00:00
Jason Stelzer
37b900c56a Add garuda-update (#227) 2022-11-26 19:38:18 +00:00
Guilherme Silva
e26ec4d9e0 Fix clippy warning for DragonFly BSD (#231) 2022-11-26 17:52:14 +00:00
Rebecca Turner
b31778bdd8 Add Sudo type (#221)
* Create `Sudo` type and `SudoKind` enum

* Fix build

* reformat

* Fix choco on windows

* Fix linux

* Fix linux more

* more fix stuff hehe hoho hahaha

* more fix stuff hehe hoho hahaha

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-25 22:19:32 +00:00
Thomas Schönauer
526c4c9a58 Fixes typo 2022-11-25 18:44:36 +00:00
Julien ITARD
3c1dda0c39 Add RubyGems update (#217) 2022-11-24 19:21:03 +00:00
Ruben Molina
25c5057171 Add support for juliaup (#208)
* Add support for juliaup

* Update config.rs

* Change the position for Juliaup Step.

* Update generic.rs
2022-11-24 19:17:58 +00:00
Rebecca Turner
e456155562 Add pre_sudo option (#219)
* Add `pre_sudo` option
2022-11-24 19:15:43 +00:00
Guilherme Silva
f2c7e4848e CI: Install only necessary components (#218)
* CI: Install only necessary components
2022-11-24 19:15:13 +00:00
Guilherme Silva
b4407963ad Fix compilation on DragonFly BSD (#210) 2022-11-23 15:24:58 +00:00
Thomas Schönauer
85a4691229 10.2.0 dependency + version bump (#209) 2022-11-23 15:24:58 +00:00
Rebecca Turner
8e9c3cc56a Add gup (#203) 2022-11-23 15:24:58 +00:00
Thomas Schönauer
7cdaefe3b0 --yes flag support on freebsd (#198)
* Adds freebsd yes flag support

* Fixes freebsd update functions

* Missing semicolon

* Adds Step dependency to freebsd.rs

* Change freebsd to status_checked
2022-11-23 15:24:58 +00:00
Thomas Schönauer
aedb25cde6 Npm rework (#199) 2022-11-23 15:24:58 +00:00
Rebecca Turner
582bc737cb Fix a bug with status_checked_with_codes (#202) 2022-11-23 15:24:58 +00:00
Thomas Schönauer
c4091584c3 Fixes NPM failure under sudo (#197)
Fixes npm under sudo
2022-11-23 15:24:58 +00:00
Guilherme Silva
22ed1ef50a CI: Add NetBSD target (#180)
* Remove the `sys-info` crate

It offers much more features than we currently use.

Additionally, it was preventing me to cross-compile for NetBSD.

Since we were just using the `hostname()` function from the crate,
I went ahead and stole it.

* Add NetBSD target

* Fix FreeBSD clippy warnings
2022-11-23 15:24:58 +00:00
Rebecca Turner
41e2321b93 Use tracing (#174) 2022-11-23 15:24:58 +00:00
Rebecca Turner
d8add139e1 Add Treesitter support to Vim upgrade (#184)
* Add `:TSUpdate` to Vim upgrade

* Reformat `freebsd.rs`

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-23 15:24:58 +00:00
Thomas Schönauer
04a8d960a9 Revert " Fix unattended package upgrades on FreeBSD" (#188)
Revert " Fix unattended package upgrades on FreeBSD (#181)"

This reverts commit a0ad83a58b.
2022-11-23 15:24:58 +00:00
Yonas Yanfa
2c6a8f73fa Fix unattended package upgrades on FreeBSD (#181)
* Fix unattended package upgrades on FreeBSD

* Fix unattended package upgrades on FreeBSD

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-23 15:24:58 +00:00
Rebecca Turner
71883d7164 Fix tmux panic (#165)
Fix `tmux` sessions

This will create a new session named `topgrade`, `topgrade-1`,
`topgrade-2`, using the first nonexistent session name it finds. That
session will have a window in it named `topgrade` in which `topgrade` is
run. If `topgrade --tmux` is being run from within tmux, it won't attach
to the new tmux session. If the user is not currently in tmux, it will
attach to the newly-created session.

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-23 15:24:58 +00:00
Rebecca Turner
d4fe748814 Run fisher if fish -c 'type -t fisher' is OK (#172) 2022-11-23 15:24:58 +00:00
LeSnake04
369d923532 Added configuration for cargo-deb and cargo-generate-rpm (#178) 2022-11-23 15:24:58 +00:00
Guilherme Silva
6be4a4a48d CI improvements + Android and FreeBSD targets (#177)
* Bump minimum Rust version to 1.60

As required by the `time` crate (`notify-rust` > `mac-notification-sys` > `time`).

* Simplify CI

Changes:

- Bump `actions/checkout` to v3, fixing a bunch of warnings.
- Replace unmaintained `actions-rs/cargo` by `dtolnay/rust-toolchain`.
- Run Rustfmt only once.
- Add support for cached dependencies (via `Swatinem/rust-cache`).

* Add Android target

Use the awesome `cross` tool for cross-compiling!

* Add FreeBSD target
2022-11-23 15:24:58 +00:00
Guilherme Silva
7442ddd386 Further clippy fixes (#176) 2022-11-23 15:24:58 +00:00
Guilherme Silva
761ffac127 Fix compilation on FreeBSD (#175) 2022-11-23 15:24:58 +00:00
Guilherme Silva
5ca1dc3703 Fix compilation on Android (#166)
Co-authored-by: guihkx <guihkx@users.noreply.github.com>
2022-11-23 15:24:58 +00:00
Rebecca Turner
a18c6e815c Fix lack of separators for pnpm/npm/yarn (#170) 2022-11-23 15:24:58 +00:00
Rebecca Turner
022afab1ca Print errors when steps fail (#171) 2022-11-23 15:24:58 +00:00
Rebecca Turner
2cbb7db66d Use color_eyre (#173) 2022-11-23 15:24:58 +00:00
Rebecca Turner
e84173be8f Add CommandExt trait (#146)
* Color CI output

* Improve `CommandExt`

* Add comments explaining `#[allow]`s

* Remove useless `dead_code` annotation

* Improve error messages

* Print errors when running a shell errors

* fixup! Remove useless `dead_code` annotation
2022-11-23 15:24:58 +00:00
Thomas Schönauer
bd34a3bcd4 Revert "10.2.0 release " (#215)
Revert "10.2.0 release  (#213)"

This reverts commit 13076fcef6.
2022-11-23 16:23:00 +01:00
Thomas Schönauer
13076fcef6 10.2.0 release (#213) 2022-11-23 15:18:09 +00:00
0xMRTT
6f48017761 Create SECURITY.md (#142) 2022-11-16 19:40:17 +01:00
Marcin Puc
7fb07879bb Add repology badge (#191) 2022-11-16 19:39:36 +01:00
Pascal Jufer
ecbaf52156 Enhance the README (#186) 2022-11-15 08:41:35 +01:00
Thomas Schönauer
6a6a84b0c5 Update update_homebrew.yml 2022-11-06 15:28:57 +00:00
Thomas Schönauer
3486200b2c Update update_homebrew.yml 2022-11-06 15:08:35 +00:00
Thomas Schönauer
f6b3a8fdca Update update_homebrew.yml 2022-11-06 15:07:55 +00:00
Thomas Schönauer
058a6fd9c9 Update update_homebrew.yml 2022-11-06 15:01:20 +00:00
Thomas Schönauer
e1783e3af8 Create update_homebrew.yml 2022-11-06 14:58:47 +00:00
Thomas Schönauer
e161d3cd3c 10.1.2 (#162)
* Closes #150 please disable distrobox by default (#151)

* Check if distrobox exists before running step

* Improve help prompt value names (#153)

* 159 self update error message with standalone versions (#161)

* Rename back to topgrade

* Bugfix Version bump

* Changes reference to topgrade-rs in self-update

* Fixes distrobox errors (#160)

* Rename back to topgrade

* Bugfix Version bump

* Check if distrobox exists before running step

* Fixed sitrobox and version bump

* Version bump to 10.1.2

Co-authored-by: Marcin Puc <tranzystorek.io@protonmail.com>
2022-11-06 13:54:38 +00:00
Marcin Puc
318f935b43 Add info about Void Linux to README (#154) 2022-11-05 14:43:09 +00:00
Thomas Schönauer
3dc245245d bugfix Closing #150 (#151) (#152)
Closes #150 please disable distrobox by default (#151)

* Check if distrobox exists before running step
2022-11-05 10:50:55 +00:00
Thomas Schönauer
9de111aa0f Merge of bug-fixes with masters the second (#149) 2022-11-05 09:17:51 +00:00
Thomas Schönauer
18951c8447 Merge branch 'master' into bug-fixes 2022-11-05 09:17:28 +00:00
Thomas Schönauer
b6e50a38af Revert "Bug fixes" (#148)
Revert "Bug fixes (#145)"

This reverts commit 8acdfc8d1c.
2022-11-05 09:15:52 +00:00
Rebecca Turner
8acdfc8d1c Bug fixes (#145) 2022-11-05 09:11:31 +00:00
Dylan M. Taylor
a6da5181f2 Fix for gcloud snap issue (#144) 2022-11-04 13:48:05 +00:00
0xMRTT
60ff087048 feat: add coc (#140) 2022-11-04 12:08:23 +00:00
Thomas Schönauer
3ebaac3a1d Fix windows clippy errors (#135)
* Changes windows get_wsl_distribution argument

* changes in get_wsl_distributions

* changes in run_wsl_topgrade due to clippy errors

* Resolves needless borrow
2022-11-03 21:43:45 +00:00
Thomas Schönauer
e4f8488837 Revert "Get windows to finish clippy without errors" (#134)
Revert "Get windows to finish clippy without errors (#133)"

This reverts commit 16953409fd.
2022-11-03 19:49:01 +00:00
Thomas Schönauer
d8748b004b Update check-and-lint.yaml 2022-11-03 19:40:24 +00:00
Thomas Schönauer
2a11df40ee Update check-and-lint.yaml 2022-11-03 19:40:02 +00:00
Thomas Schönauer
16953409fd Get windows to finish clippy without errors (#133)
* Changes windows get_wsl_distribution argument

* changes in get_wsl_distributions

* changes in run_wsl_topgrade due to clippy errors
2022-11-03 19:34:27 +00:00
Thomas Schönauer
c85adb8980 Update check-and-lint.yaml 2022-11-03 19:19:00 +00:00
Thomas Schönauer
0f0cbc1453 Update check-and-lint.yaml 2022-11-03 19:18:45 +00:00
Thomas Schönauer
91554cac56 GitHub action cleanup2 (#132)
* Changed clippy args for PR pipeline

* changes crates-publish toolchain version to stable

* Enhanced clippy for PRs

* Fixes typo
2022-11-03 19:09:44 +00:00
Thomas Schönauer
7256aaffc8 Resolve clippy errors (#131)
* Resolves clippy errors

* Fixes clippy errors

* Changes get_wsl_distributions arguments from pointer to value
2022-11-03 19:04:06 +00:00
Thomas Schönauer
66e0b94e85 Resolve clippy errors (#130)
* Resolves clippy errors

* Fixes clippy errors
2022-11-03 18:54:40 +00:00
Thomas Schönauer
4dcb5a214b GitHub action cleanups (#129)
* Changed clippy args for PR pipeline

* changes crates-publish toolchain version to stable

* Enhanced clippy for PRs
2022-11-03 18:53:37 +00:00
Thomas Schönauer
8731fd2b3f Resolves clippy errors (#128) 2022-11-03 18:29:22 +00:00
Thomas Schönauer
9233846479 Update release-cross.yml 2022-11-03 17:11:47 +00:00
Thomas Schönauer
94bdb8c3fd Update release.yml 2022-11-03 17:11:28 +00:00
Thomas Schönauer
632fcb5b77 Changes version requirements to latest path of minor version (#127) 2022-11-03 17:05:09 +00:00
Rebecca Turner
55ba2d30c1 Quote arguments when executing in a shell (#118)
* Quote arguments when executing in a shell

Fixes #107

* Parse quotes in `tmux_arguments`

This makes it possible to encode spaces in arguments. Maybe the config
value should be an array instead?

* Print error causes

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-03 16:46:43 +00:00
0xMRTT
ff66611ec0 fix: update debian os release (8->11) (#123) 2022-11-03 15:57:16 +01:00
pan93412
edc3dd6b0b refactor(ctrlc): Remove reduntant lazy_static (#109) 2022-11-03 15:57:16 +01:00
pan93412
623a11cf21 refactor!(steps/node): make PNPM a separated step (#114) 2022-11-03 15:57:16 +01:00
pan93412
7a83f38ca8 fix(steps/node): Only run global upgrade on Yarn 1.x (#112) 2022-11-03 15:57:16 +01:00
Thomas Schönauer
9a19b547c6 Revert clap version bump (#111)
* Update README.md

* Update release-cross.yml

* Update release.yml

* style(self_update): Run cargo fmt (#108)

The commit 9105a8aac is not formatted, which breaks the CI check.

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>

* Clap dependencie change

* Revert clap changes

Co-authored-by: pan93412 <pan93412@gmail.com>
2022-11-03 15:57:16 +01:00
0xMRTT
aae5c3b631 fix: link in readme (#120) 2022-11-03 09:35:34 +00:00
0xMRTT
3be75bf399 feat: add issue config (#122) 2022-11-03 09:35:12 +00:00
pan93412
a7c2262537 refactor: Run cargo clippy --fix (#113) 2022-11-02 20:26:20 +00:00
Thomas Schönauer
16a7d5f00b Cleanup CI/CD pipeline (#115) 2022-11-02 16:25:54 +00:00
pan93412
be0984cdf3 style(self_update): Run cargo fmt (#108)
The commit 9105a8aac is not formatted, which breaks the CI check.

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
2022-11-02 14:55:59 +00:00
Thomas Schönauer
fb13543e44 Update release.yml 2022-11-02 14:54:52 +00:00
Thomas Schönauer
c406fe2775 Update release-cross.yml 2022-11-02 14:53:49 +00:00
Thomas Schönauer
ce0c0c4314 Update README.md 2022-11-02 12:17:59 +01:00
129 changed files with 16009 additions and 4758 deletions

View File

@@ -2,32 +2,106 @@
name: Bug report
about: Topgrade is misbehaving
title: ''
labels: ''
labels: 'C-bug'
assignees: ''
---
<!-- If you're here to report about a "No asset found" error, please make sure that an hour has been passed since the last release was made. -->
<!--
Thanks for taking the time to fill out this bug report!
Please make sure to
[search for existing issues](https://github.com/topgrade-rs/topgrade/issues)
before filing a new one!
## What did you expect to happen?
Questions labeled with `Optional` can be skipped.
If you're here to report about a "No asset found" error, please make sure that
an hour has been passed since the last release was made.
-->
## What actually happened?
## Checklist
- [ ] I have searched the issue tracker for relevant or duplicate issues.
## Additional Details
- Which operating system or Linux distribution are you using?
- How did you install Topgrade?
- Which version are you running? <!-- Check with `topgrade -V` -->
## Erroneous Behavior
<!--
Run `topgrade --dry-run` to see which commands Topgrade is running.
If the command seems wrong and you know why please tell us so.
If the command seems fine try to run it yourself and tell us if you got a different result from Topgrade.
What actually happened?
-->
## Expected Behavior
<!--
Describe the expected behavior.
-->
## Steps to reproduce
<!--
A minimal example to reproduce the issue.
-->
## Possible Cause (Optional)
<!--
If you know the possible cause of the issue, please tell us.
-->
## Problem persists without calling from topgrade
<!--
Execute the erroneous command directly to see if the problem persists.
-->
- [ ] Yes
- [ ] No
## Ran through `Remote Execution`
<!--
Did you run topgrade through `Remote Execution`?
-->
- [ ] Yes
- [ ] No
If yes, does the issue still occur when you run topgrade directly in your
remote host?
- [ ] Yes
- [ ] No
## Configuration file (Optional)
<!--
Paste your configuration file inside the code block if you think this issue is
related to configuration.
-->
```toml
```
## Additional Details
- Operation System/Version
<!-- For example, Fedora Linux 38 -->
- Installation
<!--
How did you install topgrade: build from repo / crates.io (cargo install topgrade)
/ package manager (which one) / other (describe)
-->
- Topgrade version (`topgrade -V`)
## Verbose Output (`topgrade -v`)
<!--
Paste the verbose output into the pre-tags
-->
<details>
<!-- Paste the output of the problematic command with `-v` into the pre-tags -->
<pre>
</pre>

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/topgrade-rs/topgrade/discussions
about: Please ask and answer questions here.

View File

@@ -1,21 +1,23 @@
---
name: Feature request
about: Can you please support...?
name: General feature request
about: Suggest a general feature, or feature within an already existing step
title: ''
labels: ''
labels: C-feature request
assignees: ''
---
## I want to suggest a new step
### Which tool is this about? Where is its repository?
### Which operating systems are supported by this tool?
### What should Topgrade do to figure out if the tool needs to be invoked?
### Which exact commands should Topgrade run?
## Checklist
- [ ] I have searched the issue tracker for relevant or duplicate issues.
## I want to suggest some general feature
Topgrade should...
## More information
<!-- Assuming that someone else implements the feature,
please state if you know how to test it from a side branch of Topgrade. -->
- [ ] I am able and willing to implement this feature myself

29
.github/ISSUE_TEMPLATE/step_request.md vendored Normal file
View File

@@ -0,0 +1,29 @@
---
name: New step request
about: Suggest a new step/package manager to update
title: ''
labels: C-feature request, request step
assignees: ''
---
## Checklist
- [ ] I have searched the issue tracker for relevant or duplicate issues.
## I want to suggest a new step
* Which tool is this about? Where is its repository?
* Which operating systems are supported by this tool?
* What should Topgrade do to figure out if the tool needs to be invoked?
* Which exact commands should Topgrade run?
* Does it have a `--dry-run` option? i.e., print what should be done and exit
* Does it need the user to confirm the execution? And does it provide a `--yes`
option to skip this?
## More information
<!-- Assuming that someone else implements the step,
please state if you know how to test it from a side branch of Topgrade. -->
- [ ] I am able and willing to implement this step myself

View File

@@ -1,12 +1,18 @@
## Standards checklist:
## What does this PR do
- [ ] The PR title is descriptive.
- [ ] The code compiles (`cargo build`)
- [ ] The code passes rustfmt (`cargo fmt`)
- [ ] The code passes clippy (`cargo clippy`)
- [ ] The code passes tests (`cargo test`)
## Standards checklist
- [ ] The PR title is descriptive
- [ ] I have read `CONTRIBUTING.md`
- [ ] *Optional:* I have tested the code myself
- [ ] I also tested that Topgrade skips the step where needed
- [ ] If this PR introduces new user-facing messages they are translated
## For new steps
- [ ] *Optional:* Topgrade skips this step where needed
- [ ] *Optional:* The `--dry-run` option works with this step
- [ ] *Optional:* The `--yes` option works with this step if it is supported by
the underlying command
If you developed a feature or a bug fix for someone else and you do not have the
means to test it, please tag this person here.

View File

@@ -1,24 +0,0 @@
name: Cargo Build & Test
on:
push:
pull_request:
env:
CARGO_TERM_COLOR: always
jobs:
build_and_test:
name: Rust project - latest
runs-on: ubuntu-latest
strategy:
matrix:
toolchain:
- stable
- beta
- nightly
steps:
- uses: actions/checkout@v3
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cargo build --verbose
- run: cargo test --verbose

View File

@@ -1,55 +0,0 @@
on:
pull_request:
push:
branches:
- main
name: Check and Lint
jobs:
check:
name: Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: check
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: rustup component add rustfmt
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: clippy
override: true
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
name: Clippy Output

View File

@@ -0,0 +1,27 @@
name: Check config file creation if not exists
on:
pull_request:
env:
CARGO_TERM_COLOR: always
permissions:
contents: read
jobs:
TestConfig:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- run: |
CONFIG_PATH=~/.config/topgrade.toml;
if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi
cargo build;
TOPGRADE_SKIP_BRKC_NOTIFY=true ./target/debug/topgrade --dry-run --only system;
stat $CONFIG_PATH;

27
.github/workflows/check_i18n.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
on:
pull_request:
push:
branches:
- main
name: Check i18n
permissions:
contents: read
jobs:
check_locale:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Install checker
# Build it with the dev profile as this is faster and the checker still works
run: |
cargo install --git https://github.com/topgrade-rs/topgrade_i18n_locale_checker --profile dev
- name: Run the checker
run: topgrade_i18n_locale_checker --locale-file ./locales/app.yml --rust-src-to-check ./src

View File

@@ -0,0 +1,37 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Check Security Vulnerability
on:
pull_request:
push:
branches:
- main
permissions:
contents: read
jobs:
lint:
name: DevSkim
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Run DevSkim scanner
uses: microsoft/DevSkim-Action@4b5047945a44163b94642a1cecc0d93a3f428cc6 # v1.0.16
- name: Upload DevSkim scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3
with:
sarif_file: devskim-results.sarif

165
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,165 @@
on:
pull_request:
push:
branches:
- main
name: CI
env:
CROSS_VER: '0.2.5'
CARGO_NET_RETRY: 3
permissions:
contents: read
defaults:
run:
shell: bash
jobs:
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Run cargo fmt
env:
TERM: xterm-256color
run: |
rustup component add rustfmt
cargo fmt --all -- --check
custom-checks:
name: Custom checks
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Check if `Step` enum is sorted
run: |
ENUM_NAME="Step"
FILE="src/step.rs"
awk "/enum $ENUM_NAME/,/}/" "$FILE" | \
grep -E '^\s*[A-Za-z_][A-Za-z0-9_]*\s*,?$' | \
sed 's/[, ]//g' > original.txt
sort original.txt > sorted.txt
diff original.txt sorted.txt
- name: Check if `Step::run()`'s match is sorted
run: |
FILE="src/step.rs"
awk '/[[:alpha:]] =>/{print $1}' $FILE > original.txt
sort original.txt > sorted.txt
diff original.txt sorted.txt
- name: Check if `default_steps` contains every step
run: |
# Extract all variants from enum Step
all_variants=$(sed -n '/^pub enum Step {/,/^}/p' src/step.rs | grep -Po '^\s*\K[A-Z][A-Za-z0-9_]*' | sort)
# Extract variants used inside default_steps
used_variants=$(sed -n '/^pub(crate) fn default_steps()/,/^}/p' src/step.rs | \
grep -Po '\b[A-Z][A-Za-z0-9_]*\b' | \
grep -Fx -f <(echo "$all_variants") | \
sort)
# Check for missing variants
missing=$(comm -23 <(echo "$all_variants") <(echo "$used_variants"))
if [[ -z "$missing" ]]; then
echo "All variants are used."
else
echo "Missing variants:"
echo "$missing"
exit 1
fi
# Check for duplicates
duplicates=$(echo "$used_variants" | uniq -c | awk '$1 > 1 {print $2}')
if [[ -z "$duplicates" ]]; then
echo "No duplicates found."
else
echo "Duplicates found:"
echo "$duplicates"
# We allow duplicates, but lets keep this check for potential future usefulness
# exit 1
fi
main:
needs: [ fmt, custom-checks ]
name: ${{ matrix.target_name }} (check, clippy)
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-linux-android
target_name: Android
use_cross: true
os: ubuntu-latest
- target: x86_64-unknown-freebsd
target_name: FreeBSD
use_cross: true
os: ubuntu-latest
- target: x86_64-unknown-linux-gnu
target_name: Linux
os: ubuntu-latest
- target: x86_64-apple-darwin
target_name: macOS-x86_64
os: macos-15-intel
- target: aarch64-apple-darwin
target_name: macOS-aarch64
os: macos-latest
- target: x86_64-unknown-netbsd
target_name: NetBSD
use_cross: true
os: ubuntu-latest
- target: x86_64-pc-windows-msvc
target_name: Windows
os: windows-latest
env:
cargo_cmd: ${{ matrix.use_cross == true && 'cross' || 'cargo' }}
matrix_target: ${{ matrix.target }}
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Setup Rust Cache
uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1
with:
prefix-key: ${{ matrix.target }}
- name: Setup cross
if: matrix.use_cross == true
run: |
curl -fL --retry 3 "https://github.com/cross-rs/cross/releases/download/v${CROSS_VER}/cross-x86_64-unknown-linux-musl.tar.gz" | tar vxz -C /usr/local/bin
- name: Run cargo/cross check
run: |
"${cargo_cmd}" check --locked --target "${matrix_target}"
- name: Run cargo/cross clippy
run: |
rustup component add clippy
"${cargo_cmd}" clippy --locked --target "${matrix_target}" --all-features -- -D warnings
- name: Run cargo test
# ONLY run test with cargo
if: matrix.use_cross == false
run: |
cargo test --locked --target "${matrix_target}"

View File

@@ -1,36 +0,0 @@
on:
release:
types: [published, edited]
name: Check SemVer compliance and publish on release
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2022-08-03
override: true
semver:
runs-on: ubuntu-latest
steps:
- uses: actions-rs/cargo@v1
with:
command: install
args: --git https://github.com/rust-lang/rust-semverver
- run: eval "current_version=$(grep -e '^version = .*$' Cargo.toml | cut -d ' ' -f 3)"
- run: cargo semver | tee semver_out
- run: (head -n 1 semver_out | grep "\-> $current_version") || (echo "versioning mismatch" && return 1)
publish:
runs-on: ubuntu-latest
steps:
- uses: katyo/publish-crates@v1
with:
dry-run: true
check-repo: ${{ github.event_name == 'push' }}
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
ignore-unpublished-changes: true

View File

@@ -0,0 +1,303 @@
name: Publish release files for CD native and non-cd-native environments
on:
repository_dispatch:
types: [ release-created ]
permissions:
# Write permissions to call the repository dispatch
contents: write
defaults:
run:
shell: bash
jobs:
# Publish release files for CD native environments
native_build:
permissions:
# Use to sign the release artifacts
id-token: write
# Used to upload release artifacts
contents: write
# Used to generate artifact attestations
attestations: write
strategy:
fail-fast: false
matrix:
# Use the Ubuntu 22.04 image to link with a low version of glibc
#
# https://github.com/topgrade-rs/topgrade/issues/1095
platform: [ ubuntu-22.04, macos-latest, macos-15-intel, windows-latest ]
runs-on: ${{ matrix.platform }}
env:
tag: ${{ github.event.client_payload.tag }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Install needed components
run: |
rustup component add rustfmt
rustup component add clippy
- name: Install cargo-deb
run: cargo install cargo-deb
if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
shell: bash
- name: Check format
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --all-targets --locked -- -D warnings
- name: Run clippy (All features)
run: cargo clippy --all-targets --locked --all-features -- -D warnings
- name: Run tests
run: cargo test
# Used `https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/release.yml`
# as a reference.
- name: Build debug binary to create release assets
shell: bash
run: |
cargo build --all-features
bin="target/debug/topgrade"
echo "BIN=$bin" >> $GITHUB_ENV
- name: Create deployment directory
shell: bash
run: |
dir=deployment/deb
mkdir -p "$dir"
echo "DEPLOY_DIR=$dir" >> $GITHUB_ENV
- name: Generate man page and shell completions
shell: bash
run: |
"$BIN" --gen-manpage > "$DEPLOY_DIR/topgrade.1"
"$BIN" --gen-completion bash > "$DEPLOY_DIR/topgrade.bash"
"$BIN" --gen-completion fish > "$DEPLOY_DIR/topgrade.fish"
"$BIN" --gen-completion zsh > "$DEPLOY_DIR/_topgrade"
- name: Build in Release profile with all features enabled
run: cargo build --release --all-features
- name: Rename Release (Unix)
run: |
cargo install default-target
mkdir -p assets
FILENAME=topgrade-${tag}-$(default-target)
mv target/release/topgrade assets
cd assets
tar --format=ustar -czf $FILENAME.tar.gz topgrade
rm topgrade
ls .
if: ${{ matrix.platform != 'windows-latest' }}
shell: bash
- name: Build Debian-based system binary and create package
# First remove the binary built by previous steps
# because we don't want the auto-update feature,
# then build the new binary without auto-updating.
run: |
rm -rf target/release
cargo build --release
cargo deb --no-build --no-strip
if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
shell: bash
- name: Move Debian-based system package
run: |
mkdir -p assets
mv target/debian/*.deb assets
if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
shell: bash
- name: Rename Release (Windows)
run: |
cargo install default-target
mkdir assets
FILENAME=topgrade-${tag}-$(default-target)
mv target/release/topgrade.exe assets/topgrade.exe
cd assets
powershell Compress-Archive -Path * -Destination ${FILENAME}.zip
rm topgrade.exe
ls .
if: ${{ matrix.platform == 'windows-latest' }}
shell: bash
- name: Upload assets
run: |
gh release upload "${tag}" assets/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate artifact attestations
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: assets/*
# Publish release files for non-CD-native environments
cross_build:
permissions:
# Use to sign the release artifacts
id-token: write
# Used to upload release artifacts
contents: write
# Used to generate artifact attestations
attestations: write
strategy:
fail-fast: false
matrix:
target:
[
"aarch64-unknown-linux-gnu",
"armv7-unknown-linux-gnueabihf",
"x86_64-unknown-linux-musl",
"aarch64-unknown-linux-musl",
"x86_64-unknown-freebsd",
]
# Run this one on an older version as well, to limit glibc to 2.34 instead of 2.39.
# Even though this is cross-compiled, it links to the libc6-<arch>-cross installed on the host
# (see the apt-get install calls below)
runs-on: ubuntu-22.04
env:
matrix_target: ${{ matrix.target }}
tag: ${{ github.event.client_payload.tag }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Install needed components
run: |
rustup component add rustfmt
rustup component add clippy
- name: Install cargo-deb cross compilation dependencies
run: sudo apt-get install libc6-arm64-cross libgcc-s1-arm64-cross
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
shell: bash
- name: Install cargo-deb cross compilation dependencies for armv7
run: sudo apt-get install libc6-armhf-cross libgcc-s1-armhf-cross
if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }}
shell: bash
- name: Install cargo-deb
run: cargo install cargo-deb
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
shell: bash
- name: install targets
run: rustup target add "${matrix_target}"
- name: install cross
# Install from source to fix `ld: cannot find -lgeom` for freebsd build
run: cargo +stable install --git https://github.com/cross-rs/cross cross
- name: Run clippy
run: cross clippy --all-targets --locked --target "${matrix_target}" -- -D warnings
- name: Run clippy (All features)
run: cross clippy --locked --all-features --target "${matrix_target}" -- -D warnings
- name: Run tests
run: cross test --target "${matrix_target}"
# Running tests on FreeBSD is impossible; see https://github.com/cross-rs/cross/wiki/FAQ#running-bsd-tests
# Not that this is *NOT* the same as the original issue with `ld: cannot find -lgeom`, but a new issue:
# error: test failed, to rerun pass `--lib`
# Caused by:
# could not execute process `/target/x86_64-unknown-freebsd/debug/deps/topgrade-9b1670d87ca863dd` (never executed)
# Caused by:
# No such file or directory (os error 2)
# TODO: I have not tested this in GHA yet, only locally
if: ${{ matrix.target != 'x86_64-unknown-freebsd' }}
# Used `https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/release.yml`
# as a reference.
- name: Build debug binary to create release assets
shell: bash
run: |
# This build is not using the target arch since this binary is only needed in CI. It needs
# to be the compiled for the runner since it has the run the binary to generate completion
# scripts.
cargo build --all-features
bin="target/debug/topgrade"
echo "BIN=$bin" >> $GITHUB_ENV
- name: Create deployment directory
shell: bash
run: |
dir=deployment/deb
mkdir -p "$dir"
echo "DEPLOY_DIR=$dir" >> $GITHUB_ENV
- name: Generate man page and shell completions
shell: bash
run: |
"$BIN" --gen-manpage > "$DEPLOY_DIR/topgrade.1"
"$BIN" --gen-completion bash > "$DEPLOY_DIR/topgrade.bash"
"$BIN" --gen-completion fish > "$DEPLOY_DIR/topgrade.fish"
"$BIN" --gen-completion zsh > "$DEPLOY_DIR/_topgrade"
- name: Build in Release profile with all features enabled
run: cross build --release --all-features --target "${matrix_target}"
- name: Rename Release
run: |
mkdir -p assets
FILENAME=topgrade-${tag}-${matrix_target}
mv "target/${matrix_target}/release/topgrade" assets
cd assets
tar --format=ustar -czf "$FILENAME.tar.gz" topgrade
rm topgrade
ls .
- name: Build Debian-based system package without autoupdate feature
# First remove the binary built by previous steps
# because we don't want the auto-update feature,
# then build the new binary without auto-updating.
run: |
rm -rf "target/${matrix_target}"
cross build --release --target "${matrix_target}"
cargo deb --target="${matrix_target}" --no-build --no-strip
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
shell: bash
- name: Move Debian-based system package
run: |
mkdir -p assets
mv target/"${matrix_target}"/debian/*.deb assets
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
shell: bash
- name: Upload assets
run:
gh release upload "${tag}" assets/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate artifact attestations
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: assets/*
triggers:
runs-on: ubuntu-latest
needs: [ native_build, cross_build ]
env:
tag: ${{ github.event.client_payload.tag }}
steps:
- name: Trigger workflows
run: |
gh api "repos/${GITHUB_REPOSITORY}/dispatches" \
-f "event_type=release-assets-built" \
-F "client_payload[tag]=${tag}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

25
.github/workflows/dependency-review.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Request,
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
# Once installed, if the workflow run is marked as required,
# PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: 'Dependency Review'
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2

20
.github/workflows/lint_pr.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: 'Lint PR'
on:
pull_request_target: # zizmor: ignore[dangerous-triggers] this is the only way, and we're not running user code
types:
- opened
- edited
- reopened
- synchronize
jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,54 +0,0 @@
name: CD Cross
on:
release:
types: [ created ]
jobs:
build:
strategy:
fail-fast: false
matrix:
target: [ "aarch64-unknown-linux-gnu", "armv7-unknown-linux-gnueabihf", "x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl", "x86_64-unknown-freebsd", ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.57.0
profile: minimal
default: true
override: true
target: ${{ matrix.target }}
components: rustfmt, clippy
- uses: actions-rs/cargo@v1.0.1
name: Run clippy (All features)
with:
command: clippy
use-cross: true
args: --locked --all-features --target ${{matrix.target}}
- uses: actions-rs/cargo@v1.0.1
name: Run tests
with:
command: test
use-cross: true
args: --target ${{matrix.target}}
- uses: actions-rs/cargo@v1.0.1
name: Build
with:
command: build
use-cross: true
args: --release --all-features --target ${{matrix.target}}
- name: Rename Release
run: |
mkdir assets
FILENAME=topgrade-${{github.event.release.tag_name}}-${{matrix.target}}
mv target/${{matrix.target}}/release/topgrade assets
cd assets
tar --format=ustar -czf $FILENAME.tar.gz topgrade
rm topgrade
ls .
- name: Release
uses: softprops/action-gh-release@v1
with:
files: assets/*

View File

@@ -1,28 +0,0 @@
on:
workflow_dispatch:
push:
branches:
- main
name: Release Packaging
jobs:
release:
name: Release Packaging
env:
PROJECT_NAME_UNDERSCORE: topgrade-rs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Release Build
run: cargo build --release
- name: 'Upload Artifact'
uses: actions/upload-artifact@v2
with:
name: ${{ env.PROJECT_NAME_UNDERSCORE }}
path: target/release/${{ env.PROJECT_NAME_UNDERSCORE }}

67
.github/workflows/release-plz.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: Release-plz
on:
push:
branches:
- main
jobs:
# Release unpublished packages.
release-plz-release:
name: Release-plz release
runs-on: ubuntu-latest
environment: crates_io
permissions:
contents: write
id-token: write # For trusted publishing
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
fetch-depth: 0
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
id: release-plz
uses: release-plz/action@d529f731ae3e89610ada96eda34e5c6ba3b12214 # v0.5
with:
command: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Trigger workflows
if: steps.release-plz.outputs.releases_created == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ fromJSON(steps.release-plz.outputs.releases)[0].tag }}
run: |
gh api "repos/${GITHUB_REPOSITORY}/dispatches" \
-f "event_type=release-created" \
-F "client_payload[tag]=${tag}"
# Create a PR with the new versions and changelog, preparing the next release.
release-plz-pr:
name: Release-plz PR
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
concurrency:
group: release-plz-${{ github.ref }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
fetch-depth: 0
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: release-plz/action@d529f731ae3e89610ada96eda34e5c6ba3b12214 # v0.5
with:
command: release-pr
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,63 +0,0 @@
name: CD Native
on:
release:
types: [ created ]
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [ ubuntu-latest, macos-latest, windows-latest ]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.57.0
profile: minimal
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1.0.1
name: Run clippy (All features)
with:
command: clippy
args: --all-targets --locked --all-features
- uses: actions-rs/cargo@v1.0.1
name: Run tests
with:
command: test
- uses: actions-rs/cargo@v1.0.1
name: Build
with:
command: build
args: --release --all-features
- name: Rename Release (Unix)
run: |
cargo install default-target
mkdir assets
FILENAME=topgrade-${{github.event.release.tag_name}}-$(default-target)
mv target/release/topgrade assets
cd assets
tar --format=ustar -czf $FILENAME.tar.gz topgrade
rm topgrade
ls .
if: ${{ matrix.platform != 'windows-latest' }}
shell: bash
- name: Rename Release (Windows)
run: |
cargo install default-target
mkdir assets
FILENAME=topgrade-${{github.event.release.tag_name}}-$(default-target)
mv target/release/topgrade.exe assets/topgrade.exe
cd assets
powershell Compress-Archive -Path * -Destination ${FILENAME}.zip
rm topgrade.exe
ls .
if: ${{ matrix.platform == 'windows-latest' }}
shell: bash
- name: Release
uses: softprops/action-gh-release@v1
with:
files: assets/*

38
.github/workflows/release_to_aur.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Publish to AUR
on:
repository_dispatch:
types: [ release-assets-built ]
permissions:
contents: read
jobs:
aur-publish:
runs-on: ubuntu-latest
steps:
- name: Determine version
id: determine_version
env:
tag: ${{ github.event.client_payload.tag }}
run: |
# tag should be something like "v16.0.4", remove the prefix v here
echo "version=${tag#v}" >> $GITHUB_OUTPUT
- name: Publish source AUR package
uses: varabyte/update-aur-package@572e31b1972fa289a27b1926c06a489eb89c7fd7
with:
version: ${{ steps.determine_version.outputs.version }}
package_name: topgrade
commit_username: "Thomas Schönauer"
commit_email: t.schoenauer@hgs-wt.at
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
- name: Publish binary AUR package
uses: varabyte/update-aur-package@572e31b1972fa289a27b1926c06a489eb89c7fd7
with:
version: ${{ steps.determine_version.outputs.version }}
package_name: topgrade-bin
commit_username: "Thomas Schönauer"
commit_email: t.schoenauer@hgs-wt.at
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}

View File

@@ -0,0 +1,22 @@
name: Publish to Homebrew
on:
repository_dispatch:
types: [ release-created ]
permissions:
contents: read
jobs:
homebrew-publish:
runs-on: ubuntu-latest
steps:
- name: Bump formulae
uses: dawidd6/action-homebrew-bump-formula@3428a0601bba3173ec0bdcc945be23fa27aa4c31 # v5
with:
# Custom GitHub access token with only the 'public_repo' scope enabled
token: ${{secrets.HOMEBREW_ACCESS_TOKEN}}
formula: topgrade
tag: ${{ github.event.client_payload.tag }}
# We cannot use an org because org forks cannot give push access to maintainers, which Homebrew requires.
# org: topgrade-rs

119
.github/workflows/release_to_pypi.yml vendored Normal file
View File

@@ -0,0 +1,119 @@
name: Update PyPi
on:
repository_dispatch:
types: [ release-created ]
permissions:
contents: read
jobs:
# TODO: make linux/windows/macos/sdist a matrix. See how other workflows do it.
linux:
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64, x86, aarch64]
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Build wheels
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.target }}
args: --release --out dist
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: wheels-linux-${{ matrix.target }}
path: dist
windows:
runs-on: windows-latest
strategy:
matrix:
target: [x64, x86]
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Build wheels
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.target }}
args: --release --out dist
- name: Upload wheels
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: wheels-windows-${{ matrix.target }}
path: dist
macos:
runs-on: macos-latest
strategy:
matrix:
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Build wheels
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.target }}
args: --release --out dist
- name: Upload wheels
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: wheels-macos-${{ matrix.target }}
path: dist
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Build sdist
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
command: sdist
args: --out dist
- name: Upload sdist
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: wheels-sdist
path: dist
release:
name: Release
runs-on: ubuntu-latest
needs: [linux, windows, macos, sdist]
permissions:
# Use to sign the release artifacts
id-token: write
# Used to upload release artifacts
contents: write
# Used to generate artifact attestation
attestations: write
steps:
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
- name: Generate artifact attestation
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-path: 'wheels-*/*'
- name: Publish to PyPI
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --non-interactive --skip-existing wheels-*/*

19
.github/workflows/release_to_winget.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Publish to WinGet
on:
repository_dispatch:
types: [ release-created ]
permissions:
contents: read
jobs:
publish:
runs-on: windows-latest
steps:
- uses: vedantmgoyal2009/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f # main
with:
release-tag: ${{ github.event.client_payload.tag }}
identifier: topgrade-rs.topgrade
max-versions-to-keep: 5 # keep only latest 5 versions
token: ${{ secrets.WINGET_TOKEN }}

View File

@@ -1,59 +0,0 @@
name: CD Win/MacOS Native
on:
workflow_dispatch:
release:
types: [ created ]
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [ macos-latest, windows-latest ]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1.0.1
name: Run tests
with:
command: test
- uses: actions-rs/cargo@v1.0.1
name: Build
with:
command: build
args: --release --all-features
- name: Rename Release (Unix)
run: |
cargo install default-target
mkdir assets
FILENAME=topgrade-${{github.event.release.tag_name}}-$(default-target)
mv target/release/topgrade assets
cd assets
tar --format=ustar -czf $FILENAME.tar.gz topgrade
rm topgrade
ls .
if: ${{ matrix.platform != 'windows-latest' }}
shell: bash
- name: Rename Release (Windows)
run: |
cargo install default-target
mkdir assets
FILENAME=topgrade-${{github.event.release.tag_name}}-$(default-target)
mv target/release/topgrade.exe assets/topgrade.exe
cd assets
powershell Compress-Archive -Path * -Destination ${FILENAME}.zip
rm topgrade.exe
ls .
if: ${{ matrix.platform == 'windows-latest' }}
shell: bash
- name: Release
uses: softprops/action-gh-release@v1
with:
files: assets/*

View File

@@ -1,24 +0,0 @@
name: Rust
on:
push:
branches: [ "master", "dev" ]
pull_request:
branches: [ "master", "dev" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: cargo build --verbose
- name: Fmt
run: cargo fmt --check --all
- name: Run tests
run: cargo test --verbose

76
.github/workflows/scorecards.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '20 7 * * 2'
push:
branches: ["main"]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
contents: read
actions: read
# To allow GraphQL ListCommits to work
issues: read
pull-requests: read
# To detect SAST tools
checks: read
steps:
- name: "Checkout code"
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecards on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3
with:
sarif_file: results.sarif

View File

@@ -1,57 +0,0 @@
on:
pull_request:
push:
branches:
- main
name: Test with Code Coverage
jobs:
test:
name: Test
env:
PROJECT_NAME_UNDERSCORE: topgrade
CARGO_INCREMENTAL: 0
RUSTFLAGS: -Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort
RUSTDOCFLAGS: -Cpanic=abort
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
- name: Cache dependencies
uses: actions/cache@v2
env:
cache-name: cache-dependencies
with:
path: |
~/.cargo/.crates.toml
~/.cargo/.crates2.json
~/.cargo/bin
~/.cargo/registry/index
~/.cargo/registry/cache
target
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('Cargo.lock') }}
- name: Generate test result and coverage report
run: |
cargo install cargo2junit grcov;
cargo test $CARGO_OPTIONS -- -Z unstable-options --format json | cargo2junit > results.xml;
zip -0 ccov.zip `find . \( -name "$PROJECT_NAME_UNDERSCORE*.gc*" \) -print`;
grcov ccov.zip -s . -t lcov --llvm --ignore-not-existing --ignore "/*" --ignore "tests/*" -o lcov.info;
- name: Upload test results
uses: EnricoMi/publish-unit-test-result-action@v1
with:
check_name: Test Results
github_token: ${{ secrets.GITHUB_TOKEN }}
files: results.xml
- name: Upload to CodeCov
uses: codecov/codecov-action@v1
with:
# required for private repositories:
# token: ${{ secrets.CODECOV_TOKEN }}
files: ./lcov.info
fail_ci_if_error: true

View File

@@ -1,18 +0,0 @@
name: Publish to AUR
on:
push:
tags:
- "v*"
jobs:
aur-publish:
runs-on: ubuntu-latest
steps:
- name: Publish AUR package
uses: ATiltedTree/create-aur-release@v1
with:
package_name: topgrade
commit_username: "Thomas Schönauer"
commit_email: t.schoenauer@hgs-wt.at
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}

18
.gitignore vendored
View File

@@ -1,4 +1,20 @@
# JetBrains IDEs
.idea/
/target
# Visual Studio
.vs/
# Visual Studio Code
.vscode/
# Generic build outputs
/build
# Specific for some languages like Rust
/target
# LLVM profiling output
*.profraw
# Backup files for any .rs files in the project
**/*.rs.bk

25
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,25 @@
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.29.0
hooks:
- id: gitleaks
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.1
hooks:
- id: shellcheck
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/crate-ci/typos
rev: v1.39.2
hooks:
- id: typos
ci:
autoupdate_commit_msg: "chore(pre-commit): autoupdate"

20
.typos.toml Normal file
View File

@@ -0,0 +1,20 @@
# Typos configuration (minimal, conservative)
# Exclude locales and OS fingerprint data to avoid false positives
# - Recognize a few project-specific proper nouns
[files]
extend-exclude = [
"src/steps/os/os_release/**",
"locales/**",
# Include only English locale files - TODO: Split locales/app.yml into a Separate english File
# "!locales/en/**"
]
[default]
# Mark specific words as always valid by mapping them to themselves
check-file = true
check-filename = true
[default.extend-words]
# Add project-specific terms that should not be flagged as typos
# Example: topgrade = "topgrade"

38
.vscode/launch.json vendored
View File

@@ -1,38 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Topgrade",
"console": "integratedTerminal",
"cargo": {
"args": [
"build",
"--bin=topgrade-rs",
"--package=topgrade-rs"
],
"filter": {
"name": "topgrade-rs",
"kind": "bin"
}
},
"args": [
"--only",
"${input:step}",
"-v"
],
"cwd": "${workspaceFolder}"
},
],
"inputs": [
{
"type": "promptString",
"id": "step",
"description": "step name",
}
]
}

14
.vscode/tasks.json vendored
View File

@@ -1,14 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "cargo",
"command": "clippy",
"problemMatcher": [
"$rustc"
],
"group": "test",
"label": "rust: cargo clippy"
}
]
}

View File

@@ -1,50 +0,0 @@
{
// Place your topgrade workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"Skip Step": {
"scope": "rust",
"prefix": "skipstep",
"body": [
"return Err(SkipStep(format!(\"$1\")).into());"
]
},
"Step": {
"scope": "rust",
"prefix": "step",
"body": [
"pub fn $1(ctx: &ExecutionContext) -> Result<()> {",
" $0",
" Ok(())",
"}"
]
},
"Require Binary": {
"scope": "rust",
"prefix": "req",
"description": "Require a binary to be installed",
"body": [
"let ${1:binary} = require(\"${1:binary}\")?;"
]
},
"macos": {
"scope": "rust",
"prefix": "macos",
"body": [
"#[cfg(target_os = \"macos\")]"
]
}
}

0
BREAKINGCHANGES.md Normal file
View File

3
BREAKINGCHANGES_dev.md Normal file
View File

@@ -0,0 +1,3 @@
1. The `jet_brains_toolbox` step was renamed to `jetbrains_toolbox`. If you're
using the old name in your configuration file in the `disable` or `only`
fields, simply change it to `jetbrains_toolbox`.

229
CHANGELOG.md Normal file
View File

@@ -0,0 +1,229 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [16.2.1](https://github.com/topgrade-rs/topgrade/compare/v16.2.0...v16.2.1) - 2025-11-10
### Fixed
- *(release)* Use bash in Windows to fix powershell issues ([#1461](https://github.com/topgrade-rs/topgrade/pull/1461))
- *(release)* Fix .deb distribution ([#1460](https://github.com/topgrade-rs/topgrade/pull/1460))
- *(release)* Fix .deb distribution ([#1458](https://github.com/topgrade-rs/topgrade/pull/1458))
## [16.2.0](https://github.com/topgrade-rs/topgrade/compare/v16.1.2...v16.2.0) - 2025-11-10
### Added
- *(mise)* run `mise self-update` ([#1450](https://github.com/topgrade-rs/topgrade/pull/1450))
- *(falconf)* add falconf step ([#1219](https://github.com/topgrade-rs/topgrade/pull/1219))
- *(hyprpm)* add hyprpm step ([#1213](https://github.com/topgrade-rs/topgrade/pull/1213))
- *(doom)* add doom.aot option ([#1214](https://github.com/topgrade-rs/topgrade/pull/1214))
- add show_distribution_summary config option ([#1259](https://github.com/topgrade-rs/topgrade/pull/1259))
- *(rustup)* add rustup.channels config ([#1206](https://github.com/topgrade-rs/topgrade/pull/1206))
- *(os)* add AOSC OS support ([#1424](https://github.com/topgrade-rs/topgrade/pull/1424))
- add damp run type ([#1217](https://github.com/topgrade-rs/topgrade/pull/1217))
### Fixed
- *(release)* fix homebrew releases by migrating to dawidd6/action-homebrew-bump-formula ([#1457](https://github.com/topgrade-rs/topgrade/pull/1457))
- *(mise)* fix mise self-update failing when installed via a package manager ([#1456](https://github.com/topgrade-rs/topgrade/pull/1456))
- *(release)* Add man page to .deb distribution ([#1455](https://github.com/topgrade-rs/topgrade/pull/1455))
- *(self-update)* fix windows self-update reporting failure on successful self-update ([#1452](https://github.com/topgrade-rs/topgrade/pull/1452))
- *(pkgfile)* make pkgfile opt-in ([#1449](https://github.com/topgrade-rs/topgrade/pull/1449))
- *(vcpkg)* fix permission denied when updating vcpkg if it's installed as root ([#1447](https://github.com/topgrade-rs/topgrade/pull/1447))
- *(zh_TW)* fixed zh_TW strings ([#1446](https://github.com/topgrade-rs/topgrade/pull/1446))
- *(git)* fix shellexpand::tilde in git_repos in topgrade.d/* ([#1223](https://github.com/topgrade-rs/topgrade/pull/1223))
- *(auto-cpufreq)* skip when install script is not used ([#1215](https://github.com/topgrade-rs/topgrade/pull/1215))
- *(vim)* change nvimrc base_dir for windows ([#1433](https://github.com/topgrade-rs/topgrade/pull/1433))
- *(guix)* fix overcomplicated Guix step ([#1290](https://github.com/topgrade-rs/topgrade/pull/1290))
- *(gem)* fix incorrectly placed debug message in `gem` step ([#1212](https://github.com/topgrade-rs/topgrade/pull/1212))
- *(conda)* replace deprecated `auto_activate_base` ([#1158](https://github.com/topgrade-rs/topgrade/pull/1158))
- *(containers)* fix panic in `containers` step ([#1150](https://github.com/topgrade-rs/topgrade/pull/1150))
- *(jetbrains-toolbox)* fix step not dry running ([#1253](https://github.com/topgrade-rs/topgrade/pull/1253))
### Other
- comment run_config_update ([#1448](https://github.com/topgrade-rs/topgrade/pull/1448))
- Expand LLM guidelines in CONTRIBUTING.md ([#1445](https://github.com/topgrade-rs/topgrade/pull/1445))
- Add AI guidelines to CONTRIBUTING.md ([#1444](https://github.com/topgrade-rs/topgrade/pull/1444))
- add comments to Config::allowed_steps ([#1291](https://github.com/topgrade-rs/topgrade/pull/1291))
- *(nix)* Deduplicate run_nix and run_nix_self_upgrade nix --version checking ([#1376](https://github.com/topgrade-rs/topgrade/pull/1376))
- remove commented-out library code and unnecessary bin declaration ([#1373](https://github.com/topgrade-rs/topgrade/pull/1373))
- Simplify target cfgs ([#1346](https://github.com/topgrade-rs/topgrade/pull/1346))
- tidy up binary-conflict code ([#1329](https://github.com/topgrade-rs/topgrade/pull/1329))
- Improve installation section ([#1442](https://github.com/topgrade-rs/topgrade/pull/1442))
- *(deps)* Update jetbrains-toolbox-updater ([#1438](https://github.com/topgrade-rs/topgrade/pull/1438))
- remove template expansion in code contexts ([#1434](https://github.com/topgrade-rs/topgrade/pull/1434))
- *(deps)* bump github/codeql-action from 4.31.0 to 4.31.2 ([#1427](https://github.com/topgrade-rs/topgrade/pull/1427))
- don't persist credentials in actions/checkout ([#1422](https://github.com/topgrade-rs/topgrade/pull/1422))
- Improve CONTRIBUTING.md ([#1420](https://github.com/topgrade-rs/topgrade/pull/1420))
- Update SECURITY.md ([#1421](https://github.com/topgrade-rs/topgrade/pull/1421))
- Enforce conventional commits in PR titles ([#1418](https://github.com/topgrade-rs/topgrade/pull/1418))
- Improve contributing section
- Remove roadmap
- Reformat README.md
- Update installation methods
- *(release)* Fix dispatch error in create_release_assets.yml ([#1406](https://github.com/topgrade-rs/topgrade/pull/1406))
## [16.1.2](https://github.com/topgrade-rs/topgrade/compare/v16.1.1...v16.1.2) - 2025-11-01
### Fixed
- *(release)* Fix cross-compilation for arm requiring glibc>=2.39 ([#1405](https://github.com/topgrade-rs/topgrade/pull/1405))
- *(release)* Fix FreeBSD build ([#1404](https://github.com/topgrade-rs/topgrade/pull/1404))
- *(release)* Fix FreeBSD build ([#1402](https://github.com/topgrade-rs/topgrade/pull/1402))
- *(release)* Fix manual workflow trigger ([#1401](https://github.com/topgrade-rs/topgrade/pull/1401))
- *(release)* Fix FreeBSD build and add manual workflow trigger ([#1399](https://github.com/topgrade-rs/topgrade/pull/1399))
### Other
- *(release)* Fix cross trying to fmt ([#1403](https://github.com/topgrade-rs/topgrade/pull/1403))
## [16.1.1](https://github.com/topgrade-rs/topgrade/compare/v16.1.0...v16.1.1) - 2025-11-01
### Fixed
- *(typst)* Skip typst when self-update is disabled ([#1397](https://github.com/topgrade-rs/topgrade/pull/1397))
- *(release)* Fix winget release workflow ([#1395](https://github.com/topgrade-rs/topgrade/pull/1395))
- *(release)* Fix FreeBSD release ([#1393](https://github.com/topgrade-rs/topgrade/pull/1393))
- *(release)* Fix FreeBSD release ([#1391](https://github.com/topgrade-rs/topgrade/pull/1391))
### Other
- Update from deprecated macos-13 to macos-15-intel ([#1394](https://github.com/topgrade-rs/topgrade/pull/1394))
## [16.1.0](https://github.com/topgrade-rs/topgrade/compare/v16.0.4...v16.1.0) - 2025-10-31
### Added
- *(deb-get)* Skip non-deb-get packages by passing --dg-only ([#1386](https://github.com/topgrade-rs/topgrade/pull/1386))
- *(typst)* add typst step ([#1374](https://github.com/topgrade-rs/topgrade/pull/1374))
- *(step)* Add atuin step ([#1367](https://github.com/topgrade-rs/topgrade/pull/1367))
- *(nix)* support upgrading Determinate Nix ([#1366](https://github.com/topgrade-rs/topgrade/pull/1366))
- *(sudo)* print warning if Windows Sudo is misconfigured
- *(sudo)* print warning if steps were skipped due to missing sudo
- *(sudo)* add SudoKind::Null
- detect and warn if running as root
- add `--no-tmux` flag ([#1328](https://github.com/topgrade-rs/topgrade/pull/1328))
- add step for mandb - user and system (update man entries) ([#1319](https://github.com/topgrade-rs/topgrade/pull/1319))
- support for pkgfile ([#1306](https://github.com/topgrade-rs/topgrade/pull/1306))
- add "show_skipped" option in config file #1280 ([#1286](https://github.com/topgrade-rs/topgrade/pull/1286))
- fix typos ([#1221](https://github.com/topgrade-rs/topgrade/pull/1221))
- *(conda)* allow configuring additional envs to update ([#1048](https://github.com/topgrade-rs/topgrade/pull/1048))
- *(step)* nix-helper ([#1045](https://github.com/topgrade-rs/topgrade/pull/1045))
- *(winget)* winget uses sudo when `[windows] winget_use_sudo = true` ([#1061](https://github.com/topgrade-rs/topgrade/pull/1061))
- suppress pixi release notes by default ([#1225](https://github.com/topgrade-rs/topgrade/pull/1225))
### Fixed
- *(freshclam)* run with sudo when running without sudo fails ([#1118](https://github.com/topgrade-rs/topgrade/pull/1118))
- *(tldr)* move tldr to be a generic step ([#1370](https://github.com/topgrade-rs/topgrade/pull/1370))
- *(nix)* fix nix upgrade command selection for profiles in XDG_STATE_HOME ([#1354](https://github.com/topgrade-rs/topgrade/pull/1354))
- *(containers)* Docker update fails on M Macs due to platform / ([#1360](https://github.com/topgrade-rs/topgrade/pull/1360))
- *(sudo)* reorder require_sudo() after print_separator()
- *(sudo)* use require_sudo for windows commands
- *(sudo)* prevent sudo_command = "sudo" finding gsudo
- *(sudo)* set sudo flags depending on kind
- skip gcloud update step if component manager is disabled ([#1237](https://github.com/topgrade-rs/topgrade/pull/1237))
- *(i18n)* use double-quotes for translations with newlines
- *(powershell)* run microsoft_store command directly
- *(powershell)* remove mentions of USOClient
- *(powershell)* execution policy check breaks when run in pwsh
- *(powershell)* don't use sudo with Update-Module for pwsh
- *(powershell)* add -Command to module update cmdline
- *(tmux)* support all default `tpm` locations (xdg and both hardcoded locations) ([#1146](https://github.com/topgrade-rs/topgrade/pull/1146))
- fixed the German translation for "y/n/s/q" ([#1220](https://github.com/topgrade-rs/topgrade/pull/1220))
### Other
- *(release)* switch to release-plz ([#1333](https://github.com/topgrade-rs/topgrade/pull/1333))
- *(pre-commit)* Make pre-commit.ci use conventional commits ([#1388](https://github.com/topgrade-rs/topgrade/pull/1388))
- *(pre-commit)* pre-commit autoupdate ([#1383](https://github.com/topgrade-rs/topgrade/pull/1383))
- *(deps)* bump actions/upload-artifact from 4.6.2 to 5.0.0 ([#1382](https://github.com/topgrade-rs/topgrade/pull/1382))
- *(deps)* bump github/codeql-action from 4.30.9 to 4.31.0 ([#1379](https://github.com/topgrade-rs/topgrade/pull/1379))
- *(deps)* bump actions/download-artifact from 5.0.0 to 6.0.0 ([#1380](https://github.com/topgrade-rs/topgrade/pull/1380))
- *(deps)* bump taiki-e/install-action from 2.62.33 to 2.62.38 ([#1381](https://github.com/topgrade-rs/topgrade/pull/1381))
- *(pre-commit)* Fix pre-commit-config.yaml ([#1378](https://github.com/topgrade-rs/topgrade/pull/1378))
- *(release)* Add .deb auto completion script ([#1353](https://github.com/topgrade-rs/topgrade/pull/1353))
- *(deps)* bump github/codeql-action from 4.30.8 to 4.30.9 ([#1369](https://github.com/topgrade-rs/topgrade/pull/1369))
- *(deps)* bump taiki-e/install-action from 2.62.28 to 2.62.33 ([#1368](https://github.com/topgrade-rs/topgrade/pull/1368))
- *(deps)* bump actions/dependency-review-action from 4.8.0 to 4.8.1 ([#1362](https://github.com/topgrade-rs/topgrade/pull/1362))
- *(deps)* bump softprops/action-gh-release from 2.3.4 to 2.4.1 ([#1364](https://github.com/topgrade-rs/topgrade/pull/1364))
- *(deps)* bump taiki-e/install-action from 2.62.21 to 2.62.28 ([#1363](https://github.com/topgrade-rs/topgrade/pull/1363))
- *(deps)* bump github/codeql-action from 3.30.6 to 4.30.8 ([#1365](https://github.com/topgrade-rs/topgrade/pull/1365))
- *(deps)* bump github/codeql-action from 3.30.5 to 3.30.6 ([#1355](https://github.com/topgrade-rs/topgrade/pull/1355))
- *(deps)* bump softprops/action-gh-release from 2.3.3 to 2.3.4 ([#1356](https://github.com/topgrade-rs/topgrade/pull/1356))
- *(deps)* bump taiki-e/install-action from 2.62.13 to 2.62.21 ([#1357](https://github.com/topgrade-rs/topgrade/pull/1357))
- *(deps)* bump ossf/scorecard-action from 2.4.2 to 2.4.3 ([#1358](https://github.com/topgrade-rs/topgrade/pull/1358))
- *(deps)* bump actions/dependency-review-action from 4.7.3 to 4.8.0 ([#1350](https://github.com/topgrade-rs/topgrade/pull/1350))
- *(deps)* bump github/codeql-action from 3.30.3 to 3.30.5 ([#1349](https://github.com/topgrade-rs/topgrade/pull/1349))
- *(deps)* bump taiki-e/install-action from 2.62.1 to 2.62.13 ([#1351](https://github.com/topgrade-rs/topgrade/pull/1351))
- *(deps)* bump actions/cache from 4.2.4 to 4.3.0 ([#1352](https://github.com/topgrade-rs/topgrade/pull/1352))
- Fix WSL distribution name cleanup ([#1348](https://github.com/topgrade-rs/topgrade/pull/1348))
- *(pyproject)* mark version as dynamic ([#1347](https://github.com/topgrade-rs/topgrade/pull/1347))
- *(deps)* replace winapi with windows
- *(sudo)* rename interactive to login_shell
- Fix "WSL already reported" panic ([#1344](https://github.com/topgrade-rs/topgrade/pull/1344))
- Move step logic out of Powershell struct ([#1345](https://github.com/topgrade-rs/topgrade/pull/1345))
- *(deps)* bump taiki-e/install-action from 2.61.5 to 2.62.1 ([#1335](https://github.com/topgrade-rs/topgrade/pull/1335))
- *(deps)* bump Swatinem/rust-cache from 2.8.0 to 2.8.1 ([#1336](https://github.com/topgrade-rs/topgrade/pull/1336))
- Fixes for #1188; custom_commands broken ([#1332](https://github.com/topgrade-rs/topgrade/pull/1332))
- use login shell when executing topgrade ([#1327](https://github.com/topgrade-rs/topgrade/pull/1327))
- *(deps)* bump taiki-e/install-action from 2.60.0 to 2.61.5 ([#1325](https://github.com/topgrade-rs/topgrade/pull/1325))
- *(deps)* bump github/codeql-action from 3.30.1 to 3.30.3 ([#1324](https://github.com/topgrade-rs/topgrade/pull/1324))
- *(pre-commit)* add typos with conservative excludes; no content changes ([#1317](https://github.com/topgrade-rs/topgrade/pull/1317))
- fix simple typos in code and comments (split var, whether, Extensions) ([#1318](https://github.com/topgrade-rs/topgrade/pull/1318))
- *(deps)* bump github/codeql-action from 3.29.11 to 3.30.1 ([#1301](https://github.com/topgrade-rs/topgrade/pull/1301))
- *(deps)* bump softprops/action-gh-release from 2.3.2 to 2.3.3 ([#1302](https://github.com/topgrade-rs/topgrade/pull/1302))
- *(deps)* bump taiki-e/install-action from 2.58.21 to 2.60.0 ([#1303](https://github.com/topgrade-rs/topgrade/pull/1303))
- *(deps)* bump actions/dependency-review-action from 4.7.2 to 4.7.3 ([#1304](https://github.com/topgrade-rs/topgrade/pull/1304))
- *(deps)* bump actions/attest-build-provenance from 2.4.0 to 3.0.0 ([#1305](https://github.com/topgrade-rs/topgrade/pull/1305))
- update tracing-subscriber to ~0.3.20 (ANSI escape injection fix, GHSA-xwfj-jgwm-7wp5) ([#1288](https://github.com/topgrade-rs/topgrade/pull/1288))
- *(deps)* bump github/codeql-action from 3.29.8 to 3.29.11 ([#1281](https://github.com/topgrade-rs/topgrade/pull/1281))
- *(deps)* bump actions/dependency-review-action from 4.7.1 to 4.7.2 ([#1282](https://github.com/topgrade-rs/topgrade/pull/1282))
- *(deps)* bump taiki-e/install-action from 2.58.9 to 2.58.21 ([#1283](https://github.com/topgrade-rs/topgrade/pull/1283))
- *(deps)* bump PyO3/maturin-action from 1.49.3 to 1.49.4 ([#1285](https://github.com/topgrade-rs/topgrade/pull/1285))
- *(deps)* bump actions/cache from 4.2.3 to 4.2.4 ([#1284](https://github.com/topgrade-rs/topgrade/pull/1284))
- Support "Insiders" versions of VSCode and VSCodium ([#1279](https://github.com/topgrade-rs/topgrade/pull/1279))
- Sudo preserve env list argument is `--preserve-env` ([#1276](https://github.com/topgrade-rs/topgrade/pull/1276))
- Clippy fixes from rust 1.91 nightly ([#1267](https://github.com/topgrade-rs/topgrade/pull/1267))
- *(deps)* bump actions/checkout from 4.2.2 to 5.0.0 ([#1264](https://github.com/topgrade-rs/topgrade/pull/1264))
- *(deps)* bump actions/download-artifact from 4.3.0 to 5.0.0 ([#1263](https://github.com/topgrade-rs/topgrade/pull/1263))
- *(deps)* bump taiki-e/install-action from 2.58.0 to 2.58.9 ([#1261](https://github.com/topgrade-rs/topgrade/pull/1261))
- *(deps)* bump ossf/scorecard-action from 2.4.0 to 2.4.2 ([#1262](https://github.com/topgrade-rs/topgrade/pull/1262))
- *(deps)* bump github/codeql-action from 3.29.5 to 3.29.8 ([#1265](https://github.com/topgrade-rs/topgrade/pull/1265))
- *(ci)* Dependabot, workflow security ([#1257](https://github.com/topgrade-rs/topgrade/pull/1257))
- replace once_cell crate with std equivalent ([#1260](https://github.com/topgrade-rs/topgrade/pull/1260))
- *(deps)* bump tokio from 1.38 to 1.47 ([#1256](https://github.com/topgrade-rs/topgrade/pull/1256))
- *(app.yml)* fix fr language #1248
- *(sudo)* add SudoKind::WinSudo
- *(sudo)* add SudoExecuteOpts builder functions and preserve_env enum
- *(yarn)* remove unnecessary Yarn::yarn field
- *(apt)* extract detect_apt() function
- route sudo usage through Sudo::execute*
- move RunType::execute to ExecutionContext
- *(powershell)* store powershell path directly
- *(powershell)* cleanup and simplify code
- Move step running into enum for dynamic ordering ([#1188](https://github.com/topgrade-rs/topgrade/pull/1188))
- Generate artifact attestations for release assets ([#1216](https://github.com/topgrade-rs/topgrade/pull/1216))
- windows update, use explicit reboot policy ([#1143](https://github.com/topgrade-rs/topgrade/pull/1143))
- add Discord invite link to README ([#1203](https://github.com/topgrade-rs/topgrade/pull/1203))
- Catch secondary uv self-update error ([#1201](https://github.com/topgrade-rs/topgrade/pull/1201))
- Handle another format change in asdf version ([#1194](https://github.com/topgrade-rs/topgrade/pull/1194))
- Preserve custom command order from config instead of sorting alphabetically ([#1182](https://github.com/topgrade-rs/topgrade/pull/1182))
- Add support for multiple binary names and idea having multiple binaries ([#1167](https://github.com/topgrade-rs/topgrade/pull/1167))
- fix the invalid action version ([#1185](https://github.com/topgrade-rs/topgrade/pull/1185))
- allow us to re-run AUR CI ([#1184](https://github.com/topgrade-rs/topgrade/pull/1184))
- Update Yazi upgrade step to use ya pkg. ([#1163](https://github.com/topgrade-rs/topgrade/pull/1163))
- use the new tag name and specify shell to bash ([#1183](https://github.com/topgrade-rs/topgrade/pull/1183))
- allow specifying tag when manually run 'create_release_assets.yml' ([#1180](https://github.com/topgrade-rs/topgrade/pull/1180))
- fix homebrew ci, remove duplicate trigger event ([#1179](https://github.com/topgrade-rs/topgrade/pull/1179))
- fix PyPI pipeline duplicate wheel name ([#1178](https://github.com/topgrade-rs/topgrade/pull/1178))
- add event workflow_dispatch to release pipelines ([#1177](https://github.com/topgrade-rs/topgrade/pull/1177))
- fix pipeline release to PyPI ([#1176](https://github.com/topgrade-rs/topgrade/pull/1176))
- Install rustfmt and clippy where necessary ([#1171](https://github.com/topgrade-rs/topgrade/pull/1171))

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
open an issue on GitHub .
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

182
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,182 @@
## Contributing to `topgrade`
Thank you for your interest in contributing to `topgrade`!
We welcome and encourage contributions of all kinds, such as:
1. Issue reports or feature requests
2. Documentation improvements
3. Code (PR or PR Review)
### LLM/AI guidelines
You may use LLMs (AI tools) for:
* Inspiration, problem solving, help with Rust, translation, etc.
* Generating small and self-contained snippets of code (e.g., shell scripts or utility functions)
Do **not** use LLMs to:
* Generate ("vibe code") entire pull requests
* Write or generate issue or pull request descriptions
### General guidelines
**Please use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for your PR title**.
We use [pre-commit](https://github.com/pre-commit/pre-commit). It runs in CI, but you can optionally install the hook
locally with `pre-commit install`. If you don't want to use pre-commit, make sure the following pass before submitting
your PR:
```shell
$ cargo fmt
$ cargo clippy
$ cargo test
```
### Adding a new step
In `topgrade`'s terms, a package manager (or something else that can be upgraded) is called a step.
To add a new step to `topgrade`:
1. Add a new variant to
[`enum Step`](https://github.com/topgrade-rs/topgrade/blob/main/src/step.rs)
```rust
pub enum Step {
// Existing steps
// ...
// Your new step here!
// Make sure it stays sorted alphabetically because that looks great :)
Xxx,
}
```
2. Implement the update function
You need to find the appropriate location where this update function goes, it should be
a file under [`src/steps`](https://github.com/topgrade-rs/topgrade/tree/main/src/steps),
the file names are self-explanatory, for example, steps related to `zsh` are
placed in [`steps/zsh.rs`](https://github.com/topgrade-rs/topgrade/blob/main/src/steps/zsh.rs), and steps that run on
Linux only are placed in [`steps/linux.rs`](https://github.com/topgrade-rs/topgrade/blob/main/src/steps/linux.rs).
Then you implement the update function, and put it in the file where it belongs.
```rust
pub fn run_xxx(ctx: &ExecutionContext) -> Result<()> {
// Check if this step is installed, if not, then this update will be skipped.
let xxx = require("xxx")?;
// Print the separator
print_separator("xxx");
// Invoke the new step to get things updated!
ctx.execute(xxx)
.arg(/* args required by this step */)
.status_checked()
}
```
Such an update function would be conventionally named `run_xxx()`, where `xxx`
is the name of the new step, and it should take an argument of type
`&ExecutionContext`.
The update function should usually do 3 things:
1. Check if the step is installed
2. Output the separator
3. Execute commands
This is sufficient for most tools, but you may need some extra stuff
for complicated steps.
3. Add a match arm to `Step::run()`
```rust
Xxx => runner.execute(*self, "xxx", || ItsModule::run_xxx(ctx))?
```
We use [conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html)
to separate the steps. For example, for steps that are Linux-only, it goes
like this:
```rust
#[cfg(target_os = "linux")]
{
// Xxx is Linux-only
runner.execute(Step::Xxx, "xxx", || ItsModule::run_xxx(&ctx))?;
}
```
4. Finally, add the step to `default_steps()` in `step.rs`
```rust
steps.push(Xxx)
```
Keep the conditional compilation the same as in the above step 3.
Congrats, you just added a new step :)
### Modification to the configuration entries
If your PR has the configuration options
(in [`src/config.rs`](https://github.com/topgrade-rs/topgrade/blob/main/src/config.rs))
modified:
1. Adding new options
2. Changing the existing options
Be sure to apply your changes to
[`config.example.toml`](https://github.com/topgrade-rs/topgrade/blob/main/config.example.toml),
and have some basic documentations guiding user how to use these options.
### Breaking changes
If your PR introduces a breaking change, document it in [`BREAKINGCHANGES_dev.md`][bc_dev].
It should be written in Markdown and wrapped at 80, for example:
```md
1. The configuration location has been updated to x.
2. The step x has been removed.
3. ...
```
[bc_dev]: https://github.com/topgrade-rs/topgrade/blob/main/BREAKINGCHANGES_dev.md
### I18n
If your PR introduces user-facing messages, we need to ensure they are translated.
Please add the translations to [`locales/app.yml`][app_yml]. For simple messages
without arguments (e.g., "hello world"), we can simply translate them according
(Tip: LLMs are good at translation). If a message contains
arguments, e.g., "hello <NAME>", please follow this convention:
```yml
"hello {name}": # key
en: "hello %{name}" # translation
```
Arguments in the key should be in format `{argument_name}`, and they will have
a preceding `%` when used in translations.
[app_yml]: https://github.com/topgrade-rs/topgrade/blob/main/locales/app.yml
### Locales
Some steps respect locale, which means their output can be in language other
than English. In those cases, we cannot rely on the output of a command.
For example, one may want to check if a tool works by doing this:
```rust
let output = Command::new("xxx").arg("--help").output().unwrap();
let stdout = from_utf8(output.stdout).expect("Assume it is UTF-8 encoded");
if stdout.contains("help") {
// xxx works
}
```
If `xxx` respects locale, then the above code should work on English system,
on a system that does not use English, e.g., it uses Chinese, that `"help"` may be
translated to `"帮助"`, and the above code won't work.

3743
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,57 +3,96 @@ name = "topgrade"
description = "Upgrade all the things"
categories = ["os"]
keywords = ["upgrade", "update"]
license-file = "LICENSE"
license = "GPL-3.0"
repository = "https://github.com/topgrade-rs/topgrade"
version = "10.1.0"
rust-version = "1.84.1"
version = "16.2.1"
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
exclude = ["doc/screenshot.gif"]
exclude = ["doc/screenshot.gif", "BREAKINGCHANGES_dev.md"]
edition = "2021"
readme = "README.md"
[[bin]]
name = "topgrade"
path = "src/main.rs"
[dependencies]
home = "0.5"
directories = "4.0"
serde = { version = "1.0", features = ["derive"] }
toml = "0.5"
which_crate = { version = "4.1", package = "which" }
shellexpand = "2.1"
clap = { version = "4.0.18", features = ["cargo", "derive"] }
log = "0.4"
walkdir = "2.3"
console = "0.15"
lazy_static = "1.4"
chrono = "0.4"
pretty_env_logger = "0.4"
glob = "0.3"
strum = { version = "0.24", features = ["derive"] }
thiserror = "1.0"
anyhow = "1.0"
tempfile = "3.2"
cfg-if = "1.0"
tokio = { version = "1.5", features = ["process", "rt-multi-thread"] }
futures = "0.3"
regex = "1.5"
sys-info = "0.9"
semver = "1.0"
home = "=0.5.11"
etcetera = "=0.11.0"
serde = { version = "~1.0", features = ["derive"] }
toml = "=0.9.8"
which_crate = { version = "~8.0", package = "which" }
shellexpand = "~3.1"
clap = { version = "~4.5", features = ["cargo", "derive"] }
clap_complete = "~4.5"
clap_mangen = "~0.2"
walkdir = "~2.5"
console = "~0.16"
chrono = "~0.4"
glob = "~0.3"
strum = { version = "~0.27", features = ["derive"] }
thiserror = "~2.0"
tempfile = "~3.23"
tokio = { version = "~1.48", features = ["process", "rt-multi-thread"] }
futures = "~0.3"
regex = "~1.12"
semver = "~1.0"
shell-words = "~1.1"
color-eyre = "~0.6"
tracing = { version = "~0.1", features = ["attributes", "log"] }
tracing-subscriber = { version = "~0.3.20", features = ["env-filter", "time"] }
merge = "~0.1"
regex-split = "~0.1"
notify-rust = "~4.11"
wildmatch = "2.3.0"
rust-i18n = "3.0.1"
sys-locale = "0.3.1"
jetbrains-toolbox-updater = "5.0.0"
indexmap = { version = "2.9.0", features = ["serde"] }
serde_json = "1.0.145"
# Temporary transitive dependency pins
ignore = "=0.4.23"
globset = "=0.4.16"
base64ct = "<1.8.0"
[target.'cfg(target_os = "macos")'.dependencies]
notify-rust = "4.5"
[patch.crates-io]
mac-notification-sys = { git = "https://github.com/h4llow3En/mac-notification-sys" }
[package.metadata.generate-rpm]
assets = [{ source = "target/release/topgrade", dest = "/usr/bin/topgrade" }]
[package.metadata.generate-rpm.requires]
git = "*"
[package.metadata.deb]
name = "topgrade"
maintainer = "Chris Gelatt <kreeblah@gmail.com>"
copyright = "2024, Topgrade Team"
license-file = ["LICENSE", "0"]
depends = "$auto"
extended-description = "Keeping your system up to date usually involves invoking multiple package managers. This results in big, non-portable shell one-liners saved in your shell. To remedy this, Topgrade detects which tools you use and runs the appropriate commands to update them."
section = "utils"
priority = "optional"
default-features = true
assets = [
["target/release/topgrade", "usr/bin/", "755"],
["README.md", "usr/share/doc/topgrade/README.md", "644"],
# The man page and shell completions are automatically generated by topgrade's build process in CI,
# so these files aren't actually committed.
["deployment/deb/topgrade.1", "usr/share/man/man1/topgrade.1", "644"],
["deployment/deb/topgrade.bash", "usr/share/bash-completion/completions/topgrade", "644"],
["deployment/deb/topgrade.fish", "usr/share/fish/vendor_completions.d/topgrade.fish", "644"],
["deployment/deb/_topgrade", "usr/share/zsh/vendor-completions/", "644"],
]
[target.'cfg(unix)'.dependencies]
nix = "0.24"
rust-ini = "0.18"
self_update_crate = { version = "0.30", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
nix = { version = "~0.30", features = ["hostname", "signal", "user"] }
rust-ini = "~0.21"
self_update_crate = { version = "~0.42", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
[target.'cfg(windows)'.dependencies]
self_update_crate = { version = "0.30", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
winapi = "0.3"
parselnk = "0.1"
is_elevated = "~0.1"
parselnk = "~0.1"
self_update_crate = { version = "~0.42", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
windows = { version = "~0.62", features = ["Win32_System_Console"] }
windows-registry = "~0.6"
[profile.release]
lto = true

116
README.md
View File

@@ -1,16 +1,16 @@
<div align="center">
<img alt="Topgrade" src="doc/topgrade.png" width="850px">
<!--
<a href="https://github.com/topgrade-rs/topgrade/releases"><img alt="GitHub Release" src="https://img.shields.io/github/release/r-darwish/topgrade.svg"></a>
<h1>
<img alt="Topgrade" src="doc/topgrade_transparent.png" width="850px">
</h1>
<a href="https://github.com/topgrade-rs/topgrade/releases"><img alt="GitHub Release" src="https://img.shields.io/github/release/topgrade-rs/topgrade.svg"></a>
<a href="https://crates.io/crates/topgrade"><img alt="crates.io" src="https://img.shields.io/crates/v/topgrade.svg"></a>
<a href="https://aur.archlinux.org/packages/topgrade"><img alt="AUR" src="https://img.shields.io/aur/version/topgrade.svg"></a>
<a href="https://formulae.brew.sh/formula/topgrade"><img alt="Homebrew" src="https://img.shields.io/homebrew/v/topgrade.svg"></a>
-->
<img alt="Demo" src="doc/screenshot.gif" width="550px">
<img alt="Demo" src="doc/topgrade_demo.gif">
</div>
## Introduction
> **Note**
@@ -22,62 +22,104 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
## Installation
- Arch Linux: [AUR](https://aur.archlinux.org/packages/topgrade) package.
- NixOS: _topgrade_ package in `nixpkgs`.
- macOS: [Homebrew](https://formulae.brew.sh/formula/topgrade) or [MacPorts](https://ports.macports.org/port/topgrade/).
[![Packaging status](https://repology.org/badge/vertical-allrepos/topgrade.svg)](https://repology.org/project/topgrade/versions)
Other systems users can either use `cargo install` or use the compiled binaries from the release page.
The compiled binaries contain a self-upgrading feature.
### Official
Topgrade requires Rust 1.51 or above.
- Self-updating binary (all platforms): [releases](https://github.com/topgrade-rs/topgrade/releases)
- Install from source (all platforms): [`cargo install topgrade`](https://crates.io/crates/topgrade)
- Debian/Ubuntu ([deb-get](https://github.com/wimpysworld/deb-get)):
[`deb-get install topgrade`](https://github.com/wimpysworld/deb-get/blob/main/01-main/packages/topgrade)
- Arch Linux (AUR): [topgrade](https://aur.archlinux.org/packages/topgrade)
or [topgrade-bin](https://aur.archlinux.org/packages/topgrade-bin)
- [PyPi](https://pypi.org/): `pip`, `pipx`, or `uv tool` [
`install topgrade`](https://pypi.org/project/topgrade/)
- Windows ([Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)): [
`winget install --id=topgrade-rs.topgrade -e`](https://winstall.app/apps/topgrade-rs.topgrade)
- macOS or Linux ([Homebrew](https://brew.sh/)): [`brew install topgrade`](https://formulae.brew.sh/formula/topgrade)
## Documentation
### Community-maintained
> **Warning**
> Work in Progress
You can visit the documentation at [topgrade-rs.github.io](https://topgrade-rs.github.io/) .
- Windows ([Chocolatey](https://chocolatey.org/)): [
`choco install topgrade`](https://community.chocolatey.org/packages/topgrade)
- Windows ([Scoop](https://scoop.sh/)): [
`scoop bucket add main && scoop install main/topgrade`](https://scoop.sh/#/apps?q=topgrade)
- macOS ([MacPorts](https://www.macports.org/)): [
`sudo port install topgrade`](https://ports.macports.org/port/topgrade/)
- Fedora ([Copr](https://copr.fedorainfracloud.org/)): [
`dnf copr enable lilay/topgrade && dnf install topgrade`](https://copr.fedorainfracloud.org/coprs/lilay/topgrade/)
- NixOS or Nix (nixpkgs): [topgrade](https://search.nixos.org/packages?show=topgrade)
- Void Linux: [`sudo xbps-install -S topgrade`](https://voidlinux.org/packages/?arch=x86_64&q=topgrade)
## Usage
Just run `topgrade`.
See [the wiki](https://github.com/r-darwish/topgrade/wiki/Step-list) for the list of things Topgrade supports.
## Customization
## Configuration
See `config.example.toml` for an example configuration file.
### Configuration path
## Migration and Breaking Changes
The configuration should be placed in the following paths depending by the operating system:
Whenever there is a **breaking change**, the major version number will be bumped,
and we will document these changes in the release note, please take a look at
it when updated to a major release.
- **Windows** - `%APPDATA%/topgrade.toml`
- **macOS** and **other Unix systems** - `${XDG_CONFIG_HOME:-~/.config}/topgrade.toml`
> Got a question? Feel free to open an issue or discussion!
## Contribution
### Configuration Path
### Problems or missing features?
#### `CONFIG_DIR` on each platform
Open a new Issue describing your problem and if possible with a possible solution.
- **Windows**: `%APPDATA%`
- **macOS** and **other Unix systems**: `${XDG_CONFIG_HOME:-~/.config}`
### Missing a feature or found an unsupported tool/distro?
`topgrade` will look for the configuration file in the following places, in order of priority:
Just let us now what you are missing by opening an issue.
For tools please open an Issue describing the tool, which platforms it supports and if possible, give us an example of its usage.
1. `CONFIG_DIR/topgrade.toml`
2. `CONFIG_DIR/topgrade/topgrade.toml`
### Want to contribute to the code?
If the file with higher priority is present, no matter it is valid or not, the other configuration files will be
ignored.
Just fork the repository and start coding.
On the first run(no configuration file exists), `topgrade` will create a configuration file at
`CONFIG_DIR/topgrade.toml` for you.
## Remote execution
### Custom Commands
Custom commands can be defined in the config file which can be run before, during, or after the inbuilt commands, as
required.
By default, the custom commands are run using a new shell according to the `$SHELL` environment variable on unix (falls
back to `sh`) or `pwsh` on windows (falls back to `powershell`).
On unix, if you want to run your command using an interactive shell, for example to source your shell's rc files, you
can add `-i` at the start of your custom command.
But note that this requires the command to exit the shell correctly or else the shell will hang indefinitely.
## Remote Execution
You can specify a key called `remote_topgrades` in the configuration file.
This key should contain a list of hostnames that have Topgrade installed on them.
Topgrade will use `ssh` to run `topgrade` on remote hosts before acting locally.
To limit the execution only to specific hosts use the `--remote-host-limit` parameter.
## ToDo
## Contribution
- Add a proper testing framework to the code base.
- Add unit tests for package managers.
- Split up code into more maintainable parts, eg. putting every linux package manager in a own submodule of linux.rs.
### Problems or missing features?
Open a new issue describing your problem and if possible provide a solution.
### Missing a feature or found an unsupported tool/distro?
Just let us now what you are missing by opening an issue.
For tools, please open an issue describing the tool, which platforms it supports and if possible, give us an example of
its usage.
### Want to contribute?
See [CONTRIBUTING.md](https://github.com/topgrade-rs/topgrade/blob/master/CONTRIBUTING.md)
## Discord server
Welcome to [join](https://discord.gg/Q8HGGWundY) our Discord server if you want
to discuss Topgrade!

21
RELEASE_PROCEDURE.md Normal file
View File

@@ -0,0 +1,21 @@
Non-major versions go via release-plz.
1. bumps the version number.
> If there are breaking changes, the major version number should be increased.
2. If the major versioin number gets bumped, update [SECURITY.md][SECURITY_file_link].
[SECURITY_file_link]: https://github.com/topgrade-rs/topgrade/blob/main/SECURITY.md
3. Overwrite [`BREAKINGCHANGES`][breaking_changes] with
[`BREAKINGCHANGES_dev`][breaking_changes_dev], and create a new dev file:
```sh'
$ cd topgrade
$ mv BREAKINGCHANGES_dev.md BREAKINGCHANGES.md
$ touch BREAKINGCHANGES_dev.md
```
[breaking_changes_dev]: https://github.com/topgrade-rs/topgrade/blob/main/BREAKINGCHANGES_dev.md
[breaking_changes]: https://github.com/topgrade-rs/topgrade/blob/main/BREAKINGCHANGES.md

9
SECURITY.md Normal file
View File

@@ -0,0 +1,9 @@
# Security Policy
## Reporting a vulnerability
To report a security vulnerability, go to [the security tab](https://github.com/topgrade-rs/topgrade/security) and click "Report a vulnerability".
## Supported Versions
We only support the latest version of Topgrade. Fixes are not backported.

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env sh
#!/usr/bin/env bash
build_function() {
rustup update
cargo install cross
@@ -20,7 +21,7 @@ build_function() {
package_function() {
cd build
cd build || exit 1
mkdir x86_64-unknown-linux-gnu/
mkdir x86_64-unknown-linux-musl/
mkdir x86_64-unknown-freebsd/
@@ -35,28 +36,28 @@ package_function() {
cp ../target/aarch64-unknown-linux-musl/release/topgrade aarch64-unknown-linux-musl/topgrade
cp ../target/x86_64-pc-windows-gnu/release/topgrade.exe x86_64-pc-windows-gnu/topgrade.exe
cd x86_64-unknown-linux-gnu/
tar -czf ../topgrade-${ans}-x86_64-linux-gnu.tar.gz topgrade
cd x86_64-unknown-linux-gnu/ || exit 1
tar -czf "../topgrade-${ans}-x86_64-linux-gnu.tar.gz" topgrade
cd ..
cd x86_64-unknown-linux-musl
tar -czf ../topgrade-${ans}-x86_64-linux-musl.tar.gz topgrade
cd x86_64-unknown-linux-musl/ || exit 1
tar -czf "../topgrade-${ans}-x86_64-linux-musl.tar.gz" topgrade
cd ..
cd x86_64-unknown-freebsd/
tar -czf ../topgrade-${ans}-x86_64-freebsd.tar.gz topgrade
cd x86_64-unknown-freebsd/ || exit 1
tar -czf "../topgrade-${ans}-x86_64-freebsd.tar.gz" topgrade
cd ..
cd aarch64-unknown-linux-gnu/
tar -czf ../topgrade-${ans}-aarch64-linux-gnu.tar.gz topgrade
cd aarch64-unknown-linux-gnu/ || exit 1
tar -czf "../topgrade-${ans}-aarch64-linux-gnu.tar.gz" topgrade
cd ..
cd aarch64-unknown-linux-musl/
tar -czf ../topgrade-${ans}-aarch64-linux-musl.tar.gz topgrade
cd aarch64-unknown-linux-musl/ || exit 1
tar -czf "../topgrade-${ans}-aarch64-linux-musl.tar.gz" topgrade
cd ..
cd x86_64-pc-windows-gnu/
zip -q ../topgrade-${ans}-x86_64-windows.zip topgrade.exe
cd x86_64-pc-windows-gnu/ || exit 1
zip -q "../topgrade-${ans}-x86_64-windows.zip" topgrade.exe
cd ..
cd ..
@@ -65,17 +66,19 @@ package_function() {
print_checksums() {
cd build/
sha256sum topgrade-${ans}-*
cd build/ || exit 1
sha256sum topgrade-"${ans}"-*
cd ../
}
while true; do
echo "You should always have a look on scripts you download from the internet."
# shellcheck disable=SC2162
read -p "Do you still want to proceed? (y/n) " yn
echo -n "Input version number: "
# shellcheck disable=SC2162
read ans
mkdir build

5
clippy.toml Normal file
View File

@@ -0,0 +1,5 @@
disallowed-methods = [
{ path = "std::process::Command::output", reason = "Use `output_checked[_with][_utf8]`" },
{ path = "std::process::Command::spawn", reason = "Use `spawn_checked`" },
{ path = "std::process::Command::status", reason = "Use `status_checked`" },
]

View File

@@ -1,113 +1,406 @@
# Don't ask for confirmations
#assume_yes = true
# Include any additional configuration file(s)
# [include] sections are processed in the order you write them
# Files in $CONFIG_DIR/topgrade.d/ are automatically included before this file
[include]
# paths = ["/etc/topgrade.toml"]
[misc]
# On Unix systems, Topgrade should not be run as root, it
# will run commands with sudo or equivalent where needed.
# Set this to true to suppress the warning and confirmation
# prompt if Topgrade detects it is being run as root.
# (default: false)
# allow_root = false
# Run `sudo -v` to cache credentials at the start of the run
# This avoids a blocking password prompt in the middle of an unattended run
# (default: false)
# pre_sudo = false
# Sudo command to be used
# sudo_command = "sudo"
# Disable specific steps - same options as the command line flag
#disable = ["system", "emacs"]
# disable = ["system", "emacs"]
# Ignore failures for these steps
#ignore_failures = ["powershell"]
# Run specific steps - same options as the command line flag
#only = ["system", "emacs"]
# Do not ask to retry failed steps (default: false)
#no_retry = true
# Run inside tmux
#run_in_tmux = true
# ignore_failures = ["powershell"]
# List of remote machines with Topgrade installed on them
#remote_topgrades = ["toothless", "pi", "parnas"]
# Arguments to pass SSH when upgrading remote systems
#ssh_arguments = "-o ConnectTimeout=2"
# remote_topgrades = ["toothless", "pi", "parnas"]
# Path to Topgrade executable on remote machines
#remote_topgrade_path = ".cargo/bin/topgrade"
# remote_topgrade_path = ".cargo/bin/topgrade"
# Arguments to pass to SSH when upgrading remote systems
# ssh_arguments = "-o ConnectTimeout=2"
# Arguments to pass tmux when pulling Repositories
#tmux_arguments = "-S /var/tmux.sock"
# tmux_arguments = "-S /var/tmux.sock"
# Do not set the terminal title
#set_title = false
# Do not set the terminal title (default: true)
# set_title = true
# Display the time in step titles
# Display the time in step titles (default: true)
# display_time = true
# Cleanup temporary or old files
#cleanup = true
# Don't ask for confirmations (no default value)
# assume_yes = true
# Skip sending a notification at the end of a run
#skip_notify = true
# Do not ask to retry failed steps (default: false)
# no_retry = true
[git]
#max_concurrency = 5
# Additional git repositories to pull
#repos = [
# "~/src/*/",
# "~/.config/something"
#]
# Show the reason for skipped steps (default: false)
# This has no effect if the "only" option is specified
# show_skipped = true
# Don't pull the predefined git repos
#pull_predefined = false
# Run inside tmux (default: false)
# run_in_tmux = true
# Arguments to pass Git when pulling Repositories
#arguments = "--rebase --autostash"
# Changes the way topgrade interacts with
# the tmux session, creating the session
# and only attaching to it if not inside tmux
# (default: "attach_if_not_in_session", allowed values: "attach_if_not_in_session", "attach_always")
# tmux_session_mode = "attach_if_not_in_session"
# Cleanup temporary or old files (default: false)
# cleanup = true
# Send a notification for every step (default: false)
# notify_each_step = false
# Skip sending a notification at the end of a run (default: false)
# skip_notify = true
# The Bash-it branch to update (default: "stable")
# bashit_branch = "stable"
# Run specific steps - same options as the command line flag
# only = ["system", "emacs"]
# Whether to self update
#
# this will be ignored if the binary is built without self update support
#
# available also via setting the environment variable TOPGRADE_NO_SELF_UPGRADE)
# no_self_update = true
# Extra tracing filter directives
# These are prepended to the `--log-filter` argument
# See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
# log_filters = ["topgrade::command=debug", "warn"]
# Whether to show a distribution-specific summary if applicable, e.g. listing
# Pacman backup configuration files (*.pacsave and *.pacnew)
# (default: true)
# show_distribution_summary = false
[composer]
#self_update = true
# Commands to run before anything
[pre_commands]
#"Emacs Snapshot" = "rm -rf ~/.emacs.d/elpa.bak && cp -rl ~/.emacs.d/elpa ~/.emacs.d/elpa.bak"
# "Emacs Snapshot" = "rm -rf ~/.emacs.d/elpa.bak && cp -rl ~/.emacs.d/elpa ~/.emacs.d/elpa.bak"
# Commands to run after anything
[post_commands]
# "Emacs Snapshot" = "rm -rf ~/.emacs.d/elpa.bak && cp -rl ~/.emacs.d/elpa ~/.emacs.d/elpa.bak"
# Custom commands
[commands]
#"Python Environment" = "~/dev/.env/bin/pip install -i https://pypi.python.org/simple -U --upgrade-strategy eager jupyter"
# "Python Environment" = "~/dev/.env/bin/pip install -i https://pypi.python.org/simple -U --upgrade-strategy eager jupyter"
# "Custom command using interactive shell (unix)" = "-i vim_upgrade"
[python]
# enable_pip_review = true ###disabled by default
# enable_pip_review_local = true ###disabled by default
# enable_pipupgrade = true ###disabled by default
# pipupgrade_arguments = "-y -u --pip-path pip" ###disabled by default
# For the poetry step, by default, Topgrade skips its update if poetry is not
# installed with the official script. This configuration entry forces Topgrade
# to run the update in this case.
#
# (default: false)
# poetry_force_self_update = true
[conda]
# Additional named conda environments to update (`conda env update -n env_name`)
# env_names = [
# "Toolbox",
# "PyTorch"
# ]
# Additional conda environment paths to update (`conda env update -p env_path`)
# env_paths = [
# "~/webserver/.conda/",
# "~/experiments/.conda/"
# ]
[composer]
# self_update = true
[brew]
#greedy_cask = true
#autoremove = true
# For the BrewCask step
# If `Repo Cask Upgrade` exists, then use the `-a` option.
# Otherwise, use the `--greedy` option.
# greedy_cask = true
# For the BrewCask step
# If `Repo Cask Upgrade` does not exist, then use the `--greedy_latest` option.
# NOTE: the above entry `greedy_cask` contains this entry, though you can enable
# both of them, they won't clash with each other.
# greedy_latest = true
# For the BrewCask step
# If `Repo Cask Upgrade` does not exist, then use the `--greedy_auto_updates` option.
# NOTE: the above entry `greedy_cask` contains this entry, though you can enable
# both of them, they won't clash with each other.
# greedy_auto_updates = true
# For the BrewFormula step
# Execute `brew autoremove` after the step.
# autoremove = true
# For the BrewFormula step
# Upgrade formulae built from the HEAD branch; `brew upgrade --fetch-HEAD`
# fetch_head = true
[linux]
# Arch Package Manager to use. Allowed values: autodetect, trizen, aura, paru, yay, pikaur, pacman, pamac.
#arch_package_manager = "pacman"
# Arch Package Manager to use.
# Allowed values:
# autodetect, aura, garuda_update, pacman, pamac, paru, pikaur, trizen, yay
# arch_package_manager = "pacman"
# Arguments to pass yay (or paru) when updating packages
#yay_arguments = "--nodevel"
#aura_aur_arguments = "-kx"
#aura_pacman_arguments = ""
#show_arch_news = true
#trizen_arguments = "--devel"
#pikaur_arguments = ""
#pamac_arguments = "--no-devel"
#enable_tlmgr = true
#emerge_sync_flags = "-q"
#emerge_update_flags = "-uDNa --with-bdeps=y world"
#redhat_distro_sync = false
#rpm_ostree = false
# yay_arguments = "--nodevel"
# Arguments to pass dnf when updating packages
# dnf_arguments = "--refresh"
# aura_aur_arguments = "-kx"
# aura_pacman_arguments = ""
# garuda_update_arguments = ""
# show_arch_news = true
# trizen_arguments = "--devel"
# pikaur_arguments = ""
# pamac_arguments = "--no-devel"
# enable_tlmgr = true
# emerge_sync_flags = "-q"
# emerge_update_flags = "-uDNa --with-bdeps=y world"
# redhat_distro_sync = false
# suse_dup = false
# rpm_ostree = false
# For Fedora/CentOS/RHEL Atomic variants, if `bootc` is available and this configuration entry is set to true, use
# it to do the update - Will also supersede rpm-ostree if enabled
# (default: false)
# bootc = false
# nix_arguments = "--flake"
# nix_env_arguments = "--prebuilt-only"
# Extra Home Manager arguments
# home_manager_arguments = ["--flake", "file"]
[mandb]
# Enable the mandb step (to update manual entries).
# Mandb is updated in the background by a service on most systems by default.
# (default: false)
# enable = true
[pkgfile]
# Enable the pkgfile step (to update the pkgfile database).
# Pkgfile is sometimes installed by default, but often not used and heavy to update.
# (default: false)
# enable = true
[git]
# How many repos to pull at max in parallel
# max_concurrency = 5
# Additional git repositories to pull
# repos = [
# "~/src/*/",
# "~/.config/something"
# ]
# Don't pull the predefined git repos
# pull_predefined = false
# Arguments to pass Git when pulling Repositories
# arguments = "--rebase --autostash"
[windows]
# Manually select Windows updates
#accept_all_updates = false
#open_remotes_in_new_terminal = true
# accept_all_updates = false
# Controls whether to automatically reboot the computer when updates are
# installed that request it. (default: "no", allowed values: "yes", "no", "ask")
# updates_auto_reboot = "yes"
# open_remotes_in_new_terminal = true
# wsl_update_pre_release = true
# wsl_update_use_web_download = true
# The default for winget_install_silently is true,
# this example turns off silent install.
# winget_install_silently = false
# Causes Topgrade to rename itself during the run to allow package managers
# to upgrade it. Use this only if you installed Topgrade by using a package
# manager such as Scoop or Cargo
#self_rename = true
# self_rename = true
# Use sudo to elevate privileges for the Windows Package Manager (winget)
# Only use this option if you want to run the Winget step in sudo-mode.
# Running winget in sudo-mode is generally not recommended, as not every
# package supports installing / upgrading in sudo-mode and it may cause issues
# with some packages or may even cause the Winget-step to fail.
# If any problems occur, please try running Topgrade without this option first
# before reporting an issue.
# (default: false)
# winget_use_sudo = true
[chezmoi]
# Exclude encrypted files from update
# (default: false)
# exclude_encrypted = false
[npm]
# Use sudo if the NPM directory isn't owned by the current user
#use_sudo = true
# use_sudo = true
[yarn]
# Run `yarn global upgrade` with `sudo`
# use_sudo = true
[deno]
# Upgrade deno executable to the given version.
# version = "stable"
[vim]
# For `vim-plug`, execute `PlugUpdate!` instead of `PlugUpdate`
# force_plug_update = true
[firmware]
# Offer to update firmware; if false just check for and display available updates
#upgrade = true
# upgrade = true
[vagrant]
# Vagrant directories
# directories = []
# power on vagrant boxes if needed
# power_on = true
# Always suspend vagrant boxes instead of powering off
# always_suspend = true
[flatpak]
# Use sudo for updating the system-wide installation
#use_sudo = true
# use_sudo = true
[distrobox]
#use_root = false
#containers = ["archlinux-latest"]
# use_root = false
# containers = ["archlinux-latest"]
[containers]
# Specify the containers to ignore while updating (Wildcard supported)
# ignored_containers = ["ghcr.io/rancher-sandbox/rancher-desktop/rdx-proxy:latest", "docker.io*"]
# Specify the runtime to use for containers (default: "docker", allowed values: "docker", "podman")
# runtime = "podman"
[lensfun]
# If disabled, Topgrade invokes `lensfunupdatedata` without root privilege,
# then the update will be only available to you. Otherwise, `sudo` is required,
# and the update will be installed system-wide, i.e., available to all users.
# (default: false)
# use_sudo = false
[julia]
# If disabled, Topgrade invokes julia with the --startup-file=no CLI option.
#
# This may be desirable to avoid loading outdated packages with "using" directives
# in the startup file, which might cause the update run to fail.
# (default: true)
# startup_file = true
[zigup]
# Version strings passed to zigup.
# These may be pinned versions such as "0.13.0" or branches such as "master".
# Each one will be updated in its own zigup invocation.
# (default: ["master"])
# target_versions = ["master", "0.13.0"]
# Specifies the directory that the zig files will be installed to.
# If defined, passed with the --install-dir command line flag.
# If not defined, zigup will use its default behaviour.
# (default: not defined)
# install_dir = "~/.zig"
# Specifies the path of the symlink which will be set to point at the default compiler version.
# If defined, passed with the --path-link command line flag.
# If not defined, zigup will use its default behaviour.
# This is not meaningful if set_default is not enabled.
# (default: not defined)
# path_link = "~/.bin/zig"
# If enabled, run `zigup clean` after updating all versions.
# If enabled, each updated version above will be marked with `zigup keep`.
# (default: false)
# cleanup = false
[vscode]
# If this is set and is a non-empty string, it specifies the profile the
# extensions should be updated for.
# (default: this won't be set by default)
# profile = ""
[pixi]
# Show the release notes of the latest pixi release
# during the pixi step
# (default: false)
# include_release_notes = false
[doom]
# If this is set to true, the `--aot` flag is added to `doom upgrade`,
# which enables ahead-of-time native compilation of packages.
# (default: false)
# aot = true
[rustup]
# If set, updates only these channels.
# (default: [] (all channels))
# channels = ["stable"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 718 KiB

BIN
doc/topgrade_demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

1412
locales/app.yml Normal file

File diff suppressed because it is too large Load Diff

17
pyproject.toml Normal file
View File

@@ -0,0 +1,17 @@
[build-system]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"
[project]
name = "topgrade"
dynamic = ["version"]
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
[tool.maturin]
bindings = "bin"

10
renovate.json Normal file
View File

@@ -0,0 +1,10 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:best-practices",
":semanticCommits"
],
"lockFileMaintenance": {
"enabled": true
}
}

2
rust-toolchain.toml Normal file
View File

@@ -0,0 +1,2 @@
[toolchain]
channel = "1.84.1"

171
src/breaking_changes.rs Normal file
View File

@@ -0,0 +1,171 @@
//! Inform the users of the breaking changes introduced in this major release.
//!
//! Print the breaking changes and possibly a migration guide when:
//! 1. The Topgrade being executed is a new major release
//! 2. This is the first launch of that major release
use crate::terminal::print_separator;
#[cfg(windows)]
use crate::WINDOWS_DIRS;
#[cfg(unix)]
use crate::XDG_DIRS;
use color_eyre::eyre::Result;
use etcetera::base_strategy::BaseStrategy;
use rust_i18n::t;
use std::{
env::var,
fs::{read_to_string, OpenOptions},
io::Write,
path::PathBuf,
str::FromStr,
};
/// Version string x.y.z
static VERSION_STR: &str = env!("CARGO_PKG_VERSION");
/// Version info
#[derive(Debug)]
pub(crate) struct Version {
_major: u64,
minor: u64,
patch: u64,
}
impl FromStr for Version {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
const NOT_SEMVER: &str = "Topgrade version is not semantic";
const NOT_NUMBER: &str = "Topgrade version is not dot-separated numbers";
let mut iter = s.split('.').take(3);
let major = iter.next().expect(NOT_SEMVER).parse().expect(NOT_NUMBER);
let minor = iter.next().expect(NOT_SEMVER).parse().expect(NOT_NUMBER);
let patch = iter.next().expect(NOT_SEMVER).parse().expect(NOT_NUMBER);
// They cannot be all 0s
assert!(
!(major == 0 && minor == 0 && patch == 0),
"Version numbers cannot be all 0s"
);
Ok(Self {
_major: major,
minor,
patch,
})
}
}
impl Version {
/// True if this version is a new major release.
pub(crate) fn is_new_major_release(&self) -> bool {
// We have already checked that they cannot all be zeros, so `self.major`
// is guaranteed to be non-zero.
self.minor == 0 && self.patch == 0
}
}
/// Topgrade's breaking changes
///
/// We store them in the compiled binary.
pub(crate) static BREAKINGCHANGES: &str = include_str!("../BREAKINGCHANGES.md");
/// Return platform's data directory.
fn data_dir() -> PathBuf {
#[cfg(unix)]
return XDG_DIRS.data_dir();
#[cfg(windows)]
return WINDOWS_DIRS.data_dir();
}
/// Return Topgrade's keep file path.
///
/// keep file is a file under the data directory containing a major version
/// number, it will be created on first run and is used to check if an execution
/// of Topgrade is the first run of a major release, for more details, see
/// `first_run_of_major_release()`.
fn keep_file_path() -> PathBuf {
let keep_file = "topgrade_keep";
data_dir().join(keep_file)
}
/// If environment variable `TOPGRADE_SKIP_BRKC_NOTIFY` is set to `true`, then
/// we won't notify the user of the breaking changes.
pub(crate) fn should_skip() -> bool {
if let Ok(var) = var("TOPGRADE_SKIP_BRKC_NOTIFY") {
return var.as_str() == "true";
}
false
}
/// True if this is the first execution of a major release.
pub(crate) fn first_run_of_major_release() -> Result<bool> {
let version = VERSION_STR.parse::<Version>().expect("should be a valid version");
let keep_file = keep_file_path();
// disable this lint here as the current code has better readability
#[allow(clippy::collapsible_if)]
if version.is_new_major_release() {
if !keep_file.exists() || read_to_string(&keep_file)? != VERSION_STR {
return Ok(true);
}
}
Ok(false)
}
/// Print breaking changes to the user.
pub(crate) fn print_breaking_changes() {
let header = format!(
"{}",
t!("Topgrade {version_str} Breaking Changes", version_str = VERSION_STR)
);
print_separator(header);
let contents = if BREAKINGCHANGES.is_empty() {
t!("No Breaking changes").to_string()
} else {
BREAKINGCHANGES.to_string()
};
println!("{contents}\n");
}
/// This function will be ONLY executed when the user has confirmed the breaking
/// changes, once confirmed, we write the keep file, which means the first run
/// of this major release is finished.
pub(crate) fn write_keep_file() -> Result<()> {
std::fs::create_dir_all(data_dir())?;
let keep_file = keep_file_path();
let mut file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(keep_file)?;
let _ = file.write(VERSION_STR.as_bytes())?;
Ok(())
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn is_new_major_release_works() {
let first_major_release: Version = "1.0.0".parse().unwrap();
let under_dev: Version = "0.1.0".parse().unwrap();
assert!(first_major_release.is_new_major_release());
assert!(!under_dev.is_new_major_release());
}
#[test]
#[should_panic(expected = "Version numbers cannot be all 0s")]
fn invalid_version() {
let all_0 = "0.0.0";
all_0.parse::<Version>().unwrap();
}
}

250
src/command.rs Normal file
View File

@@ -0,0 +1,250 @@
//! Utilities for running commands and providing user-friendly error messages.
use std::fmt::Display;
use std::process::Child;
use std::process::{Command, ExitStatus, Output};
use color_eyre::eyre;
use color_eyre::eyre::eyre;
use color_eyre::eyre::Context;
use crate::error::TopgradeError;
use tracing::debug;
/// Like [`Output`], but UTF-8 decoded.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Utf8Output {
pub status: ExitStatus,
pub stdout: String,
pub stderr: String,
}
impl TryFrom<Output> for Utf8Output {
type Error = eyre::Error;
fn try_from(Output { status, stdout, stderr }: Output) -> Result<Self, Self::Error> {
let stdout = String::from_utf8(stdout).map_err(|err| {
eyre!(
"Stdout contained invalid UTF-8: {}",
String::from_utf8_lossy(err.as_bytes())
)
})?;
let stderr = String::from_utf8(stderr).map_err(|err| {
eyre!(
"Stderr contained invalid UTF-8: {}",
String::from_utf8_lossy(err.as_bytes())
)
})?;
Ok(Utf8Output { status, stdout, stderr })
}
}
impl TryFrom<&Output> for Utf8Output {
type Error = eyre::Error;
fn try_from(Output { status, stdout, stderr }: &Output) -> Result<Self, Self::Error> {
let stdout = String::from_utf8(stdout.clone()).map_err(|err| {
eyre!(
"Stdout contained invalid UTF-8: {}",
String::from_utf8_lossy(err.as_bytes())
)
})?;
let stderr = String::from_utf8(stderr.clone()).map_err(|err| {
eyre!(
"Stderr contained invalid UTF-8: {}",
String::from_utf8_lossy(err.as_bytes())
)
})?;
let status = *status;
Ok(Utf8Output { status, stdout, stderr })
}
}
impl Display for Utf8Output {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.stdout)
}
}
/// Extension trait for [`Command`], adding helpers to gather output while checking the exit
/// status.
///
/// These also give us significantly better error messages, which include:
///
/// 1. The command and arguments that were executed, escaped with familiar `sh` syntax.
/// 2. The exit status of the command or the signal that killed it.
/// 3. If we were capturing the output of the command, rather than forwarding it to the user's
/// stdout/stderr, the error message includes the command's stdout and stderr output.
///
/// Additionally, executing commands with these methods will log the command at debug-level,
/// useful when gathering error reports.
pub trait CommandExt {
type Child;
/// Like [`Command::output`], but checks the exit status and provides nice error messages.
///
/// Returns an `Err` if the command failed to execute or returned a non-zero exit code.
#[track_caller]
fn output_checked(&mut self) -> eyre::Result<Output> {
self.output_checked_with(|output: &Output| if output.status.success() { Ok(()) } else { Err(()) })
}
/// Like [`output_checked`], but also decodes Stdout and Stderr as UTF-8.
///
/// Returns an `Err` if the command failed to execute, returned a non-zero exit code, or if the
/// output contains invalid UTF-8.
#[track_caller]
fn output_checked_utf8(&mut self) -> eyre::Result<Utf8Output> {
let output = self.output_checked()?;
output.try_into()
}
/// Like [`output_checked`] but a closure determines if the command failed instead of
/// [`ExitStatus::success`].
///
/// Returns an `Err` if the command failed to execute or if `succeeded` returns an `Err`.
/// (This lets the caller substitute their own notion of "success" instead of assuming
/// non-zero exit codes indicate success.)
#[track_caller]
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> eyre::Result<Output>;
/// Like [`output_checked_with`], but also decodes Stdout and Stderr as UTF-8.
///
/// Returns an `Err` if the command failed to execute, if `succeeded` returns an `Err`, or if
/// the output contains invalid UTF-8.
// This function is currently unused, but is useful and makes sense with `output_checked_with`
// and `output_checked_utf8` existing.
#[allow(dead_code)]
#[track_caller]
fn output_checked_with_utf8(
&mut self,
succeeded: impl Fn(&Utf8Output) -> Result<(), ()>,
) -> eyre::Result<Utf8Output> {
// This decodes the Stdout and Stderr as UTF-8 twice...
let output =
self.output_checked_with(|output| output.try_into().map_err(|_| ()).and_then(|o| succeeded(&o)))?;
output.try_into()
}
/// Like [`Command::status`], but gives a nice error message if the status is unsuccessful
/// rather than returning the [`ExitStatus`].
///
/// Returns `Ok` if the command executes successfully, returns `Err` if the command fails to
/// execute or returns a non-zero exit code.
#[track_caller]
fn status_checked(&mut self) -> eyre::Result<()> {
self.status_checked_with(|status| if status.success() { Ok(()) } else { Err(()) })
}
/// Like [`status_checked`], but gives a nice error message if the status is unsuccessful
/// rather than returning the [`ExitStatus`].
///
/// Returns `Ok` if the command executes successfully, returns `Err` if the command fails to
/// execute or if `succeeded` returns an `Err`.
/// (This lets the caller substitute their own notion of "success" instead of assuming
/// non-zero exit codes indicate success.)
#[track_caller]
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> eyre::Result<()>;
/// Like [`Command::spawn`], but gives a nice error message if the command fails to
/// execute.
#[track_caller]
#[allow(dead_code)]
fn spawn_checked(&mut self) -> eyre::Result<Self::Child>;
}
impl CommandExt for Command {
type Child = Child;
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> eyre::Result<Output> {
let command = log(self);
// This is where we implement `output_checked`, which is what we prefer to use instead of
// `output`, so we allow `Command::output` here.
#[allow(clippy::disallowed_methods)]
let output = self
.output()
.with_context(|| format!("Failed to execute `{command}`"))?;
if succeeded(&output).is_ok() {
Ok(output)
} else {
let mut message = format!("Command failed: `{command}`");
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
let stdout_trimmed = stdout.trim();
if !stdout_trimmed.is_empty() {
message.push_str(&format!("\n\nStdout:\n{stdout_trimmed}"));
}
let stderr_trimmed = stderr.trim();
if !stderr_trimmed.is_empty() {
message.push_str(&format!("\n\nStderr:\n{stderr_trimmed}"));
}
let (program, _) = get_program_and_args(self);
let err = TopgradeError::ProcessFailedWithOutput(program, output.status, stderr.into_owned());
let ret = Err(err).with_context(|| message);
debug!("Command failed: {ret:?}");
ret
}
}
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> eyre::Result<()> {
let command = log(self);
let message = format!("Failed to execute `{command}`");
// This is where we implement `status_checked`, which is what we prefer to use instead of
// `status`, so we allow `Command::status` here.
#[allow(clippy::disallowed_methods)]
let status = self.status().with_context(|| message.clone())?;
if succeeded(status).is_ok() {
Ok(())
} else {
let (program, _) = get_program_and_args(self);
let err = TopgradeError::ProcessFailed(program, status);
let ret = Err(err).with_context(|| format!("Command failed: `{command}`"));
debug!("Command failed: {ret:?}");
ret
}
}
fn spawn_checked(&mut self) -> eyre::Result<Self::Child> {
let command = log(self);
let message = format!("Failed to execute `{command}`");
// This is where we implement `spawn_checked`, which is what we prefer to use instead of
// `spawn`, so we allow `Command::spawn` here.
#[allow(clippy::disallowed_methods)]
{
self.spawn().with_context(|| message.clone())
}
}
}
fn get_program_and_args(cmd: &Command) -> (String, String) {
// We're not doing anything weird with commands that are invalid UTF-8 so this is fine.
let program = cmd.get_program().to_string_lossy().into_owned();
let args = shell_words::join(cmd.get_args().map(|arg| arg.to_string_lossy()));
(program, args)
}
fn format_program_and_args(cmd: &Command) -> String {
let (program, args) = get_program_and_args(cmd);
if args.is_empty() {
program
} else {
format!("{program} {args}")
}
}
fn log(cmd: &Command) -> String {
let command = format_program_and_args(cmd);
debug!("Executing command `{command}`");
command
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,7 @@
use lazy_static::lazy_static;
use std::sync::atomic::{AtomicBool, Ordering};
lazy_static! {
/// A global variable telling whether the application has been interrupted.
static ref INTERRUPTED: AtomicBool = AtomicBool::new(false);
}
/// A global variable telling whether the application has been interrupted.
static INTERRUPTED: AtomicBool = AtomicBool::new(false);
/// Tells whether the program has been interrupted
pub fn interrupted() -> bool {
@@ -14,9 +11,9 @@ pub fn interrupted() -> bool {
/// Clears the interrupted flag
pub fn unset_interrupted() {
debug_assert!(INTERRUPTED.load(Ordering::SeqCst));
INTERRUPTED.store(false, Ordering::SeqCst)
INTERRUPTED.store(false, Ordering::SeqCst);
}
pub fn set_interrupted() {
INTERRUPTED.store(true, Ordering::SeqCst)
INTERRUPTED.store(true, Ordering::SeqCst);
}

View File

@@ -1,21 +1,17 @@
//! SIGINT handling in Unix systems.
use crate::ctrlc::interrupted::set_interrupted;
use nix::sys::signal;
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
/// Handle SIGINT. Set the interruption flag.
extern "C" fn handle_sigint(_: i32) {
set_interrupted()
set_interrupted();
}
/// Set the necessary signal handlers.
/// The function panics on failure.
pub fn set_handler() {
let sig_action = signal::SigAction::new(
signal::SigHandler::Handler(handle_sigint),
signal::SaFlags::empty(),
signal::SigSet::empty(),
);
let sig_action = SigAction::new(SigHandler::Handler(handle_sigint), SaFlags::empty(), SigSet::empty());
unsafe {
signal::sigaction(signal::SIGINT, &sig_action).unwrap();
sigaction(Signal::SIGINT, &sig_action).unwrap();
}
}

View File

@@ -1,21 +1,21 @@
//! A stub for Ctrl + C handling.
use crate::ctrlc::interrupted::set_interrupted;
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
use winapi::um::consoleapi::SetConsoleCtrlHandler;
use winapi::um::wincon::CTRL_C_EVENT;
use tracing::error;
use windows::core::BOOL;
use windows::Win32::System::Console::{SetConsoleCtrlHandler, CTRL_C_EVENT};
extern "system" fn handler(ctrl_type: DWORD) -> BOOL {
extern "system" fn handler(ctrl_type: u32) -> BOOL {
match ctrl_type {
CTRL_C_EVENT => {
set_interrupted();
TRUE
true.into()
}
_ => FALSE,
_ => false.into(),
}
}
pub fn set_handler() {
if 0 == unsafe { SetConsoleCtrlHandler(Some(handler), TRUE) } {
log::error!("Cannot set a control C handler")
if let Err(e) = unsafe { SetConsoleCtrlHandler(Some(handler), true) } {
error!("Cannot set a control C handler: {e}")
}
}

View File

@@ -1,41 +1,118 @@
use std::process::ExitStatus;
use std::{fmt::Display, process::ExitStatus};
use rust_i18n::t;
use thiserror::Error;
use crate::sudo::SudoKind;
#[derive(Error, Debug, PartialEq, Eq)]
pub enum TopgradeError {
#[error("{0}")]
ProcessFailed(ExitStatus),
ProcessFailed(String, ExitStatus),
#[error("{0}: {1}")]
ProcessFailedWithOutput(ExitStatus, String),
ProcessFailedWithOutput(String, ExitStatus, String),
#[error("Sudo is required for this step")]
#[allow(dead_code)]
SudoRequired,
#[error("Unknown Linux Distribution")]
#[cfg(target_os = "linux")]
UnknownLinuxDistribution,
#[error("Failed getting the system package manager")]
#[cfg(target_os = "linux")]
EmptyOSReleaseFile,
#[cfg(target_os = "linux")]
FailedGettingPackageManager,
}
impl Display for TopgradeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TopgradeError::ProcessFailed(process, exit_status) => {
write!(
f,
"{}",
t!(
"`{process}` failed: {exit_status}",
process = process,
exit_status = exit_status
)
)
}
TopgradeError::ProcessFailedWithOutput(process, exit_status, output) => {
write!(
f,
"{}",
t!(
"`{process}` failed: {exit_status} with {output}",
process = process,
exit_status = exit_status,
output = output
)
)
}
#[cfg(target_os = "linux")]
TopgradeError::UnknownLinuxDistribution => write!(f, "{}", t!("Unknown Linux Distribution")),
#[cfg(target_os = "linux")]
TopgradeError::EmptyOSReleaseFile => {
write!(f, "{}", t!("File \"/etc/os-release\" does not exist or is empty"))
}
#[cfg(target_os = "linux")]
TopgradeError::FailedGettingPackageManager => {
write!(f, "{}", t!("Failed getting the system package manager"))
}
}
}
}
#[derive(Error, Debug)]
#[error("A step failed")]
pub struct StepFailed;
impl Display for StepFailed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", t!("A step failed"))
}
}
#[derive(Error, Debug)]
pub struct UnsupportedSudo<'a> {
pub sudo_kind: SudoKind,
pub option: &'a str,
}
impl Display for UnsupportedSudo<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
t!(
"{sudo_kind} does not support the {option} option",
sudo_kind = self.sudo_kind,
option = self.option
)
)
}
}
#[derive(Error, Debug)]
pub struct MissingSudo();
impl Display for MissingSudo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", t!("Could not find sudo"))
}
}
#[derive(Error, Debug)]
#[error("Dry running")]
pub struct DryRun();
impl Display for DryRun {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", t!("Dry running"))
}
}
#[derive(Error, Debug)]
#[error("{0}")]
pub struct SkipStep(pub String);
#[cfg(all(windows, feature = "self-update"))]
#[derive(Error, Debug)]
#[error("Topgrade Upgraded")]
pub struct Upgraded(pub ExitStatus);
impl Display for SkipStep {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

View File

@@ -1,70 +1,135 @@
#![allow(dead_code)]
use crate::executor::RunType;
use crate::git::Git;
use std::env::var;
use std::ffi::OsStr;
use std::process::Command;
use std::sync::{LazyLock, Mutex};
use clap::ValueEnum;
use color_eyre::eyre::Result;
use rust_i18n::t;
use serde::Deserialize;
use strum::EnumString;
use crate::config::Config;
use crate::error::MissingSudo;
use crate::executor::{DryCommand, Executor};
use crate::powershell::Powershell;
#[cfg(target_os = "linux")]
use crate::steps::linux::Distribution;
use crate::sudo::Sudo;
use crate::utils::require_option;
use crate::{config::Config, executor::Executor};
use anyhow::Result;
use directories::BaseDirs;
use std::path::{Path, PathBuf};
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
#[derive(Clone, Copy, Debug, Deserialize, Default, EnumString, ValueEnum)]
pub enum RunType {
/// Executing commands will just print the command with its argument.
Dry,
/// Executing commands will perform actual execution.
#[default]
Wet,
/// Executing commands will print the command and perform actual execution.
Damp,
}
impl RunType {
/// Tells whether we're performing a dry run.
pub fn dry(self) -> bool {
match self {
RunType::Dry => true,
RunType::Wet => false,
RunType::Damp => false,
}
}
}
pub struct ExecutionContext<'a> {
run_type: RunType,
sudo: &'a Option<PathBuf>,
git: &'a Git,
sudo: Option<Sudo>,
config: &'a Config,
base_dirs: &'a BaseDirs,
/// Name of a tmux session to execute commands in, if any.
/// This is used in `./steps/remote/ssh.rs`, where we want to run `topgrade` in a new
/// tmux window for each remote.
tmux_session: Mutex<Option<String>>,
/// True if topgrade is running under ssh.
under_ssh: bool,
#[cfg(target_os = "linux")]
distribution: &'a Result<Distribution>,
powershell: LazyLock<Option<Powershell>>,
}
impl<'a> ExecutionContext<'a> {
pub fn new(
run_type: RunType,
sudo: &'a Option<PathBuf>,
git: &'a Git,
sudo: Option<Sudo>,
config: &'a Config,
base_dirs: &'a BaseDirs,
) -> ExecutionContext<'a> {
ExecutionContext {
#[cfg(target_os = "linux")] distribution: &'a Result<Distribution>,
) -> Self {
let under_ssh = var("SSH_CLIENT").is_ok() || var("SSH_TTY").is_ok();
Self {
run_type,
sudo,
git,
config,
base_dirs,
tmux_session: Mutex::new(None),
under_ssh,
#[cfg(target_os = "linux")]
distribution,
powershell: LazyLock::new(Powershell::new),
}
}
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
let mut cmd = self.run_type.execute(&sudo);
if sudo.ends_with("sudo") {
cmd.arg("--preserve-env=DIFFPROG");
/// Create an instance of `Executor` that should run `program`.
pub fn execute<S: AsRef<OsStr>>(&self, program: S) -> Executor {
match self.run_type {
RunType::Dry => Executor::Dry(DryCommand::new(program)),
RunType::Wet => Executor::Wet(Command::new(program)),
RunType::Damp => Executor::Damp(Command::new(program)),
}
if interactive {
cmd.arg("-i");
}
cmd.arg(command);
Ok(cmd)
}
pub fn run_type(&self) -> RunType {
self.run_type
}
pub fn git(&self) -> &Git {
self.git
pub fn sudo(&self) -> &Option<Sudo> {
&self.sudo
}
pub fn sudo(&self) -> &Option<PathBuf> {
self.sudo
pub fn require_sudo(&self) -> Result<&Sudo> {
if let Some(value) = self.sudo() {
Ok(value)
} else {
Err(MissingSudo().into())
}
}
pub fn config(&self) -> &Config {
self.config
}
pub fn base_dirs(&self) -> &BaseDirs {
self.base_dirs
pub fn under_ssh(&self) -> bool {
self.under_ssh
}
pub fn set_tmux_session(&self, session_name: String) {
self.tmux_session.lock().unwrap().replace(session_name);
}
pub fn get_tmux_session(&self) -> Option<String> {
self.tmux_session.lock().unwrap().clone()
}
#[cfg(target_os = "linux")]
pub fn distribution(&self) -> &Result<Distribution> {
self.distribution
}
pub fn powershell(&self) -> &Option<Powershell> {
&self.powershell
}
pub fn require_powershell(&self) -> Result<&Powershell> {
require_option(self.powershell.as_ref(), t!("Powershell is not installed").to_string())
}
}

View File

@@ -1,65 +1,41 @@
//! Utilities for command execution
use crate::error::{DryRun, TopgradeError};
use crate::utils::{Check, CheckWithCodes};
use anyhow::Result;
use log::{debug, trace};
use std::ffi::{OsStr, OsString};
use std::fmt::Debug;
use std::iter;
use std::path::Path;
use std::process::{Child, Command, ExitStatus};
use std::process::{Child, Command, ExitStatus, Output};
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
#[derive(Clone, Copy, Debug)]
pub enum RunType {
/// Executing commands will just print the command with its argument.
Dry,
use color_eyre::eyre::Result;
use rust_i18n::t;
use tracing::{debug, enabled, Level};
/// Executing commands will perform actual execution.
Wet,
}
impl RunType {
/// Create a new instance from a boolean telling whether to dry run.
pub fn new(dry_run: bool) -> Self {
if dry_run {
RunType::Dry
} else {
RunType::Wet
}
}
/// Create an instance of `Executor` that should run `program`.
pub fn execute<S: AsRef<OsStr>>(self, program: S) -> Executor {
match self {
RunType::Dry => Executor::Dry(DryCommand {
program: program.as_ref().into(),
..Default::default()
}),
RunType::Wet => Executor::Wet(Command::new(program)),
}
}
/// Tells whether we're performing a dry run.
pub fn dry(self) -> bool {
match self {
RunType::Dry => true,
RunType::Wet => false,
}
}
}
use crate::command::CommandExt;
use crate::error::DryRun;
/// An enum providing a similar interface to `std::process::Command`.
/// If the enum is set to `Wet`, execution will be performed with `std::process::Command`.
/// If the enum is set to `Dry`, execution will just print the command with its arguments.
pub enum Executor {
Wet(Command),
Damp(Command),
Dry(DryCommand),
}
impl Executor {
/// Get the name of the program being run.
///
/// Will give weird results for non-UTF-8 programs; see `to_string_lossy()`.
pub fn get_program(&self) -> String {
match self {
Executor::Wet(c) | Executor::Damp(c) => c.get_program().to_string_lossy().into_owned(),
Executor::Dry(c) => c.program.to_string_lossy().into_owned(),
}
}
/// See `std::process::Command::arg`
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Executor {
match self {
Executor::Wet(c) => {
Executor::Wet(c) | Executor::Damp(c) => {
c.arg(arg);
}
Executor::Dry(c) => {
@@ -77,7 +53,7 @@ impl Executor {
S: AsRef<OsStr>,
{
match self {
Executor::Wet(c) => {
Executor::Wet(c) | Executor::Damp(c) => {
c.args(args);
}
Executor::Dry(c) => {
@@ -92,7 +68,7 @@ impl Executor {
/// See `std::process::Command::current_dir`
pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Executor {
match self {
Executor::Wet(c) => {
Executor::Wet(c) | Executor::Damp(c) => {
c.current_dir(dir);
}
Executor::Dry(c) => c.directory = Some(dir.as_ref().into()),
@@ -108,7 +84,7 @@ impl Executor {
K: AsRef<OsStr>,
{
match self {
Executor::Wet(c) => {
Executor::Wet(c) | Executor::Damp(c) => {
c.env_remove(key);
}
Executor::Dry(_) => (),
@@ -125,7 +101,7 @@ impl Executor {
V: AsRef<OsStr>,
{
match self {
Executor::Wet(c) => {
Executor::Wet(c) | Executor::Damp(c) => {
c.env(key, val);
}
Executor::Dry(_) => (),
@@ -136,15 +112,16 @@ impl Executor {
/// See `std::process::Command::spawn`
pub fn spawn(&mut self) -> Result<ExecutorChild> {
self.log_command();
let result = match self {
Executor::Wet(c) => {
Executor::Wet(c) | Executor::Damp(c) => {
debug!("Running {:?}", c);
// We should use `spawn()` here rather than `spawn_checked()` since
// their semantics and behaviors are different.
#[allow(clippy::disallowed_methods)]
c.spawn().map(ExecutorChild::Wet)?
}
Executor::Dry(c) => {
c.dry_run();
ExecutorChild::Dry
}
Executor::Dry(_) => ExecutorChild::Dry,
};
Ok(result)
@@ -152,37 +129,64 @@ impl Executor {
/// See `std::process::Command::output`
pub fn output(&mut self) -> Result<ExecutorOutput> {
self.log_command();
match self {
Executor::Wet(c) => Ok(ExecutorOutput::Wet(c.output()?)),
Executor::Dry(c) => {
c.dry_run();
Ok(ExecutorOutput::Dry)
Executor::Wet(c) | Executor::Damp(c) => {
// We should use `output()` here rather than `output_checked()` since
// their semantics and behaviors are different.
#[allow(clippy::disallowed_methods)]
Ok(ExecutorOutput::Wet(c.output()?))
}
Executor::Dry(_) => Ok(ExecutorOutput::Dry),
}
}
/// A convinence method for `spawn().wait().check()`.
/// Returns an error if something went wrong during the execution or if the
/// process exited with failure.
pub fn check_run(&mut self) -> Result<()> {
self.spawn()?.wait()?.check()
}
/// An extension of `check_run` that allows you to set a sequence of codes
/// An extension of `status_checked` that allows you to set a sequence of codes
/// that can indicate success of a script
#[allow(dead_code)]
pub fn check_run_with_codes(&mut self, codes: &[i32]) -> Result<()> {
self.spawn()?.wait()?.check_with_codes(codes)
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
self.log_command();
match self {
Executor::Wet(c) | Executor::Damp(c) => c.status_checked_with(|status| {
if status.success() || status.code().as_ref().is_some_and(|c| codes.contains(c)) {
Ok(())
} else {
Err(())
}
}),
Executor::Dry(_) => Ok(()),
}
}
fn log_command(&self) {
match self {
Executor::Wet(_) => (),
Executor::Damp(c) => {
log_command(
"Executing: {program_name} {arguments}",
c.get_program(),
c.get_args(),
c.get_envs(),
c.get_current_dir(),
);
}
Executor::Dry(c) => log_command(
"Dry running: {program_name} {arguments}",
&c.program,
&c.args,
iter::empty(),
c.directory.as_ref(),
),
}
}
}
pub enum ExecutorOutput {
Wet(std::process::Output),
Wet(Output),
Dry,
}
/// A struct represending a command. Trying to execute it will just print its arguments.
#[derive(Default)]
/// A struct representing a command. Trying to execute it will just print its arguments.
pub struct DryCommand {
program: OsString,
args: Vec<OsString>,
@@ -190,101 +194,85 @@ pub struct DryCommand {
}
impl DryCommand {
fn dry_run(&self) {
print!(
"Dry running: {} {}",
self.program.to_string_lossy(),
self.args
.iter()
.map(|a| String::from(a.to_string_lossy()))
.collect::<Vec<String>>()
.join(" ")
);
match &self.directory {
Some(dir) => println!(" in {}", dir.to_string_lossy()),
None => println!(),
};
pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
Self {
program: program.as_ref().to_os_string(),
args: Vec::new(),
directory: None,
}
}
}
/// The Result of spawn. Contains an actual `std::process::Child` if executed by a wet command.
pub enum ExecutorChild {
// Both RunType::Wet and RunType::Damp use this variant
#[allow(unused)] // this type has not been used
Wet(Child),
Dry,
}
impl ExecutorChild {
/// See `std::process::Child::wait`
pub fn wait(&mut self) -> Result<ExecutorExitStatus> {
let result = match self {
ExecutorChild::Wet(c) => c.wait().map(ExecutorExitStatus::Wet)?,
ExecutorChild::Dry => ExecutorExitStatus::Dry,
};
Ok(result)
}
}
/// The Result of wait. Contains an actual `std::process::ExitStatus` if executed by a wet command.
pub enum ExecutorExitStatus {
Wet(ExitStatus),
Dry,
}
impl CheckWithCodes for ExecutorExitStatus {
fn check_with_codes(self, codes: &[i32]) -> Result<()> {
match self {
ExecutorExitStatus::Wet(e) => e.check_with_codes(codes),
ExecutorExitStatus::Dry => Ok(()),
}
}
}
/// Extension methods for `std::process::Command`
pub trait CommandExt {
/// Run the command, wait for it to complete, check the return code and decode the output as UTF-8.
fn check_output(&mut self) -> Result<String>;
fn string_output(&mut self) -> Result<String>;
}
impl CommandExt for Command {
fn check_output(&mut self) -> Result<String> {
let output = self.output()?;
trace!("Output of {:?}: {:?}", self, output);
let status = output.status;
if !status.success() {
let stderr = String::from_utf8(output.stderr).unwrap_or_default();
return Err(TopgradeError::ProcessFailedWithOutput(status, stderr).into());
}
Ok(String::from_utf8(output.stdout)?)
}
fn string_output(&mut self) -> Result<String> {
let output = self.output()?;
trace!("Output of {:?}: {:?}", self, output);
Ok(String::from_utf8(output.stdout)?)
}
}
impl CommandExt for Executor {
fn check_output(&mut self) -> Result<String> {
let output = match self.output()? {
ExecutorOutput::Wet(output) => output,
ExecutorOutput::Dry => return Err(DryRun().into()),
};
let status = output.status;
if !status.success() {
let stderr = String::from_utf8(output.stderr).unwrap_or_default();
return Err(TopgradeError::ProcessFailedWithOutput(status, stderr).into());
type Child = ExecutorChild;
// TODO: It might be nice to make `output_checked_with` return something that has a
// variant for wet/dry runs.
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> Result<Output> {
self.log_command();
match self {
Executor::Wet(c) | Executor::Damp(c) => c.output_checked_with(succeeded),
Executor::Dry(_) => Err(DryRun().into()),
}
Ok(String::from_utf8(output.stdout)?)
}
fn string_output(&mut self) -> Result<String> {
let output = match self.output()? {
ExecutorOutput::Wet(output) => output,
ExecutorOutput::Dry => return Err(DryRun().into()),
};
Ok(String::from_utf8(output.stdout)?)
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> Result<()> {
self.log_command();
match self {
Executor::Wet(c) | Executor::Damp(c) => c.status_checked_with(succeeded),
Executor::Dry(_) => Ok(()),
}
}
fn spawn_checked(&mut self) -> Result<Self::Child> {
self.spawn()
}
}
fn log_command<
'a,
I: ExactSizeIterator<Item = (&'a (impl Debug + 'a + ?Sized), Option<&'a (impl Debug + 'a + ?Sized)>)>,
>(
prefix: &str,
exec: &OsStr,
args: impl IntoIterator<Item = &'a (impl AsRef<OsStr> + ?Sized + 'a)>,
env: impl IntoIterator<Item = (&'a OsStr, Option<&'a OsStr>), IntoIter = I>,
dir: Option<&'a (impl AsRef<Path> + ?Sized)>,
) {
println!(
"{}",
t!(
prefix,
program_name = exec.to_string_lossy(),
arguments = shell_words::join(args.into_iter().map(|s| s.as_ref().to_string_lossy()))
)
);
let env_iter = env.into_iter();
if env_iter.len() != 0 && enabled!(Level::DEBUG) {
println!(
" {}",
t!(
"with env: {env}",
env = env_iter
.filter(|(_, val)| val.is_some())
.map(|(key, val)| format!("{:?}={:?}", key, val.unwrap()))
.collect::<Vec<_>>()
.join(" ")
)
)
}
if let Some(d) = dir {
println!(" {}", t!("in {directory}", directory = d.as_ref().display()));
}
}

View File

@@ -2,114 +2,192 @@
use std::env;
use std::io;
use std::path::PathBuf;
use std::process::exit;
use std::time::Duration;
use anyhow::{anyhow, Result};
use crate::breaking_changes::{first_run_of_major_release, print_breaking_changes, should_skip, write_keep_file};
use clap::CommandFactory;
use clap::{crate_version, Parser};
use color_eyre::eyre::Context;
use color_eyre::eyre::Result;
use console::Key;
use log::debug;
use log::LevelFilter;
use pretty_env_logger::formatted_timed_builder;
#[cfg(windows)]
use etcetera::base_strategy::Windows;
#[cfg(unix)]
use etcetera::base_strategy::Xdg;
use rust_i18n::{i18n, t};
use std::sync::LazyLock;
use tracing::debug;
use self::config::{CommandLineArgs, Config, Step};
use self::config::{CommandLineArgs, Config};
use self::error::StepFailed;
#[cfg(all(windows, feature = "self-update"))]
use self::error::Upgraded;
use self::runner::StepResult;
#[allow(clippy::wildcard_imports)]
use self::steps::{remote::*, *};
use self::sudo::{Sudo, SudoCreateError, SudoKind};
#[allow(clippy::wildcard_imports)]
use self::terminal::*;
use self::utils::{install_color_eyre, install_tracing, is_elevated, update_tracing};
mod breaking_changes;
mod command;
mod config;
mod ctrlc;
mod error;
mod execution_context;
mod executor;
mod report;
mod runner;
#[cfg(windows)]
mod self_renamer;
#[cfg(feature = "self-update")]
mod self_update;
mod step;
mod steps;
mod sudo;
mod terminal;
mod utils;
pub(crate) static HOME_DIR: LazyLock<PathBuf> = LazyLock::new(|| home::home_dir().expect("No home directory"));
#[cfg(unix)]
pub(crate) static XDG_DIRS: LazyLock<Xdg> = LazyLock::new(|| Xdg::new().expect("No home directory"));
#[cfg(windows)]
pub(crate) static WINDOWS_DIRS: LazyLock<Windows> = LazyLock::new(|| Windows::new().expect("No home directory"));
// Init and load the i18n files
i18n!("locales", fallback = "en");
#[allow(clippy::too_many_lines)]
fn run() -> Result<()> {
install_color_eyre()?;
ctrlc::set_handler();
let base_dirs = directories::BaseDirs::new().ok_or_else(|| anyhow!("No base directories"))?;
let opt = CommandLineArgs::parse();
// Set up the logger with the filter directives from:
// 1. CLI option `--log-filter`
// 2. `debug` if the `--verbose` option is present
// We do this because we need our logger to work while loading the
// configuration file.
//
// When the configuration file is loaded, update the logger with the full
// filter directives.
//
// For more info, see the comments in `CommandLineArgs::tracing_filter_directives()`
// and `Config::tracing_filter_directives()`.
let reload_handle = install_tracing(&opt.tracing_filter_directives())?;
// Get current system locale and set it as the default locale
let system_locale = sys_locale::get_locale().unwrap_or("en".to_string());
rust_i18n::set_locale(&system_locale);
debug!("Current system locale is {system_locale}");
if let Some(shell) = opt.gen_completion {
let cmd = &mut CommandLineArgs::command();
clap_complete::generate(shell, cmd, clap::crate_name!(), &mut io::stdout());
return Ok(());
}
if opt.gen_manpage {
let man = clap_mangen::Man::new(CommandLineArgs::command());
man.render(&mut io::stdout())?;
return Ok(());
}
for env in opt.env_variables() {
let mut splitted = env.split('=');
let var = splitted.next().unwrap();
let value = splitted.next().unwrap();
let mut parts = env.split('=');
let var = parts.next().unwrap();
let value = parts.next().unwrap();
env::set_var(var, value);
}
let mut builder = formatted_timed_builder();
if opt.verbose {
builder.filter(Some("topgrade"), LevelFilter::Trace);
}
builder.init();
if opt.edit_config() {
Config::edit(&base_dirs)?;
Config::edit()?;
return Ok(());
};
if opt.show_config_reference() {
print!("{}", crate::config::EXAMPLE_CONFIG);
print!("{}", config::EXAMPLE_CONFIG);
return Ok(());
}
let config = Config::load(&base_dirs, opt)?;
terminal::set_title(config.set_title());
terminal::display_time(config.display_time());
terminal::set_desktop_notifications(config.notify_each_step());
let config = Config::load(opt)?;
// Update the logger with the full filter directives.
update_tracing(&reload_handle, &config.tracing_filter_directives())?;
set_title(config.set_title());
display_time(config.display_time());
set_desktop_notifications(config.notify_each_step());
debug!("Version: {}", crate_version!());
debug!("OS: {}", env!("TARGET"));
debug!("{:?}", std::env::args());
debug!("Binary path: {:?}", std::env::current_exe());
debug!("Self Update: {:?}", cfg!(feature = "self-update"));
debug!("{:?}", env::args());
debug!("Binary path: {:?}", env::current_exe());
debug!("self-update Feature Enabled: {:?}", cfg!(feature = "self-update"));
debug!("Configuration: {:?}", config);
if config.run_in_tmux() && env::var("TOPGRADE_INSIDE_TMUX").is_err() {
#[cfg(unix)]
{
tmux::run_in_tmux(config.tmux_arguments());
tmux::run_in_tmux(config.tmux_config()?)?;
return Ok(());
}
}
let git = git::Git::new();
let mut git_repos = git::Repositories::new(&git);
let elevated = is_elevated();
let sudo = utils::sudo();
let run_type = executor::RunType::new(config.dry_run());
#[cfg(unix)]
if !config.allow_root() && elevated {
print_warning(t!(
"Topgrade should not be run as root, it will run commands with sudo or equivalent where needed."
));
if !prompt_yesno(&t!("Continue?"))? {
exit(1)
}
}
let ctx = execution_context::ExecutionContext::new(run_type, &sudo, &git, &config, &base_dirs);
let sudo = match config.sudo_command() {
Some(kind) => Sudo::new(kind),
None if elevated => Sudo::new(SudoKind::Null),
None => Sudo::detect(),
};
debug!("Sudo: {:?}", sudo);
let (sudo, sudo_err) = match sudo {
Ok(sudo) => (Some(sudo), None),
Err(e) => (None, Some(e)),
};
#[cfg(target_os = "linux")]
let distribution = linux::Distribution::detect();
let run_type = config.run_type();
let ctx = execution_context::ExecutionContext::new(
run_type,
sudo,
&config,
#[cfg(target_os = "linux")]
&distribution,
);
let mut runner = runner::Runner::new(&ctx);
#[cfg(feature = "self-update")]
{
if !run_type.dry() && env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() {
let result = self_update::self_update();
// If
//
// 1. the breaking changes notification shouldn't be skipped
// 2. this is the first execution of a major release
//
// inform user of breaking changes
if !should_skip() && first_run_of_major_release()? {
print_breaking_changes();
if let Err(e) = &result {
#[cfg(windows)]
{
if e.downcast_ref::<Upgraded>().is_some() {
return result;
}
}
print_warning(format!("Self update error: {}", e));
}
if prompt_yesno(&t!("Continue?"))? {
write_keep_file()?;
} else {
exit(1);
}
}
step::Step::SelfUpdate.run(&mut runner, &ctx)?;
#[cfg(windows)]
let _self_rename = if config.self_rename() {
Some(crate::self_renamer::SelfRenamer::create()?)
@@ -117,365 +195,113 @@ fn run() -> Result<()> {
None
};
if config.pre_sudo() {
if let Some(sudo) = ctx.sudo() {
sudo.elevate(&ctx)?;
}
}
if let Some(commands) = config.pre_commands() {
for (name, command) in commands {
generic::run_custom_command(name, command, &ctx)?;
}
}
let powershell = powershell::Powershell::new();
let should_run_powershell = powershell.profile().is_some() && config.should_run(Step::Powershell);
#[cfg(windows)]
runner.execute(Step::Wsl, "WSL", || windows::run_wsl_topgrade(&ctx))?;
if let Some(topgrades) = config.remote_topgrades() {
for remote_topgrade in topgrades.iter().filter(|t| config.should_execute_remote(t)) {
runner.execute(Step::Remotes, format!("Remote ({})", remote_topgrade), || {
remote::ssh::ssh_step(&ctx, remote_topgrade)
})?;
}
}
#[cfg(target_os = "linux")]
let distribution = linux::Distribution::detect();
#[cfg(target_os = r#"linux"#)]
{
match &distribution {
Ok(distribution) => {
runner.execute(Step::System, "System update", || distribution.upgrade(&ctx))?;
for step in step::default_steps() {
match step.run(&mut runner, &ctx) {
Ok(()) => (),
Err(error)
if error
.downcast_ref::<io::Error>()
.is_some_and(|e| e.kind() == io::ErrorKind::Interrupted) =>
{
println!();
debug!("Interrupted (possibly with 'q' during retry prompt). Printing summary.");
break;
}
Err(e) => {
println!("Error detecting current distribution: {}", e);
Err(error) => return Err(error),
}
}
let mut failed = false;
let report = runner.report();
if !report.is_empty() {
print_separator(t!("Summary"));
let mut skipped_missing_sudo = false;
for (key, result) in report {
if !failed && result.failed() {
failed = true;
}
}
runner.execute(Step::ConfigUpdate, "config-update", || linux::run_config_update(&ctx))?;
runner.execute(Step::BrewFormula, "Brew", || {
unix::run_brew_formula(&ctx, unix::BrewVariant::Path)
})?;
}
#[cfg(windows)]
{
runner.execute(Step::Chocolatey, "Chocolatey", || windows::run_chocolatey(&ctx))?;
runner.execute(Step::Scoop, "Scoop", || windows::run_scoop(config.cleanup(), run_type))?;
runner.execute(Step::Winget, "Winget", || windows::run_winget(&ctx))?;
}
#[cfg(target_os = "macos")]
{
runner.execute(Step::BrewFormula, "Brew (ARM)", || {
unix::run_brew_formula(&ctx, unix::BrewVariant::MacArm)
})?;
runner.execute(Step::BrewFormula, "Brew (Intel)", || {
unix::run_brew_formula(&ctx, unix::BrewVariant::MacIntel)
})?;
runner.execute(Step::BrewFormula, "Brew", || {
unix::run_brew_formula(&ctx, unix::BrewVariant::Path)
})?;
runner.execute(Step::BrewCask, "Brew Cask (ARM)", || {
unix::run_brew_cask(&ctx, unix::BrewVariant::MacArm)
})?;
runner.execute(Step::BrewCask, "Brew Cask (Intel)", || {
unix::run_brew_cask(&ctx, unix::BrewVariant::MacIntel)
})?;
runner.execute(Step::BrewCask, "Brew Cask", || {
unix::run_brew_cask(&ctx, unix::BrewVariant::Path)
})?;
runner.execute(Step::Macports, "MacPorts", || macos::run_macports(&ctx))?;
}
#[cfg(unix)]
{
runner.execute(Step::Yadm, "yadm", || unix::run_yadm(&ctx))?;
runner.execute(Step::Nix, "nix", || unix::run_nix(&ctx))?;
runner.execute(Step::Guix, "guix", || unix::run_guix(&ctx))?;
runner.execute(Step::HomeManager, "home-manager", || unix::run_home_manager(run_type))?;
runner.execute(Step::Asdf, "asdf", || unix::run_asdf(run_type))?;
runner.execute(Step::Pkgin, "pkgin", || unix::run_pkgin(&ctx))?;
runner.execute(Step::Bun, "bun", || unix::run_bun(&ctx))?;
}
#[cfg(target_os = "dragonfly")]
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
dragonfly::upgrade_packages(sudo.as_ref(), run_type)
})?;
#[cfg(target_os = "freebsd")]
runner.execute(Step::Pkg, "FreeBSD Packages", || {
freebsd::upgrade_packages(sudo.as_ref(), run_type)
})?;
#[cfg(target_os = "openbsd")]
runner.execute(Step::Pkg, "OpenBSD Packages", || {
openbsd::upgrade_packages(sudo.as_ref(), run_type)
})?;
#[cfg(target_os = "android")]
runner.execute(Step::Pkg, "Termux Packages", || android::upgrade_packages(&ctx))?;
let emacs = emacs::Emacs::new(&base_dirs);
if config.use_predefined_git_repos() {
if config.should_run(Step::Emacs) {
if !emacs.is_doom() {
if let Some(directory) = emacs.directory() {
git_repos.insert_if_repo(directory);
}
if let StepResult::SkippedMissingSudo = result {
skipped_missing_sudo = true;
}
git_repos.insert_if_repo(base_dirs.home_dir().join(".doom.d"));
}
if config.should_run(Step::Vim) {
git_repos.insert_if_repo(base_dirs.home_dir().join(".vim"));
git_repos.insert_if_repo(base_dirs.home_dir().join(".config/nvim"));
}
git_repos.insert_if_repo(base_dirs.home_dir().join(".ideavimrc"));
git_repos.insert_if_repo(base_dirs.home_dir().join(".intellimacs"));
if config.should_run(Step::Rcm) {
git_repos.insert_if_repo(base_dirs.home_dir().join(".dotfiles"));
}
#[cfg(unix)]
{
git_repos.insert_if_repo(zsh::zshrc(&base_dirs));
if config.should_run(Step::Tmux) {
git_repos.insert_if_repo(base_dirs.home_dir().join(".tmux"));
}
git_repos.insert_if_repo(base_dirs.home_dir().join(".config/fish"));
git_repos.insert_if_repo(base_dirs.config_dir().join("openbox"));
git_repos.insert_if_repo(base_dirs.config_dir().join("bspwm"));
git_repos.insert_if_repo(base_dirs.config_dir().join("i3"));
git_repos.insert_if_repo(base_dirs.config_dir().join("sway"));
}
#[cfg(windows)]
git_repos.insert_if_repo(
base_dirs
.data_local_dir()
.join("Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState"),
);
#[cfg(windows)]
windows::insert_startup_scripts(&ctx, &mut git_repos).ok();
if let Some(profile) = powershell.profile() {
git_repos.insert_if_repo(profile);
}
}
if config.should_run(Step::GitRepos) {
if let Some(custom_git_repos) = config.git_repos() {
for git_repo in custom_git_repos {
git_repos.glob_insert(git_repo);
}
}
runner.execute(Step::GitRepos, "Git repositories", || {
git.multi_pull_step(&git_repos, &ctx)
})?;
}
if should_run_powershell {
runner.execute(Step::Powershell, "Powershell Modules Update", || {
powershell.update_modules(&ctx)
})?;
}
#[cfg(unix)]
{
runner.execute(Step::Shell, "zr", || zsh::run_zr(&base_dirs, run_type))?;
runner.execute(Step::Shell, "antibody", || zsh::run_antibody(run_type))?;
runner.execute(Step::Shell, "antigen", || zsh::run_antigen(&base_dirs, run_type))?;
runner.execute(Step::Shell, "zgenom", || zsh::run_zgenom(&base_dirs, run_type))?;
runner.execute(Step::Shell, "zplug", || zsh::run_zplug(&base_dirs, run_type))?;
runner.execute(Step::Shell, "zinit", || zsh::run_zinit(&base_dirs, run_type))?;
runner.execute(Step::Shell, "zi", || zsh::run_zi(&base_dirs, run_type))?;
runner.execute(Step::Shell, "zim", || zsh::run_zim(&base_dirs, run_type))?;
runner.execute(Step::Shell, "oh-my-zsh", || zsh::run_oh_my_zsh(&ctx))?;
runner.execute(Step::Shell, "fisher", || unix::run_fisher(&base_dirs, run_type))?;
runner.execute(Step::Shell, "bash-it", || unix::run_bashit(&ctx))?;
runner.execute(Step::Shell, "oh-my-fish", || unix::run_oh_my_fish(&ctx))?;
runner.execute(Step::Shell, "fish-plug", || unix::run_fish_plug(&ctx))?;
runner.execute(Step::Shell, "fundle", || unix::run_fundle(&ctx))?;
runner.execute(Step::Tmux, "tmux", || tmux::run_tpm(&base_dirs, run_type))?;
runner.execute(Step::Tldr, "TLDR", || unix::run_tldr(run_type))?;
runner.execute(Step::Pearl, "pearl", || unix::run_pearl(run_type))?;
#[cfg(not(any(target_os = "macos", target_os = "android")))]
runner.execute(Step::GnomeShellExtensions, "Gnome Shell Extensions", || {
unix::upgrade_gnome_extensions(&ctx)
})?;
runner.execute(Step::Sdkman, "SDKMAN!", || {
unix::run_sdkman(&base_dirs, config.cleanup(), run_type)
})?;
runner.execute(Step::Rcm, "rcm", || unix::run_rcm(&ctx))?;
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly"
)))]
runner.execute(Step::Atom, "apm", || generic::run_apm(run_type))?;
runner.execute(Step::Fossil, "fossil", || generic::run_fossil(run_type))?;
runner.execute(Step::Rustup, "rustup", || generic::run_rustup(&base_dirs, run_type))?;
runner.execute(Step::Dotnet, ".NET", || generic::run_dotnet_upgrade(&ctx))?;
runner.execute(Step::Choosenim, "choosenim", || generic::run_choosenim(&ctx))?;
runner.execute(Step::Cargo, "cargo", || generic::run_cargo_update(&ctx))?;
runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(run_type))?;
runner.execute(Step::Go, "Go", || generic::run_go(run_type))?;
runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?;
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(run_type))?;
runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(run_type))?;
runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?;
runner.execute(Step::Pip3, "pip3", || generic::run_pip3_update(run_type))?;
runner.execute(Step::Ghcup, "ghcup", || generic::run_ghcup_update(run_type))?;
runner.execute(Step::Stack, "stack", || generic::run_stack_update(run_type))?;
runner.execute(Step::Tlmgr, "tlmgr", || generic::run_tlmgr_update(&ctx))?;
runner.execute(Step::Myrepos, "myrepos", || {
generic::run_myrepos_update(&base_dirs, run_type)
})?;
runner.execute(Step::Chezmoi, "chezmoi", || {
generic::run_chezmoi_update(&base_dirs, run_type)
})?;
runner.execute(Step::Jetpack, "jetpack", || generic::run_jetpack(run_type))?;
runner.execute(Step::Vim, "vim", || vim::upgrade_vim(&base_dirs, &ctx))?;
runner.execute(Step::Vim, "Neovim", || vim::upgrade_neovim(&base_dirs, &ctx))?;
runner.execute(Step::Vim, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(&ctx))?;
runner.execute(Step::Vim, "voom", || vim::run_voom(&base_dirs, run_type))?;
runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?;
runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?;
runner.execute(Step::Node, "yarn", || node::run_yarn_upgrade(&ctx))?;
runner.execute(Step::Containers, "Containers", || containers::run_containers(&ctx))?;
runner.execute(Step::Deno, "deno", || node::deno_upgrade(&ctx))?;
runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?;
runner.execute(Step::Krew, "krew", || generic::run_krew_upgrade(run_type))?;
runner.execute(Step::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?;
runner.execute(Step::Julia, "julia", || generic::update_julia_packages(&ctx))?;
runner.execute(Step::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?;
runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?;
runner.execute(Step::Rtcl, "rtcl", || generic::run_rtcl(&ctx))?;
runner.execute(Step::Bin, "bin", || generic::bin_update(&ctx))?;
runner.execute(Step::Gcloud, "gcloud", || {
generic::run_gcloud_components_update(run_type)
})?;
runner.execute(Step::Micro, "micro", || generic::run_micro(run_type))?;
runner.execute(Step::Raco, "raco", || generic::run_raco_update(run_type))?;
runner.execute(Step::Spicetify, "spicetify", || generic::spicetify_upgrade(&ctx))?;
runner.execute(Step::GithubCliExtensions, "GitHub CLI Extensions", || {
generic::run_ghcli_extensions_upgrade(&ctx)
})?;
#[cfg(target_os = "linux")]
{
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
runner.execute(Step::Snap, "snap", || linux::run_snap(sudo.as_ref(), run_type))?;
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
runner.execute(Step::Distrobox, "distrobox", || linux::run_distrobox_update(&ctx))?;
}
if let Some(commands) = config.commands() {
for (name, command) in commands {
if config.should_run_custom_command(name) {
runner.execute(Step::CustomCommands, name, || {
generic::run_custom_command(name, command, &ctx)
})?;
}
}
}
#[cfg(target_os = "linux")]
{
runner.execute(Step::System, "pihole", || {
linux::run_pihole_update(sudo.as_ref(), run_type)
})?;
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
runner.execute(Step::Restarts, "Restarts", || {
linux::run_needrestart(sudo.as_ref(), run_type)
})?;
}
#[cfg(target_os = "macos")]
{
runner.execute(Step::Sparkle, "Sparkle", || macos::run_sparkle(&ctx))?;
runner.execute(Step::Mas, "App Store", || macos::run_mas(run_type))?;
runner.execute(Step::System, "System upgrade", || macos::upgrade_macos(&ctx))?;
}
#[cfg(target_os = "freebsd")]
runner.execute(Step::System, "FreeBSD Upgrade", || {
freebsd::upgrade_freebsd(sudo.as_ref(), run_type)
})?;
#[cfg(target_os = "openbsd")]
runner.execute(Step::System, "OpenBSD Upgrade", || {
openbsd::upgrade_openbsd(sudo.as_ref(), run_type)
})?;
#[cfg(windows)]
runner.execute(Step::System, "Windows update", || windows::windows_update(&ctx))?;
if config.should_run(Step::Vagrant) {
if let Ok(boxes) = vagrant::collect_boxes(&ctx) {
for vagrant_box in boxes {
runner.execute(Step::Vagrant, format!("Vagrant ({})", vagrant_box.smart_name()), || {
vagrant::topgrade_vagrant_box(&ctx, &vagrant_box)
})?;
}
}
}
runner.execute(Step::Vagrant, "Vagrant boxes", || vagrant::upgrade_vagrant_boxes(&ctx))?;
if !runner.report().data().is_empty() {
print_separator("Summary");
for (key, result) in runner.report().data() {
print_result(key, result);
}
#[cfg(target_os = "linux")]
{
if let Ok(distribution) = &distribution {
distribution.show_summary();
if skipped_missing_sudo {
print_warning(t!(
"\nSome steps were skipped as sudo or equivalent could not be found."
));
// Steps can only fail with SkippedMissingSudo if sudo is None,
// therefore we must have a sudo_err
match sudo_err.unwrap() {
SudoCreateError::CannotFindBinary => {
#[cfg(unix)]
print_warning(t!(
"Install one of `sudo`, `doas`, `pkexec`, `run0` or `please` to run these steps."
));
// if this windows version supported Windows Sudo, the error would have been WinSudoDisabled
#[cfg(windows)]
print_warning(t!("Install gsudo to run these steps."));
}
#[cfg(windows)]
SudoCreateError::WinSudoDisabled => {
print_warning(t!(
"Install gsudo or enable Windows Sudo to run these steps.\nFor Windows Sudo, the default 'In a new window' mode is not supported as it prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more."
));
}
#[cfg(windows)]
SudoCreateError::WinSudoNewWindowMode => {
print_warning(t!(
"Windows Sudo was found, but it is set to 'In a new window' mode, which prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more."
));
}
}
}
#[cfg(target_os = "freebsd")]
freebsd::audit_packages(&sudo).ok();
#[cfg(target_os = "dragonfly")]
dragonfly::audit_packages(&sudo).ok();
}
let mut post_command_failed = false;
#[cfg(target_os = "linux")]
if config.show_distribution_summary() {
if let Ok(distribution) = &distribution {
distribution.show_summary();
}
}
if let Some(commands) = config.post_commands() {
for (name, command) in commands {
if generic::run_custom_command(name, command, &ctx).is_err() {
post_command_failed = true;
let result = generic::run_custom_command(name, command, &ctx);
if !failed && result.is_err() {
failed = true;
}
}
}
if config.keep_at_end() {
print_info("\n(R)eboot\n(S)hell\n(Q)uit");
print_info(t!("\n(R)eboot\n(S)hell\n(Q)uit"));
loop {
match get_key() {
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
run_shell();
Ok(Key::Char('s' | 'S')) => {
run_shell().context("Failed to execute shell")?;
}
Ok(Key::Char('r')) | Ok(Key::Char('R')) => {
reboot();
Ok(Key::Char('r' | 'R')) => {
println!("{}", t!("Rebooting..."));
reboot(&ctx).context("Failed to reboot")?;
}
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => (),
Ok(Key::Char('q' | 'Q')) => (),
_ => {
continue;
}
@@ -484,15 +310,14 @@ fn run() -> Result<()> {
}
}
let failed = post_command_failed || runner.report().data().iter().any(|(_, result)| result.failed());
if !config.skip_notify() {
terminal::notify_desktop(
format!(
"Topgrade finished {}",
if failed { "with errors" } else { "successfully" }
),
None,
notify_desktop(
if failed {
t!("Topgrade finished with errors")
} else {
t!("Topgrade finished successfully")
},
Some(Duration::from_secs(10)),
);
}
@@ -509,13 +334,6 @@ fn main() {
exit(0);
}
Err(error) => {
#[cfg(all(windows, feature = "self-update"))]
{
if let Some(Upgraded(status)) = error.downcast_ref::<Upgraded>() {
exit(status.code().unwrap());
}
}
let skip_print = (error.downcast_ref::<StepFailed>().is_some())
|| (error
.downcast_ref::<io::Error>()
@@ -523,7 +341,10 @@ fn main() {
.is_some());
if !skip_print {
println!("Error: {}", error);
// The `Debug` implementation of `eyre::Result` prints a multi-line
// error message that includes all the 'causes' added with
// `.with_context(...)` calls.
println!("{}", t!("Error: {error}", error = format!("{:?}", error)));
}
exit(1);
}

View File

@@ -1,45 +0,0 @@
use std::borrow::Cow;
pub enum StepResult {
Success,
Failure,
Ignored,
Skipped(String),
}
impl StepResult {
pub fn failed(&self) -> bool {
match self {
StepResult::Success | StepResult::Ignored | StepResult::Skipped(_) => false,
StepResult::Failure => true,
}
}
}
type CowString<'a> = Cow<'a, str>;
type ReportData<'a> = Vec<(CowString<'a>, StepResult)>;
pub struct Report<'a> {
data: ReportData<'a>,
}
impl<'a> Report<'a> {
pub fn new() -> Self {
Self { data: Vec::new() }
}
pub fn push_result<M>(&mut self, result: Option<(M, StepResult)>)
where
M: Into<CowString<'a>>,
{
if let Some((key, success)) = result {
let key = key.into();
debug_assert!(!self.data.iter().any(|(k, _)| k == &key), "{} already reported", key);
self.data.push((key, success));
}
}
pub fn data(&self) -> &ReportData<'a> {
&self.data
}
}

View File

@@ -1,12 +1,36 @@
use crate::ctrlc;
use crate::error::{DryRun, SkipStep};
use crate::execution_context::ExecutionContext;
use crate::report::{Report, StepResult};
use crate::{config::Step, terminal::should_retry};
use anyhow::Result;
use log::debug;
use color_eyre::eyre::{Result, WrapErr};
use rust_i18n::t;
use std::borrow::Cow;
use std::fmt::Debug;
use std::io;
use tracing::debug;
use crate::ctrlc;
use crate::error::{DryRun, MissingSudo, SkipStep};
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::terminal::{print_error, print_warning, should_retry, ShouldRetry};
pub enum StepResult {
Success,
Failure,
Ignored,
SkippedMissingSudo,
Skipped(String),
}
impl StepResult {
pub fn failed(&self) -> bool {
use StepResult::*;
match self {
Success | Ignored | Skipped(_) | SkippedMissingSudo => false,
Failure => true,
}
}
}
type Report<'a> = Vec<(Cow<'a, str>, StepResult)>;
pub struct Runner<'a> {
ctx: &'a ExecutionContext<'a>,
@@ -17,32 +41,50 @@ impl<'a> Runner<'a> {
pub fn new(ctx: &'a ExecutionContext) -> Runner<'a> {
Runner {
ctx,
report: Report::new(),
report: Vec::new(),
}
}
pub fn execute<F, M>(&mut self, step: Step, key: M, func: F) -> Result<()>
fn push_result(&mut self, key: Cow<'a, str>, result: StepResult) {
debug_assert!(!self.report.iter().any(|(k, _)| k == &key), "{key} already reported");
self.report.push((key, result));
}
pub fn execute<K, F>(&mut self, step: Step, key: K, func: F) -> Result<()>
where
K: Into<Cow<'a, str>> + Debug,
F: Fn() -> Result<()>,
M: Into<Cow<'a, str>> + Debug,
{
if !self.ctx.config().should_run(step) {
return Ok(());
}
let key = key.into();
let key: Cow<'a, str> = key.into();
debug!("Step {:?}", key);
// alter the `func` to put it in a span
let func = || {
let span =
tracing::span!(parent: tracing::Span::none(), tracing::Level::TRACE, "step", step = ?step, key = %key);
let _guard = span.enter();
func()
};
loop {
match func() {
Ok(()) => {
self.report.push_result(Some((key, StepResult::Success)));
self.push_result(key, StepResult::Success);
break;
}
Err(e) if e.downcast_ref::<DryRun>().is_some() => break,
Err(e) if e.downcast_ref::<MissingSudo>().is_some() => {
print_warning(t!("Skipping step, sudo is required"));
self.push_result(key, StepResult::SkippedMissingSudo);
break;
}
Err(e) if e.downcast_ref::<SkipStep>().is_some() => {
if self.ctx.config().verbose() || self.ctx.config().show_skipped() {
self.report.push_result(Some((key, StepResult::Skipped(e.to_string()))));
self.push_result(key, StepResult::Skipped(e.to_string()));
}
break;
}
@@ -55,18 +97,30 @@ impl<'a> Runner<'a> {
let ignore_failure = self.ctx.config().ignore_failure(step);
let should_ask = interrupted || !(self.ctx.config().no_retry() || ignore_failure);
let should_retry = should_ask && should_retry(interrupted, key.as_ref())?;
let should_retry = if should_ask {
print_error(&key, format!("{e:?}"));
should_retry(key.as_ref())?
} else {
ShouldRetry::No
};
if !should_retry {
self.report.push_result(Some((
key,
if ignore_failure {
StepResult::Ignored
} else {
StepResult::Failure
},
)));
break;
match should_retry {
ShouldRetry::No | ShouldRetry::Quit => {
self.push_result(
key,
if ignore_failure {
StepResult::Ignored
} else {
StepResult::Failure
},
);
if let ShouldRetry::Quit = should_retry {
return Err(io::Error::from(io::ErrorKind::Interrupted))
.context("Quit from user input");
}
break;
}
ShouldRetry::Yes => (),
}
}
}
@@ -75,7 +129,7 @@ impl<'a> Runner<'a> {
Ok(())
}
pub fn report(&self) -> &Report {
pub fn report(&self) -> &Report<'_> {
&self.report
}
}

View File

@@ -1,8 +1,6 @@
#![cfg(windows)]
use anyhow::Result;
use log::{debug, error};
use color_eyre::eyre::Result;
use std::{env::current_exe, fs, path::PathBuf};
use tracing::{debug, error};
pub struct SelfRenamer {
exe_path: PathBuf,

View File

@@ -1,59 +1,74 @@
use super::terminal::*;
#[cfg(windows)]
use crate::error::Upgraded;
use anyhow::{bail, Result};
use self_update_crate::backends::github::Update;
use self_update_crate::update::UpdateStatus;
use std::env;
#[cfg(unix)]
use std::os::unix::process::CommandExt;
use std::os::unix::process::CommandExt as _;
#[cfg(windows)]
use std::process::exit;
use std::process::Command;
pub fn self_update() -> Result<()> {
print_separator("Self update");
let current_exe = env::current_exe();
use crate::step::Step;
#[cfg(unix)]
use color_eyre::eyre::bail;
use color_eyre::eyre::Result;
use rust_i18n::t;
use self_update_crate::backends::github::Update;
use self_update_crate::update::UpdateStatus;
let target = self_update_crate::get_target();
let result = Update::configure()
.repo_owner("topgrade-rs")
.repo_name("topgrade")
.target(target)
.bin_name(if cfg!(windows) { "topgrade-rs.exe" } else { "topgrade-rs" })
.show_output(false)
.show_download_progress(true)
.current_version(self_update_crate::cargo_crate_version!())
.no_confirm(true)
.build()?
.update_extended()?;
use super::terminal::{print_info, print_separator};
use crate::execution_context::ExecutionContext;
if let UpdateStatus::Updated(release) = &result {
println!("\nTopgrade upgraded to {}:\n", release.version);
if let Some(body) = &release.body {
println!("{}", body);
}
pub fn self_update(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("Self update"));
if ctx.run_type().dry() {
println!("{}", t!("Would self-update"));
Ok(())
} else {
println!("Topgrade is up-to-date");
}
let assume_yes = ctx.config().yes(Step::SelfUpdate);
let current_exe = env::current_exe();
{
if result.updated() {
print_warning("Respawning...");
let mut command = Command::new(current_exe?);
command.args(env::args().skip(1)).env("TOPGRADE_NO_SELF_UPGRADE", "");
let target = self_update_crate::get_target();
let result = Update::configure()
.repo_owner("topgrade-rs")
.repo_name("topgrade")
.target(target)
.bin_name(if cfg!(windows) { "topgrade.exe" } else { "topgrade" })
.show_output(true)
.show_download_progress(true)
.current_version(self_update_crate::cargo_crate_version!())
.no_confirm(assume_yes)
.build()?
.update_extended()?;
#[cfg(unix)]
{
let err = command.exec();
bail!(err);
if let UpdateStatus::Updated(release) = &result {
println!("{}", t!("Topgrade upgraded to {version}:\n", version = release.version));
if let Some(body) = &release.body {
println!("{body}");
}
} else {
println!("{}", t!("Topgrade is up-to-date"));
}
#[cfg(windows)]
{
let status = command.spawn().and_then(|mut c| c.wait())?;
bail!(Upgraded(status));
{
if result.updated() {
print_info(t!("Respawning..."));
let mut command = Command::new(current_exe?);
command.args(env::args().skip(1)).env("TOPGRADE_NO_SELF_UPGRADE", "");
#[cfg(unix)]
{
let err = command.exec();
bail!(err);
}
#[cfg(windows)]
{
#[allow(clippy::disallowed_methods)]
let status = command.status()?;
exit(status.code().expect("This cannot return None on Windows"));
}
}
}
}
Ok(())
Ok(())
}
}

901
src/step.rs Normal file
View File

@@ -0,0 +1,901 @@
use crate::execution_context::ExecutionContext;
use crate::runner::Runner;
use clap::ValueEnum;
use color_eyre::Result;
#[cfg(target_os = "linux")]
use rust_i18n::t;
use serde::Deserialize;
use strum::{EnumCount, EnumIter, EnumString, VariantNames};
#[cfg(feature = "self-update")]
use crate::self_update;
use crate::steps::remote::vagrant;
#[allow(clippy::wildcard_imports)]
use crate::steps::*;
use crate::utils::hostname;
#[derive(ValueEnum, EnumString, VariantNames, Debug, Clone, PartialEq, Eq, Deserialize, EnumIter, Copy, EnumCount)]
#[clap(rename_all = "snake_case")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum Step {
AM,
AndroidStudio,
AppMan,
Aqua,
Asdf,
Atom,
Atuin,
Audit,
AutoCpufreq,
Bin,
Bob,
BrewCask,
BrewFormula,
Bun,
BunPackages,
Cargo,
Certbot,
Chezmoi,
Chocolatey,
Choosenim,
CinnamonSpices,
ClamAvDb,
Composer,
Conda,
ConfigUpdate,
Containers,
CustomCommands,
DebGet,
Deno,
Distrobox,
DkpPacman,
Dotnet,
Elan,
Emacs,
Falconf,
Firmware,
Flatpak,
Flutter,
Fossil,
Gcloud,
Gem,
Ghcup,
GitRepos,
GithubCliExtensions,
GnomeShellExtensions,
Go,
Guix,
Haxelib,
Helix,
Helm,
HomeManager,
Hyprpm,
// These names are miscapitalized on purpose, so the CLI name is
// `jetbrains_pycharm` instead of `jet_brains_py_charm`.
JetbrainsAqua,
JetbrainsClion,
JetbrainsDatagrip,
JetbrainsDataspell,
JetbrainsGateway,
JetbrainsGoland,
JetbrainsIdea,
JetbrainsMps,
JetbrainsPhpstorm,
JetbrainsPycharm,
JetbrainsRider,
JetbrainsRubymine,
JetbrainsRustrover,
JetbrainsToolbox,
JetbrainsWebstorm,
Jetpack,
Julia,
Juliaup,
Kakoune,
Krew,
Lensfun,
Lure,
Macports,
Mamba,
Mandb,
Mas,
Maza,
Micro,
MicrosoftStore,
Miktex,
Mise,
Myrepos,
Nix,
NixHelper,
Node,
Opam,
Pacdef,
Pacstall,
Pearl,
Pip3,
PipReview,
PipReviewLocal,
Pipupgrade,
Pipx,
Pipxu,
Pixi,
Pkg,
Pkgfile,
Pkgin,
PlatformioCore,
Pnpm,
Poetry,
Powershell,
Protonup,
Pyenv,
Raco,
Rcm,
Remotes,
Restarts,
Rtcl,
RubyGems,
Rustup,
Rye,
Scoop,
Sdkman,
SelfUpdate,
Sheldon,
Shell,
Snap,
Sparkle,
Spicetify,
Stack,
Stew,
System,
Tldr,
Tlmgr,
Tmux,
Toolbx,
Typst,
Uv,
Vagrant,
Vcpkg,
Vim,
VoltaPackages,
Vscode,
VscodeInsiders,
Vscodium,
VscodiumInsiders,
Waydroid,
Winget,
Wsl,
WslUpdate,
Xcodes,
Yadm,
Yarn,
Yazi,
Zigup,
Zvm,
}
impl Step {
#[allow(clippy::too_many_lines)]
pub fn run(&self, runner: &mut Runner, ctx: &ExecutionContext) -> Result<()> {
use Step::*;
match *self {
AM =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "am", || linux::run_am(ctx))?
}
AndroidStudio => runner.execute(*self, "Android Studio Plugins", || generic::run_android_studio(ctx))?,
AppMan =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "appman", || linux::run_appman(ctx))?
}
Aqua => runner.execute(*self, "aqua", || generic::run_aqua(ctx))?,
Asdf =>
{
#[cfg(unix)]
runner.execute(*self, "asdf", || unix::run_asdf(ctx))?
}
Atom =>
{
#[cfg(not(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly"
)))]
runner.execute(*self, "apm", || generic::run_apm(ctx))?
}
Atuin =>
{
#[cfg(unix)]
runner.execute(*self, "atuin", || unix::run_atuin(ctx))?
}
Audit => {
#[cfg(target_os = "dragonfly")]
runner.execute(*self, "DragonFly Audit", || dragonfly::audit_packages(ctx))?;
#[cfg(target_os = "freebsd")]
runner.execute(*self, "FreeBSD Audit", || freebsd::audit_packages(ctx))?
}
AutoCpufreq =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "auto-cpufreq", || linux::run_auto_cpufreq(ctx))?
}
Bin => runner.execute(*self, "bin", || generic::bin_update(ctx))?,
Bob => runner.execute(*self, "Bob", || generic::run_bob(ctx))?,
BrewCask => {
#[cfg(target_os = "macos")]
runner.execute(*self, "Brew Cask", || unix::run_brew_cask(ctx, unix::BrewVariant::Path))?;
#[cfg(target_os = "macos")]
runner.execute(*self, "Brew Cask (Intel)", || {
unix::run_brew_cask(ctx, unix::BrewVariant::MacIntel)
})?;
#[cfg(target_os = "macos")]
runner.execute(*self, "Brew Cask (ARM)", || {
unix::run_brew_cask(ctx, unix::BrewVariant::MacArm)
})?
}
BrewFormula => {
#[cfg(target_os = "linux")]
runner.execute(*self, "Brew", || unix::run_brew_formula(ctx, unix::BrewVariant::Path))?;
#[cfg(target_os = "macos")]
runner.execute(*self, "Brew (ARM)", || {
unix::run_brew_formula(ctx, unix::BrewVariant::MacArm)
})?;
#[cfg(target_os = "macos")]
runner.execute(*self, "Brew (Intel)", || {
unix::run_brew_formula(ctx, unix::BrewVariant::MacIntel)
})?
}
Bun => runner.execute(*self, "bun", || generic::run_bun(ctx))?,
BunPackages =>
{
#[cfg(unix)]
runner.execute(*self, "bun-packages", || unix::run_bun_packages(ctx))?
}
Cargo => runner.execute(*self, "cargo", || generic::run_cargo_update(ctx))?,
Certbot => runner.execute(*self, "Certbot", || generic::run_certbot(ctx))?,
Chezmoi => runner.execute(*self, "chezmoi", || generic::run_chezmoi_update(ctx))?,
Chocolatey =>
{
#[cfg(windows)]
runner.execute(*self, "Chocolatey", || windows::run_chocolatey(ctx))?
}
Choosenim => runner.execute(*self, "choosenim", || generic::run_choosenim(ctx))?,
CinnamonSpices =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "Cinnamon spices", || linux::run_cinnamon_spices_updater(ctx))?
}
ClamAvDb => runner.execute(*self, "ClamAV Databases", || generic::run_freshclam(ctx))?,
Composer => runner.execute(*self, "composer", || generic::run_composer_update(ctx))?,
Conda => runner.execute(*self, "conda", || generic::run_conda_update(ctx))?,
ConfigUpdate =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "config-update", || linux::run_config_update(ctx))?
}
Containers => runner.execute(*self, "Containers", || containers::run_containers(ctx))?,
CustomCommands => {
if let Some(commands) = ctx.config().commands() {
for (name, command) in commands
.iter()
.filter(|(n, _)| ctx.config().should_run_custom_command(n))
{
runner.execute(*self, name.clone(), || generic::run_custom_command(name, command, ctx))?;
}
}
}
DebGet =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "deb-get", || linux::run_deb_get(ctx))?
}
Deno => runner.execute(*self, "deno", || node::deno_upgrade(ctx))?,
Distrobox =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "distrobox", || linux::run_distrobox_update(ctx))?
}
DkpPacman =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "dkp-pacman", || linux::run_dkp_pacman_update(ctx))?
}
Dotnet => runner.execute(*self, ".NET", || generic::run_dotnet_upgrade(ctx))?,
Elan => runner.execute(*self, "elan", || generic::run_elan(ctx))?,
Emacs => runner.execute(*self, "Emacs", || emacs::Emacs::new().upgrade(ctx))?,
Falconf => runner.execute(*self, "falconf sync", || generic::run_falconf(ctx))?,
Firmware =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "Firmware", || linux::run_fwupdmgr(ctx))?
}
Flatpak =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "Flatpak", || linux::run_flatpak(ctx))?
}
Flutter => runner.execute(*self, "Flutter", || generic::run_flutter_upgrade(ctx))?,
Fossil => runner.execute(*self, "fossil", || generic::run_fossil(ctx))?,
Gcloud => runner.execute(*self, "gcloud", || generic::run_gcloud_components_update(ctx))?,
Gem => runner.execute(*self, "gem", || generic::run_gem(ctx))?,
Ghcup => runner.execute(*self, "ghcup", || generic::run_ghcup_update(ctx))?,
GitRepos => runner.execute(*self, "Git Repositories", || git::run_git_pull(ctx))?,
GithubCliExtensions => runner.execute(*self, "GitHub CLI Extensions", || {
generic::run_ghcli_extensions_upgrade(ctx)
})?,
GnomeShellExtensions =>
{
#[cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))]
runner.execute(*self, "Gnome Shell Extensions", || unix::upgrade_gnome_extensions(ctx))?
}
Go => {
runner.execute(*self, "go-global-update", || go::run_go_global_update(ctx))?;
runner.execute(*self, "gup", || go::run_go_gup(ctx))?
}
Guix =>
{
#[cfg(unix)]
runner.execute(*self, "guix", || unix::run_guix(ctx))?
}
Haxelib => runner.execute(*self, "haxelib", || generic::run_haxelib_update(ctx))?,
Helix => runner.execute(*self, "helix", || generic::run_helix_grammars(ctx))?,
Helm => runner.execute(*self, "helm", || generic::run_helm_repo_update(ctx))?,
HomeManager =>
{
#[cfg(unix)]
runner.execute(*self, "home-manager", || unix::run_home_manager(ctx))?
}
Hyprpm =>
{
#[cfg(unix)]
runner.execute(*self, "hyprpm", || unix::run_hyprpm(ctx))?
}
JetbrainsAqua => runner.execute(*self, "JetBrains Aqua Plugins", || generic::run_jetbrains_aqua(ctx))?,
JetbrainsClion => runner.execute(*self, "JetBrains CL", || generic::run_jetbrains_clion(ctx))?,
JetbrainsDatagrip => {
runner.execute(*self, "JetBrains DataGrip", || generic::run_jetbrains_datagrip(ctx))?
}
JetbrainsDataspell => runner.execute(*self, "JetBrains DataSpell Plugins", || {
generic::run_jetbrains_dataspell(ctx)
})?,
JetbrainsGateway => runner.execute(*self, "JetBrains Gateway Plugins", || {
generic::run_jetbrains_gateway(ctx)
})?,
JetbrainsGoland => {
runner.execute(*self, "JetBrains GoLand Plugins", || generic::run_jetbrains_goland(ctx))?
}
JetbrainsIdea => runner.execute(*self, "JetBrains IntelliJ IDEA Plugins", || {
generic::run_jetbrains_idea(ctx)
})?,
JetbrainsMps => runner.execute(*self, "JetBrains MPS Plugins", || generic::run_jetbrains_mps(ctx))?,
JetbrainsPhpstorm => runner.execute(*self, "JetBrains PhpStorm Plugins", || {
generic::run_jetbrains_phpstorm(ctx)
})?,
JetbrainsPycharm => runner.execute(*self, "JetBrains PyCharm Plugins", || {
generic::run_jetbrains_pycharm(ctx)
})?,
JetbrainsRider => runner.execute(*self, "JetBrains Rider Plugins", || generic::run_jetbrains_rider(ctx))?,
JetbrainsRubymine => runner.execute(*self, "JetBrains RubyMine Plugins", || {
generic::run_jetbrains_rubymine(ctx)
})?,
JetbrainsRustrover => runner.execute(*self, "JetBrains RustRover Plugins", || {
generic::run_jetbrains_rustrover(ctx)
})?,
JetbrainsToolbox => runner.execute(*self, "JetBrains Toolbox", || generic::run_jetbrains_toolbox(ctx))?,
JetbrainsWebstorm => runner.execute(*self, "JetBrains WebStorm Plugins", || {
generic::run_jetbrains_webstorm(ctx)
})?,
Jetpack => runner.execute(*self, "jetpack", || generic::run_jetpack(ctx))?,
Julia => runner.execute(*self, "julia", || generic::update_julia_packages(ctx))?,
Juliaup => runner.execute(*self, "juliaup", || generic::run_juliaup(ctx))?,
Kakoune => runner.execute(*self, "Kakoune", || kakoune::upgrade_kak_plug(ctx))?,
Krew => runner.execute(*self, "krew", || generic::run_krew_upgrade(ctx))?,
Lensfun => runner.execute(*self, "Lensfun's database update", || {
generic::run_lensfun_update_data(ctx)
})?,
Lure =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "LURE", || linux::run_lure_update(ctx))?
}
Macports =>
{
#[cfg(target_os = "macos")]
runner.execute(*self, "MacPorts", || macos::run_macports(ctx))?
}
Mamba => runner.execute(*self, "mamba", || generic::run_mamba_update(ctx))?,
Mandb =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "Manual Entries", || linux::run_mandb(ctx))?
}
Mas =>
{
#[cfg(target_os = "macos")]
runner.execute(*self, "App Store", || macos::run_mas(ctx))?
}
Maza =>
{
#[cfg(unix)]
runner.execute(*self, "maza", || unix::run_maza(ctx))?
}
Micro => runner.execute(*self, "micro", || generic::run_micro(ctx))?,
MicrosoftStore =>
{
#[cfg(windows)]
runner.execute(*self, "Microsoft Store", || windows::microsoft_store(ctx))?
}
Miktex => runner.execute(*self, "miktex", || generic::run_miktex_packages_update(ctx))?,
Mise =>
{
#[cfg(unix)]
runner.execute(*self, "mise", || unix::run_mise(ctx))?
}
Myrepos => runner.execute(*self, "myrepos", || generic::run_myrepos_update(ctx))?,
Nix => {
#[cfg(unix)]
runner.execute(*self, "nix", || unix::run_nix(ctx))?;
#[cfg(unix)]
runner.execute(*self, "nix upgrade-nix", || unix::run_nix_self_upgrade(ctx))?
}
NixHelper =>
{
#[cfg(unix)]
runner.execute(*self, "nh", || unix::run_nix_helper(ctx))?
}
Node => runner.execute(*self, "npm", || node::run_npm_upgrade(ctx))?,
Opam => runner.execute(*self, "opam", || generic::run_opam_update(ctx))?,
Pacdef =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "pacdef", || linux::run_pacdef(ctx))?
}
Pacstall =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "pacstall", || linux::run_pacstall(ctx))?
}
Pearl =>
{
#[cfg(unix)]
runner.execute(*self, "pearl", || unix::run_pearl(ctx))?
}
Pip3 => runner.execute(*self, "pip3", || generic::run_pip3_update(ctx))?,
PipReview => runner.execute(*self, "pip-review", || generic::run_pip_review_update(ctx))?,
PipReviewLocal => runner.execute(*self, "pip-review (local)", || {
generic::run_pip_review_local_update(ctx)
})?,
Pipupgrade => runner.execute(*self, "pipupgrade", || generic::run_pipupgrade_update(ctx))?,
Pipx => runner.execute(*self, "pipx", || generic::run_pipx_update(ctx))?,
Pipxu => runner.execute(*self, "pipxu", || generic::run_pipxu_update(ctx))?,
Pixi => runner.execute(*self, "pixi", || generic::run_pixi_update(ctx))?,
Pkg => {
#[cfg(target_os = "dragonfly")]
runner.execute(*self, "Dragonfly BSD Packages", || dragonfly::upgrade_packages(ctx))?;
#[cfg(target_os = "freebsd")]
runner.execute(*self, "FreeBSD Packages", || freebsd::upgrade_packages(ctx))?;
#[cfg(target_os = "openbsd")]
runner.execute(*self, "OpenBSD Packages", || openbsd::upgrade_packages(ctx))?;
#[cfg(target_os = "android")]
runner.execute(*self, "Termux Packages", || android::upgrade_packages(ctx))?
}
Pkgfile =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "pkgfile", || linux::run_pkgfile(ctx))?
}
Pkgin =>
{
#[cfg(unix)]
runner.execute(*self, "pkgin", || unix::run_pkgin(ctx))?
}
PlatformioCore => runner.execute(*self, "PlatformIO Core", || generic::run_platform_io(ctx))?,
Pnpm => runner.execute(*self, "pnpm", || node::run_pnpm_upgrade(ctx))?,
Poetry => runner.execute(*self, "Poetry", || generic::run_poetry(ctx))?,
Powershell => runner.execute(*self, "Powershell Modules Update", || generic::run_powershell(ctx))?,
Protonup =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "protonup", || linux::run_protonup_update(ctx))?
}
Pyenv =>
{
#[cfg(unix)]
runner.execute(*self, "pyenv", || unix::run_pyenv(ctx))?
}
Raco => runner.execute(*self, "raco", || generic::run_raco_update(ctx))?,
Rcm =>
{
#[cfg(unix)]
runner.execute(*self, "rcm", || unix::run_rcm(ctx))?
}
Remotes => {
if let Some(topgrades) = ctx.config().remote_topgrades() {
for remote_topgrade in topgrades
.iter()
.filter(|t| ctx.config().should_execute_remote(hostname(), t))
{
runner.execute(*self, format!("Remote ({remote_topgrade})"), || {
crate::ssh::ssh_step(ctx, remote_topgrade)
})?;
}
}
}
Restarts =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "Restarts", || linux::run_needrestart(ctx))?
}
Rtcl => runner.execute(*self, "rtcl", || generic::run_rtcl(ctx))?,
RubyGems => runner.execute(*self, "rubygems", || generic::run_rubygems(ctx))?,
Rustup => runner.execute(*self, "rustup", || generic::run_rustup(ctx))?,
Rye => runner.execute(*self, "rye", || generic::run_rye(ctx))?,
Scoop =>
{
#[cfg(windows)]
runner.execute(*self, "Scoop", || windows::run_scoop(ctx))?
}
Sdkman =>
{
#[cfg(unix)]
runner.execute(*self, "SDKMAN!", || unix::run_sdkman(ctx))?
}
SelfUpdate => {
// Self-Update step, this will execute only if:
// 1. the `self-update` feature is enabled
// 2. it is not disabled from configuration (env var/CLI opt/file)
#[cfg(feature = "self-update")]
{
if std::env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !ctx.config().no_self_update() {
runner.execute(*self, "Self Update", || self_update::self_update(ctx))?;
}
}
}
Sheldon => runner.execute(*self, "sheldon", || generic::run_sheldon(ctx))?,
Shell => {
#[cfg(unix)]
{
runner.execute(*self, "zr", || zsh::run_zr(ctx))?;
runner.execute(*self, "antibody", || zsh::run_antibody(ctx))?;
runner.execute(*self, "antidote", || zsh::run_antidote(ctx))?;
runner.execute(*self, "antigen", || zsh::run_antigen(ctx))?;
runner.execute(*self, "zgenom", || zsh::run_zgenom(ctx))?;
runner.execute(*self, "zplug", || zsh::run_zplug(ctx))?;
runner.execute(*self, "zinit", || zsh::run_zinit(ctx))?;
runner.execute(*self, "zi", || zsh::run_zi(ctx))?;
runner.execute(*self, "zim", || zsh::run_zim(ctx))?;
runner.execute(*self, "oh-my-zsh", || zsh::run_oh_my_zsh(ctx))?;
runner.execute(*self, "oh-my-bash", || unix::run_oh_my_bash(ctx))?;
runner.execute(*self, "fisher", || unix::run_fisher(ctx))?;
runner.execute(*self, "bash-it", || unix::run_bashit(ctx))?;
runner.execute(*self, "oh-my-fish", || unix::run_oh_my_fish(ctx))?;
runner.execute(*self, "fish-plug", || unix::run_fish_plug(ctx))?;
runner.execute(*self, "fundle", || unix::run_fundle(ctx))?
}
}
Snap =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "snap", || linux::run_snap(ctx))?
}
Sparkle =>
{
#[cfg(target_os = "macos")]
runner.execute(*self, "Sparkle", || macos::run_sparkle(ctx))?
}
Spicetify => runner.execute(*self, "spicetify", || generic::spicetify_upgrade(ctx))?,
Stack => runner.execute(*self, "stack", || generic::run_stack_update(ctx))?,
Stew => runner.execute(*self, "stew", || generic::run_stew(ctx))?,
System => {
#[cfg(target_os = "linux")]
{
// NOTE: Due to breaking `nu` updates, `packer.nu` needs to be updated before `nu` get updated
// by other package managers.
runner.execute(Shell, "packer.nu", || linux::run_packer_nu(ctx))?;
match ctx.distribution() {
Ok(distribution) => {
runner.execute(*self, "System update", || distribution.upgrade(ctx))?;
}
Err(e) => {
println!("{}", t!("Error detecting current distribution: {error}", error = e));
}
}
runner.execute(*self, "pihole", || linux::run_pihole_update(ctx))?;
}
#[cfg(windows)]
runner.execute(*self, "Windows update", || windows::windows_update(ctx))?;
#[cfg(target_os = "macos")]
runner.execute(*self, "System update", || macos::upgrade_macos(ctx))?;
#[cfg(target_os = "freebsd")]
runner.execute(*self, "FreeBSD Upgrade", || freebsd::upgrade_freebsd(ctx))?;
#[cfg(target_os = "openbsd")]
runner.execute(*self, "OpenBSD Upgrade", || openbsd::upgrade_openbsd(ctx))?
}
Tldr => runner.execute(*self, "TLDR", || generic::run_tldr(ctx))?,
Tlmgr => runner.execute(*self, "tlmgr", || generic::run_tlmgr_update(ctx))?,
Tmux =>
{
#[cfg(unix)]
runner.execute(*self, "tmux", || tmux::run_tpm(ctx))?
}
Toolbx =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "toolbx", || toolbx::run_toolbx(ctx))?
}
Typst => runner.execute(*self, "Typst", || generic::run_typst(ctx))?,
Uv => runner.execute(*self, "uv", || generic::run_uv(ctx))?,
Vagrant => {
if ctx.config().should_run(Vagrant) {
if let Ok(boxes) = vagrant::collect_boxes(ctx) {
for vagrant_box in boxes {
runner.execute(*self, format!("Vagrant ({})", vagrant_box.smart_name()), || {
vagrant::topgrade_vagrant_box(ctx, &vagrant_box)
})?;
}
}
}
runner.execute(*self, "Vagrant boxes", || vagrant::upgrade_vagrant_boxes(ctx))?;
}
Vcpkg => runner.execute(*self, "vcpkg", || generic::run_vcpkg_update(ctx))?,
Vim => {
runner.execute(*self, "vim", || vim::upgrade_vim(ctx))?;
runner.execute(*self, "Neovim", || vim::upgrade_neovim(ctx))?;
runner.execute(*self, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(ctx))?;
runner.execute(*self, "voom", || vim::run_voom(ctx))?
}
VoltaPackages => runner.execute(*self, "volta packages", || node::run_volta_packages_upgrade(ctx))?,
Vscode => runner.execute(*self, "Visual Studio Code extensions", || {
generic::run_vscode_extensions_update(ctx)
})?,
VscodeInsiders => runner.execute(*self, "Visual Studio Code Insiders extensions", || {
generic::run_vscode_insiders_extensions_update(ctx)
})?,
Vscodium => runner.execute(*self, "VSCodium extensions", || {
generic::run_vscodium_extensions_update(ctx)
})?,
VscodiumInsiders => runner.execute(*self, "VSCodium Insiders extensions", || {
generic::run_vscodium_insiders_extensions_update(ctx)
})?,
Waydroid =>
{
#[cfg(target_os = "linux")]
runner.execute(*self, "Waydroid", || linux::run_waydroid(ctx))?
}
Winget =>
{
#[cfg(windows)]
runner.execute(*self, "Winget", || windows::run_winget(ctx))?
}
Wsl =>
{
#[cfg(windows)]
runner.execute(*self, "WSL", || windows::run_wsl_topgrade(ctx))?
}
WslUpdate =>
{
#[cfg(windows)]
runner.execute(*self, "Update WSL", || windows::update_wsl(ctx))?
}
Xcodes =>
{
#[cfg(target_os = "macos")]
runner.execute(*self, "Xcodes", || macos::update_xcodes(ctx))?
}
Yadm =>
{
#[cfg(unix)]
runner.execute(*self, "yadm", || unix::run_yadm(ctx))?
}
Yarn => runner.execute(*self, "yarn", || node::run_yarn_upgrade(ctx))?,
Yazi => runner.execute(*self, "Yazi packages", || generic::run_yazi(ctx))?,
Zigup => runner.execute(*self, "zigup", || generic::run_zigup(ctx))?,
Zvm => runner.execute(*self, "ZVM", || generic::run_zvm(ctx))?,
}
Ok(())
}
}
#[allow(clippy::too_many_lines)]
pub(crate) fn default_steps() -> Vec<Step> {
// For now, SelfRenamer and SelfUpdate isn't included as they're ran before the other non-steps (pre-commands, sudo, etc)
use Step::*;
// Could probably have a smaller starting capacity, but this at least ensures only 2 allocations:
// initial and shrink
let mut steps = Vec::with_capacity(Step::COUNT);
// Not combined with other generic steps to preserve the order as it was in main.rs originally,
// but this can be changed in the future.
steps.push(Remotes);
#[cfg(windows)]
steps.extend_from_slice(&[Wsl, WslUpdate, Chocolatey, Scoop, Winget, System, MicrosoftStore]);
#[cfg(target_os = "macos")]
steps.extend_from_slice(&[BrewFormula, BrewCask, Macports, Xcodes, Sparkle, Mas, System]);
#[cfg(target_os = "dragonfly")]
steps.extend_from_slice(&[Pkg, Audit]);
#[cfg(target_os = "freebsd")]
steps.extend_from_slice(&[Pkg, System, Audit]);
#[cfg(target_os = "openbsd")]
steps.extend_from_slice(&[Pkg, System]);
#[cfg(target_os = "android")]
steps.push(Pkg);
#[cfg(target_os = "linux")]
steps.extend_from_slice(&[
System,
ConfigUpdate,
AM,
AppMan,
DebGet,
Toolbx,
Snap,
Pacstall,
Pacdef,
Protonup,
Distrobox,
DkpPacman,
Firmware,
Restarts,
Flatpak,
BrewFormula,
Lure,
Waydroid,
AutoCpufreq,
CinnamonSpices,
Mandb,
Pkgfile,
]);
#[cfg(unix)]
steps.extend_from_slice(&[
Yadm,
Nix,
NixHelper,
Guix,
HomeManager,
Asdf,
Mise,
Pkgin,
BunPackages,
Shell,
Tmux,
Pearl,
#[cfg(not(any(target_os = "macos", target_os = "android")))]
GnomeShellExtensions,
Pyenv,
Sdkman,
Rcm,
Maza,
Hyprpm,
Atuin,
]);
#[cfg(not(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly"
)))]
steps.push(Atom);
// The following update function should be executed on all OSes.
steps.extend_from_slice(&[
Fossil,
Elan,
Rye,
Rustup,
Juliaup,
Dotnet,
Choosenim,
Cargo,
Flutter,
Go,
Emacs,
Opam,
Vcpkg,
Pipx,
Pipxu,
Vscode,
VscodeInsiders,
Vscodium,
VscodiumInsiders,
Conda,
Mamba,
Pixi,
Miktex,
Pip3,
PipReview,
PipReviewLocal,
Pipupgrade,
Ghcup,
Stack,
Tldr,
Tlmgr,
Myrepos,
Chezmoi,
Jetpack,
Vim,
Kakoune,
Helix,
Node,
Yarn,
Pnpm,
VoltaPackages,
Containers,
Deno,
Composer,
Krew,
Helm,
Gem,
RubyGems,
Julia,
Haxelib,
Sheldon,
Stew,
Rtcl,
Bin,
Gcloud,
Micro,
Raco,
Spicetify,
GithubCliExtensions,
Bob,
Certbot,
GitRepos,
ClamAvDb,
PlatformioCore,
Lensfun,
Poetry,
Uv,
Zvm,
Aqua,
Bun,
Zigup,
JetbrainsToolbox,
AndroidStudio,
JetbrainsAqua,
JetbrainsClion,
JetbrainsDatagrip,
JetbrainsDataspell,
// JetBrains dotCover has no CLI
// JetBrains dotMemory has no CLI
// JetBrains dotPeek has no CLI
// JetBrains dotTrace has no CLI
// JetBrains Fleet has a different CLI without a `fleet update` command.
JetbrainsGateway,
JetbrainsGoland,
JetbrainsIdea,
JetbrainsMps,
JetbrainsPhpstorm,
JetbrainsPycharm,
// JetBrains ReSharper has no CLI (it's a VSCode extension)
// JetBrains ReSharper C++ has no CLI (it's a VSCode extension)
JetbrainsRider,
JetbrainsRubymine,
JetbrainsRustrover,
// JetBrains Space Desktop does not have a CLI
JetbrainsWebstorm,
Yazi,
Falconf,
Powershell,
CustomCommands,
Vagrant,
Typst,
]);
steps.shrink_to_fit();
steps
}

View File

@@ -1,109 +1,241 @@
use anyhow::Result;
use crate::error::{self, TopgradeError};
use crate::executor::CommandExt;
use crate::terminal::print_separator;
use crate::{execution_context::ExecutionContext, utils::require};
use log::{debug, error, warn};
use std::path::Path;
use std::process::Command;
// A string found in the output of docker for containers that weren't found in
// the docker registry. We use this to gracefully handle and skip containers
// that cannot be pulled, likely because they don't exist in the registry in
// the first place. This happens e.g. when the user tags an image locally
// themselves or when using docker-compose.
const NONEXISTENT_REPO: &str = "repository does not exist";
/// Returns a Vector of all containers, with Strings in the format
/// "REGISTRY/[PATH/]CONTAINER_NAME:TAG"
fn list_containers(crt: &Path) -> Result<Vec<String>> {
debug!(
"Querying '{} image ls --format \"{{{{.Repository}}}}:{{{{.Tag}}}}\"' for containers",
crt.display()
);
let output = Command::new(crt)
.args(["image", "ls", "--format", "{{.Repository}}:{{.Tag}}"])
.output()?;
let output_str = String::from_utf8(output.stdout)?;
let mut retval = vec![];
for line in output_str.lines() {
if line.starts_with("localhost") {
// Don't know how to update self-built containers
debug!("Skipping self-built container '{}'", line);
continue;
}
if line.contains("<none>") {
// Bogus/dangling container or intermediate layer
debug!("Skipping bogus container '{}'", line);
continue;
}
if line.starts_with("vsc-") {
debug!("Skipping visual studio code dev container '{}'", line);
continue;
}
debug!("Using container '{}'", line);
retval.push(String::from(line));
}
Ok(retval)
}
pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
// Prefer podman, fall back to docker if not present
let crt = require("podman").or_else(|_| require("docker"))?;
debug!("Using container runtime '{}'", crt.display());
print_separator("Containers");
let mut success = true;
let containers = list_containers(&crt)?;
debug!("Containers to inspect: {:?}", containers);
for container in containers.iter() {
debug!("Pulling container '{}'", container);
let args = vec!["pull", &container[..]];
let mut exec = ctx.run_type().execute(&crt);
if let Err(e) = exec.args(&args).check_run() {
error!("Pulling container '{}' failed: {}", container, e);
// Find out if this is 'skippable'
// This is necessary e.g. for docker, because unlike podman docker doesn't tell from
// which repository a container originates (such as `docker.io`). This has the
// practical consequence that all containers, whether self-built, created by
// docker-compose or pulled from the docker hub, look exactly the same to us. We can
// only find out what went wrong by manually parsing the output of the command...
if match exec.check_output() {
Ok(s) => s.contains(NONEXISTENT_REPO),
Err(e) => match e.downcast_ref::<TopgradeError>() {
Some(TopgradeError::ProcessFailedWithOutput(_, stderr)) => stderr.contains(NONEXISTENT_REPO),
_ => false,
},
} {
warn!("Skipping unknown container '{}'", container);
continue;
}
success = false;
}
}
if ctx.config().cleanup() {
// Remove dangling images
debug!("Removing dangling images");
if let Err(e) = ctx.run_type().execute(&crt).args(["image", "prune", "-f"]).check_run() {
error!("Removing dangling images failed: {}", e);
success = false;
}
}
if success {
Ok(())
} else {
Err(anyhow::anyhow!(error::StepFailed))
}
}
use std::fmt::{Display, Formatter};
use std::io;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use color_eyre::eyre::Context;
use color_eyre::eyre::Result;
use color_eyre::eyre::{eyre, OptionExt};
use tracing::{debug, error, warn};
use wildmatch::WildMatch;
use crate::command::CommandExt;
use crate::error::{self, SkipStep, TopgradeError};
use crate::terminal::print_separator;
use crate::{execution_context::ExecutionContext, utils::require};
use rust_i18n::t;
// A string found in the output of docker for containers that weren't found in
// the docker registry. We use this to gracefully handle and skip containers
// that cannot be pulled, likely because they don't exist in the registry in
// the first place. This happens e.g. when the user tags an image locally
// themselves or when using docker-compose.
const NONEXISTENT_REPO: &str = "repository does not exist";
// A string found in the output of docker when Docker Desktop is not running.
const DOCKER_NOT_RUNNING: &str = "We recommend to activate the WSL integration in Docker Desktop settings.";
/// Uniquely identifies a `Container`.
#[derive(Debug)]
struct Container {
/// `Repository` and `Tag`
///
/// format: `Repository:Tag`, e.g., `nixos/nix:latest`.
repo_tag: String,
/// Platform
///
/// format: `OS/Architecture`, e.g., `linux/amd64`.
platform: String,
}
impl Container {
/// Construct a new `Container`.
fn new(repo_tag: String, platform: String) -> Self {
Self { repo_tag, platform }
}
}
impl Display for Container {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
// e.g., "`fedora:latest` for `linux/amd64`"
write!(
f,
"{}",
t!(
"`{repo_tag}` for `{platform}`",
repo_tag = self.repo_tag,
platform = self.platform
)
)
}
}
/// Returns a Vector of all containers, with Strings in the format
/// "REGISTRY/[PATH/]CONTAINER_NAME:TAG"
///
/// Containers specified in `ignored_containers` will be filtered out.
fn list_containers(crt: &Path, ignored_containers: Option<&Vec<String>>) -> Result<Vec<Container>> {
let ignored_containers = ignored_containers.map(|patterns| {
patterns
.iter()
.map(|pattern| WildMatch::new(pattern))
.collect::<Vec<WildMatch>>()
});
debug!(
"Querying '{} image ls --format \"{{{{.Repository}}}}:{{{{.Tag}}}}/{{{{.ID}}}}\"' for containers",
crt.display()
);
let output = Command::new(crt)
.args(["image", "ls", "--format", "{{.Repository}}:{{.Tag}} {{.ID}}"])
.output_checked_utf8()?;
let mut retval = vec![];
for line in output.stdout.lines() {
if line.starts_with("localhost") {
// Don't know how to update self-built containers
debug!("Skipping self-built container '{}'", line);
continue;
}
if line.contains("<none>") {
// Bogus/dangling container or intermediate layer
debug!("Skipping bogus container '{}'", line);
continue;
}
if line.starts_with("vsc-") {
debug!("Skipping visual studio code dev container '{}'", line);
continue;
}
debug!("Using container '{}'", line);
// line is of format: `Repository:Tag ImageID`, e.g., `nixos/nix:latest d80fea9c32b4`
let split_res = line.split(' ').collect::<Vec<&str>>();
if split_res.len() != 2 {
return Err(eyre!(format!(
"Got erroneous output from `{} image ls --format \"{{.Repository}}:{{.Tag}} {{.ID}}\"; Expected line to split into 2 parts",
crt.display()
)));
}
let (repo_tag, image_id) = (split_res[0], split_res[1]);
if let Some(ref ignored_containers) = ignored_containers {
if ignored_containers.iter().any(|pattern| pattern.matches(repo_tag)) {
debug!("Skipping ignored container '{}'", line);
continue;
}
}
debug!(
"Querying '{} image inspect --format \"{{{{.Os}}}}/{{{{.Architecture}}}}\"' for container {}",
crt.display(),
image_id
);
let inspect_output = Command::new(crt)
.args(["image", "inspect", image_id, "--format", "{{.Os}}/{{.Architecture}}"])
.output_checked_utf8()?;
let mut platform = inspect_output.stdout;
// truncate the tailing new line character
platform.truncate(platform.len() - 1);
if !platform.contains('/') {
return Err(eyre!(format!(
"Got erroneous output from `{} image ls --format \"{{.Repository}}:{{.Tag}} {{.ID}}\"; Expected platform to contain '/'",
crt.display()
)));
}
retval.push(Container::new(repo_tag.to_string(), platform));
}
Ok(retval)
}
pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
// Check what runtime is specified in the config
let container_runtime = ctx.config().containers_runtime().to_string();
let crt = require(container_runtime)?;
debug!("Using container runtime '{}'", crt.display());
print_separator(t!("Containers"));
let output = Command::new(&crt).arg("--help").output_checked_with(|_| Ok(()))?;
let status_code = output
.status
.code()
.ok_or_eyre("Couldn't get status code (terminated by signal)")?;
let stdout = std::str::from_utf8(&output.stdout).wrap_err("Expected output to be valid UTF-8")?;
if stdout.contains(DOCKER_NOT_RUNNING) && status_code == 1 {
// Write the output
io::stdout().write_all(&output.stdout)?;
io::stderr().write_all(&output.stderr)?;
// Don't crash, but don't be silent either.
// This can happen in other ways than Docker Desktop not running, but even in those cases
// we don't want to crash, since the containers step is enabled by default.
warn!(
"{} seems to be non-functional right now (see above). Is WSL integration enabled for Docker Desktop? Is Docker Desktop running?",
crt.display()
);
return Err(SkipStep(format!(
"{} seems to be non-functional right now. Possibly WSL integration is not enabled for Docker Desktop, or Docker Desktop is not running.",
crt.display()
)).into());
} else if !output.status.success() {
// Write the output
io::stdout().write_all(&output.stdout)?;
io::stderr().write_all(&output.stderr)?;
// If we saw the message, but the code is not 1 (e.g. 0, or a non-1 failure), crash, as we expect a 1.
// If we did not see the message, it's broken in some way we do not understand.
return Err(eyre!(
"{0} seems to be non-functional (`{0} --help` returned non-zero exit code {1})",
crt.display(),
status_code,
));
}
let mut success = true;
let containers =
list_containers(&crt, ctx.config().containers_ignored_tags()).context("Failed to list Docker containers")?;
debug!("Containers to inspect: {:?}", containers);
for container in &containers {
debug!("Pulling container '{}'", container);
let mut args = vec!["pull", container.repo_tag.as_str()];
if container.platform.as_str() != "/" {
args.push("--platform");
args.push(container.platform.as_str());
}
let mut exec = ctx.execute(&crt);
if let Err(e) = exec.args(&args).status_checked() {
error!("Pulling container '{}' failed: {}", container, e);
// Find out if this is 'skippable'
// This is necessary e.g. for docker, because unlike podman docker doesn't tell from
// which repository a container originates (such as `docker.io`). This has the
// practical consequence that all containers, whether self-built, created by
// docker-compose or pulled from the docker hub, look exactly the same to us. We can
// only find out what went wrong by manually parsing the output of the command...
if match exec.output_checked_utf8() {
Ok(s) => s.stdout.contains(NONEXISTENT_REPO) || s.stderr.contains(NONEXISTENT_REPO),
Err(e) => match e.downcast_ref::<TopgradeError>() {
Some(TopgradeError::ProcessFailedWithOutput(_, _, stderr)) => stderr.contains(NONEXISTENT_REPO),
_ => false,
},
} {
warn!("Skipping unknown container '{}'", container);
continue;
}
success = false;
}
}
if ctx.config().cleanup() {
// Remove dangling images
debug!("Removing dangling images");
if let Err(e) = ctx.execute(&crt).args(["image", "prune", "-f"]).status_checked() {
error!("Removing dangling images failed: {}", e);
success = false;
}
}
if success {
Ok(())
} else {
Err(eyre!(error::StepFailed))
}
}

View File

@@ -1,9 +1,4 @@
(when (fboundp 'paradox-upgrade-packages)
(progn
(unless (boundp 'paradox-github-token)
(setq paradox-github-token t))
(paradox-upgrade-packages)
(princ
(if (get-buffer "*Paradox Report*")
(with-current-buffer "*Paradox Report*" (buffer-string))
"\nNothing to upgrade\n"))))
(when (featurep 'package)
(if (fboundp 'package-upgrade-all)
(package-upgrade-all nil)
(message "Your Emacs version doesn't support unattended packages upgrade")))

View File

@@ -1,14 +1,16 @@
#[cfg(any(windows, target_os = "macos"))]
#[cfg(windows)]
use std::env;
use std::path::{Path, PathBuf};
use anyhow::Result;
use directories::BaseDirs;
use color_eyre::eyre::Result;
use etcetera::base_strategy::BaseStrategy;
use rust_i18n::t;
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::terminal::print_separator;
use crate::utils::{require, require_option, PathExt};
use crate::Step;
const EMACS_UPGRADE: &str = include_str!("emacs.el");
#[cfg(windows)]
@@ -22,20 +24,12 @@ pub struct Emacs {
}
impl Emacs {
fn directory_path(base_dirs: &BaseDirs) -> Option<PathBuf> {
fn directory_path() -> Option<PathBuf> {
#[cfg(unix)]
cfg_if::cfg_if! {
if #[cfg(target_os = "macos")] {
let emacs_xdg_dir = env::var("XDG_CONFIG_HOME")
.ok()
.and_then(|config| PathBuf::from(config).join("emacs").if_exists())
.or_else(|| base_dirs.home_dir().join(".config/emacs").if_exists());
} else {
let emacs_xdg_dir = base_dirs.config_dir().join("emacs").if_exists();
}
}
#[cfg(unix)]
return base_dirs.home_dir().join(".emacs.d").if_exists().or(emacs_xdg_dir);
return {
let emacs_xdg_dir = crate::XDG_DIRS.config_dir().join("emacs").if_exists();
crate::HOME_DIR.join(".emacs.d").if_exists().or(emacs_xdg_dir)
};
#[cfg(windows)]
return env::var("HOME")
@@ -46,11 +40,11 @@ impl Emacs {
.if_exists()
.or_else(|| PathBuf::from(&home).join(".config\\emacs").if_exists())
})
.or_else(|| base_dirs.data_dir().join(".emacs.d").if_exists());
.or_else(|| crate::WINDOWS_DIRS.data_dir().join(".emacs.d").if_exists());
}
pub fn new(base_dirs: &BaseDirs) -> Self {
let directory = Emacs::directory_path(base_dirs);
pub fn new() -> Self {
let directory = Emacs::directory_path();
let doom = directory.as_ref().and_then(|d| d.join(DOOM_PATH).if_exists());
Self { directory, doom }
}
@@ -66,14 +60,18 @@ impl Emacs {
fn update_doom(doom: &Path, ctx: &ExecutionContext) -> Result<()> {
print_separator("Doom Emacs");
let mut command = ctx.run_type().execute(doom);
let mut command = ctx.execute(doom);
if ctx.config().yes(Step::Emacs) {
command.arg("--force");
}
command.args(["upgrade"]);
command.arg("upgrade");
command.check_run()
if ctx.config().doom_aot() {
command.arg("--aot");
}
command.status_checked()
}
pub fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
@@ -81,13 +79,16 @@ impl Emacs {
if let Some(doom) = &self.doom {
Emacs::update_doom(doom, ctx)?;
}
let init_file = require_option(self.directory.as_ref(), String::from("Emacs directory does not exist"))?
.join("init.el")
.require()?;
let init_file = require_option(
self.directory.as_ref(),
t!("Emacs directory does not exist").to_string(),
)?
.join("init.el")
.require()?;
print_separator("Emacs");
let mut command = ctx.run_type().execute(&emacs);
let mut command = ctx.execute(emacs);
command
.args(["--batch", "--debug-init", "-l"])
@@ -105,6 +106,6 @@ impl Emacs {
#[cfg(not(unix))]
command.arg(EMACS_UPGRADE);
command.check_run()
command.status_checked()
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,141 +3,177 @@ use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
use anyhow::{anyhow, Result};
use color_eyre::eyre::Context;
use color_eyre::eyre::{eyre, Result};
use console::style;
use futures::stream::{iter, FuturesUnordered};
use futures::StreamExt;
use futures::stream::{iter, FuturesUnordered, StreamExt};
use glob::{glob_with, MatchOptions};
use log::{debug, error};
use tokio::process::Command as AsyncCommand;
use tokio::runtime;
use tracing::{debug, error};
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::executor::{CommandExt, RunType};
use crate::step::Step;
use crate::steps::emacs::Emacs;
use crate::terminal::print_separator;
use crate::utils::{which, PathExt};
use crate::{error::SkipStep, terminal::print_warning};
use crate::utils::{require, PathExt};
use crate::{error::SkipStep, terminal::print_warning, HOME_DIR};
use etcetera::base_strategy::BaseStrategy;
use rust_i18n::t;
#[cfg(unix)]
use crate::XDG_DIRS;
#[cfg(windows)]
use crate::WINDOWS_DIRS;
pub fn run_git_pull(ctx: &ExecutionContext) -> Result<()> {
let mut repos = RepoStep::try_new()?;
let config = ctx.config();
// handle built-in repos
if config.use_predefined_git_repos() {
// should be executed on all the platforms
{
if config.should_run(Step::Emacs) {
let emacs = Emacs::new();
if !emacs.is_doom() {
if let Some(directory) = emacs.directory() {
repos.insert_if_repo(directory);
}
}
repos.insert_if_repo(HOME_DIR.join(".doom.d"));
}
if config.should_run(Step::Vim) {
repos.insert_if_repo(HOME_DIR.join(".vim"));
repos.insert_if_repo(HOME_DIR.join(".config/nvim"));
}
repos.insert_if_repo(HOME_DIR.join(".ideavimrc"));
repos.insert_if_repo(HOME_DIR.join(".intellimacs"));
if config.should_run(Step::Rcm) {
repos.insert_if_repo(HOME_DIR.join(".dotfiles"));
}
if let Some(powershell) = ctx.powershell() {
if let Some(profile) = powershell.profile() {
repos.insert_if_repo(profile);
}
}
}
#[cfg(unix)]
{
repos.insert_if_repo(crate::steps::zsh::zshrc());
if config.should_run(Step::Tmux) {
repos.insert_if_repo(HOME_DIR.join(".tmux"));
}
repos.insert_if_repo(HOME_DIR.join(".config/fish"));
repos.insert_if_repo(XDG_DIRS.config_dir().join("openbox"));
repos.insert_if_repo(XDG_DIRS.config_dir().join("bspwm"));
repos.insert_if_repo(XDG_DIRS.config_dir().join("i3"));
repos.insert_if_repo(XDG_DIRS.config_dir().join("sway"));
}
#[cfg(windows)]
{
repos.insert_if_repo(
WINDOWS_DIRS
.cache_dir()
.join("Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState"),
);
super::os::windows::insert_startup_scripts(&mut repos).ok();
}
}
// Handle user-defined repos
if let Some(custom_git_repos) = config.git_repos() {
for git_repo in custom_git_repos {
repos.glob_insert(&shellexpand::tilde(git_repo));
}
}
// Warn the user about the bad patterns.
//
// NOTE: this should be executed **before** skipping the Git step or the
// user won't receive this warning in the cases where all the paths configured
// are bad patterns.
repos.bad_patterns.iter().for_each(|pattern| {
print_warning(t!(
"Path {pattern} did not contain any git repositories",
pattern = pattern
));
});
if repos.is_repos_empty() {
return Err(SkipStep(t!("No repositories to pull").to_string()).into());
}
print_separator(t!("Git repositories"));
repos.pull_repos(ctx)
}
#[cfg(windows)]
static PATH_PREFIX: &str = "\\\\?\\";
#[derive(Debug)]
pub struct Git {
git: Option<PathBuf>,
}
pub struct Repositories<'a> {
git: &'a Git,
repositories: HashSet<String>,
pub struct RepoStep {
git: PathBuf,
repos: HashSet<PathBuf>,
glob_match_options: MatchOptions,
bad_patterns: Vec<String>,
}
fn check_output(output: Output) -> Result<()> {
#[track_caller]
fn output_checked_utf8(output: Output) -> Result<()> {
if !(output.status.success()) {
let stderr = String::from_utf8(output.stderr).unwrap();
Err(anyhow!(stderr))
let stderr = String::from_utf8_lossy(&output.stderr);
let stderr = stderr.trim();
Err(eyre!("{stderr}"))
} else {
Ok(())
}
}
async fn pull_repository(repo: String, git: &Path, ctx: &ExecutionContext<'_>) -> Result<()> {
let path = repo.to_string();
let before_revision = get_head_revision(git, &repo);
println!("{} {}", style("Pulling").cyan().bold(), path);
let mut command = AsyncCommand::new(git);
command
.stdin(Stdio::null())
.current_dir(&repo)
.args(["pull", "--ff-only"]);
if let Some(extra_arguments) = ctx.config().git_arguments() {
command.args(extra_arguments.split_whitespace());
}
let pull_output = command.output().await?;
let submodule_output = AsyncCommand::new(git)
.args(["submodule", "update", "--recursive"])
.current_dir(&repo)
.stdin(Stdio::null())
.output()
.await?;
let result = check_output(pull_output).and_then(|_| check_output(submodule_output));
if let Err(message) = &result {
println!("{} pulling {}", style("Failed").red().bold(), &repo);
print!("{}", message);
} else {
let after_revision = get_head_revision(git, &repo);
match (&before_revision, &after_revision) {
(Some(before), Some(after)) if before != after => {
println!("{} {}:", style("Changed").yellow().bold(), &repo);
Command::new(git)
.stdin(Stdio::null())
.current_dir(&repo)
.args([
"--no-pager",
"log",
"--no-decorate",
"--oneline",
&format!("{}..{}", before, after),
])
.spawn()
.unwrap()
.wait()
.unwrap();
println!();
}
_ => {
println!("{} {}", style("Up-to-date").green().bold(), &repo);
}
}
}
result.map(|_| ())
}
fn get_head_revision(git: &Path, repo: &str) -> Option<String> {
fn get_head_revision<P: AsRef<Path>>(git: &Path, repo: P) -> Option<String> {
Command::new(git)
.stdin(Stdio::null())
.current_dir(repo)
.current_dir(repo.as_ref())
.args(["rev-parse", "HEAD"])
.check_output()
.map(|output| output.trim().to_string())
.output_checked_utf8()
.map(|output| output.stdout.trim().to_string())
.map_err(|e| {
error!("Error getting revision for {}: {}", repo, e);
error!("Error getting revision for {}: {e}", repo.as_ref().display(),);
e
})
.ok()
}
fn has_remotes(git: &Path, repo: &str) -> Option<bool> {
Command::new(git)
.stdin(Stdio::null())
.current_dir(repo)
.args(["remote", "show"])
.check_output()
.map(|output| output.lines().count() > 0)
.map_err(|e| {
error!("Error getting remotes for {}: {}", repo, e);
e
})
.ok()
}
impl RepoStep {
/// Try to create a `RepoStep`, fail if `git` is not found.
pub fn try_new() -> Result<Self> {
let git = require("git")?;
let mut glob_match_options = MatchOptions::new();
impl Git {
pub fn new() -> Self {
Self { git: which("git") }
if cfg!(windows) {
glob_match_options.case_sensitive = false;
}
Ok(Self {
git,
repos: HashSet::new(),
bad_patterns: Vec::new(),
glob_match_options,
})
}
pub fn get_repo_root<P: AsRef<Path>>(&self, path: P) -> Option<String> {
/// Try to get the root of the repo specified in `path`.
pub fn get_repo_root<P: AsRef<Path>>(&self, path: P) -> Option<PathBuf> {
match path.as_ref().canonicalize() {
Ok(mut path) => {
debug_assert!(path.exists());
@@ -161,105 +197,59 @@ impl Git {
path_string
};
if let Some(git) = &self.git {
let output = Command::new(git)
.stdin(Stdio::null())
.current_dir(path)
.args(["rev-parse", "--show-toplevel"])
.check_output()
.ok()
.map(|output| output.trim().to_string());
return output;
let output = Command::new(&self.git)
.stdin(Stdio::null())
.current_dir(path)
.args(["rev-parse", "--show-toplevel"])
.output_checked_utf8()
.ok()
// trim the last newline char
.map(|output| PathBuf::from(output.stdout.trim()));
return output;
}
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
debug!("{} does not exist", path.as_ref().display());
} else {
error!("Error looking for {}: {e}", path.as_ref().display());
}
}
Err(e) => match e.kind() {
io::ErrorKind::NotFound => debug!("{} does not exists", path.as_ref().display()),
_ => error!("Error looking for {}: {}", path.as_ref().display(), e),
},
}
None
}
pub fn multi_pull_step(&self, repositories: &Repositories, ctx: &ExecutionContext) -> Result<()> {
if repositories.repositories.is_empty() {
return Err(SkipStep(String::from("No repositories to pull")).into());
}
print_separator("Git repositories");
repositories
.bad_patterns
.iter()
.for_each(|pattern| print_warning(format!("Path {} did not contain any git repositories", pattern)));
self.multi_pull(repositories, ctx)
}
pub fn multi_pull(&self, repositories: &Repositories, ctx: &ExecutionContext) -> Result<()> {
let git = self.git.as_ref().unwrap();
if let RunType::Dry = ctx.run_type() {
repositories
.repositories
.iter()
.for_each(|repo| println!("Would pull {}", &repo));
return Ok(());
}
let futures_iterator = repositories
.repositories
.iter()
.filter(|repo| match has_remotes(git, repo) {
Some(false) => {
println!(
"{} {} because it has no remotes",
style("Skipping").yellow().bold(),
repo
);
false
}
_ => true, // repo has remotes or command to check for remotes has failed. proceed to pull anyway.
})
.map(|repo| pull_repository(repo.clone(), git, ctx));
let stream_of_futures = if let Some(limit) = ctx.config().git_concurrency_limit() {
iter(futures_iterator).buffer_unordered(limit).boxed()
} else {
futures_iterator.collect::<FuturesUnordered<_>>().boxed()
};
let basic_rt = runtime::Runtime::new()?;
let results = basic_rt.block_on(async { stream_of_futures.collect::<Vec<Result<()>>>().await });
let error = results.into_iter().find(|r| r.is_err());
error.unwrap_or(Ok(()))
}
}
impl<'a> Repositories<'a> {
pub fn new(git: &'a Git) -> Self {
let mut glob_match_options = MatchOptions::new();
if cfg!(windows) {
glob_match_options.case_sensitive = false;
}
Self {
git,
repositories: HashSet::new(),
bad_patterns: Vec::new(),
glob_match_options,
}
}
/// Check if `path` is a git repo, if yes, add it to `self.repos`.
///
/// Return the check result.
pub fn insert_if_repo<P: AsRef<Path>>(&mut self, path: P) -> bool {
if let Some(repo) = self.git.get_repo_root(path) {
self.repositories.insert(repo);
if let Some(repo) = self.get_repo_root(path) {
self.repos.insert(repo);
true
} else {
false
}
}
/// Check if `repo` has a remote.
fn has_remotes<P: AsRef<Path>>(&self, repo: P) -> Option<bool> {
let mut cmd = Command::new(&self.git);
cmd.stdin(Stdio::null())
.current_dir(repo.as_ref())
.args(["remote", "show"]);
let res = cmd.output_checked_utf8();
res.map(|output| output.stdout.lines().count() > 0)
.map_err(|e| {
error!("Error getting remotes for {}: {e}", repo.as_ref().display());
e
})
.ok()
}
/// Similar to `insert_if_repo`, with glob support.
pub fn glob_insert(&mut self, pattern: &str) {
if let Ok(glob) = glob_with(pattern, self.glob_match_options) {
let mut last_git_repo: Option<PathBuf> = None;
@@ -269,7 +259,7 @@ impl<'a> Repositories<'a> {
if let Some(last_git_repo) = &last_git_repo {
if path.is_descendant_of(last_git_repo) {
debug!(
"Skipping {} because it's a decendant of last known repo {}",
"Skipping {} because it's a descendant of last known repo {}",
path.display(),
last_git_repo.display()
);
@@ -281,7 +271,7 @@ impl<'a> Repositories<'a> {
}
}
Err(e) => {
error!("Error in path {}", e);
error!("Error in path {e}");
}
}
}
@@ -290,18 +280,141 @@ impl<'a> Repositories<'a> {
self.bad_patterns.push(String::from(pattern));
}
} else {
error!("Bad glob pattern: {}", pattern);
error!("Bad glob pattern: {pattern}");
}
}
#[cfg(unix)]
pub fn is_empty(&self) -> bool {
self.repositories.is_empty()
/// True if `self.repos` is empty.
pub fn is_repos_empty(&self) -> bool {
self.repos.is_empty()
}
/// Remove `path` from `self.repos`.
///
// `cfg(unix)` because it is only used in the oh-my-zsh step.
#[cfg(unix)]
pub fn remove(&mut self, path: &str) {
let _removed = self.repositories.remove(path);
pub fn remove<P: AsRef<Path>>(&mut self, path: P) {
let _removed = self.repos.remove(path.as_ref());
debug_assert!(_removed);
}
/// Try to pull a repo.
async fn pull_repo<P: AsRef<Path>>(&self, ctx: &ExecutionContext<'_>, repo: P) -> Result<()> {
let before_revision = get_head_revision(&self.git, &repo);
if ctx.config().verbose() {
println!("{} {}", style(t!("Pulling")).cyan().bold(), repo.as_ref().display());
}
let mut command = AsyncCommand::new(&self.git);
command
.stdin(Stdio::null())
.current_dir(&repo)
.args(["pull", "--ff-only"]);
if let Some(extra_arguments) = ctx.config().git_arguments() {
command.args(extra_arguments.split_whitespace());
}
let pull_output = command.output().await?;
let submodule_output = AsyncCommand::new(&self.git)
.args(["submodule", "update", "--recursive"])
.current_dir(&repo)
.stdin(Stdio::null())
.output()
.await?;
let result = output_checked_utf8(pull_output)
.and_then(|()| output_checked_utf8(submodule_output))
.wrap_err_with(|| format!("Failed to pull {}", repo.as_ref().display()));
if result.is_err() {
println!(
"{} {} {}",
style(t!("Failed")).red().bold(),
t!("pulling"),
repo.as_ref().display()
);
} else {
let after_revision = get_head_revision(&self.git, repo.as_ref());
match (&before_revision, &after_revision) {
(Some(before), Some(after)) if before != after => {
println!("{} {}", style(t!("Changed")).yellow().bold(), repo.as_ref().display());
Command::new(&self.git)
.stdin(Stdio::null())
.current_dir(&repo)
.args([
"--no-pager",
"log",
"--no-decorate",
"--oneline",
&format!("{before}..{after}"),
])
.status_checked()?;
println!();
}
_ => {
if ctx.config().verbose() {
println!("{} {}", style(t!("Up-to-date")).green().bold(), repo.as_ref().display());
}
}
}
}
result
}
/// Pull the repositories specified in `self.repos`.
///
/// # NOTE
/// This function will create an async runtime and do the real job so the
/// function itself is not async.
fn pull_repos(&self, ctx: &ExecutionContext) -> Result<()> {
if ctx.run_type().dry() {
self.repos
.iter()
.for_each(|repo| println!("{}", t!("Would pull {repo}", repo = repo.display())));
return Ok(());
}
if !ctx.config().verbose() {
println!(
"\n{} {}\n",
style(t!("Only")).green().bold(),
t!("updated repositories will be shown...")
);
}
let futures_iterator = self
.repos
.iter()
.filter(|repo| match self.has_remotes(repo) {
Some(false) => {
println!(
"{} {} {}",
style(t!("Skipping")).yellow().bold(),
repo.display(),
t!("because it has no remotes")
);
false
}
_ => true, // repo has remotes or command to check for remotes has failed. proceed to pull anyway.
})
.map(|repo| self.pull_repo(ctx, repo));
let stream_of_futures = if let Some(limit) = ctx.config().git_concurrency_limit() {
iter(futures_iterator).buffer_unordered(limit).boxed()
} else {
futures_iterator.collect::<FuturesUnordered<_>>().boxed()
};
let basic_rt = runtime::Runtime::new()?;
let results = basic_rt.block_on(async { stream_of_futures.collect::<Vec<Result<()>>>().await });
let error = results.into_iter().find(std::result::Result::is_err);
error.unwrap_or(Ok(()))
}
}

45
src/steps/go.rs Normal file
View File

@@ -0,0 +1,45 @@
use std::path::PathBuf;
use std::process::Command;
use color_eyre::eyre::Result;
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::terminal::print_separator;
use crate::utils;
use crate::utils::PathExt;
/// <https://github.com/Gelio/go-global-update>
pub fn run_go_global_update(ctx: &ExecutionContext) -> Result<()> {
let go_global_update = require_go_bin("go-global-update")?;
print_separator("go-global-update");
ctx.execute(go_global_update).status_checked()
}
/// <https://github.com/nao1215/gup>
pub fn run_go_gup(ctx: &ExecutionContext) -> Result<()> {
let gup = require_go_bin("gup")?;
print_separator("gup");
ctx.execute(gup).arg("update").status_checked()
}
/// Get the path of a Go binary.
fn require_go_bin(name: &str) -> Result<PathBuf> {
utils::require(name).or_else(|_| {
let go = utils::require("go")?;
// TODO: Does this work? `go help gopath` says that:
// > The GOPATH environment variable lists places to look for Go code.
// > On Unix, the value is a colon-separated string.
// > On Windows, the value is a semicolon-separated string.
// > On Plan 9, the value is a list.
// Should we also fallback to the env variable?
let gopath_output = Command::new(go).args(["env", "GOPATH"]).output_checked_utf8()?;
let gopath = gopath_output.stdout.trim();
PathBuf::from(gopath).join("bin").join(name).require()
})
}

View File

@@ -1,10 +1,9 @@
use crate::error::TopgradeError;
use crate::terminal::print_separator;
use crate::utils::require;
use anyhow::Result;
use color_eyre::eyre::Result;
use rust_i18n::t;
use crate::execution_context::ExecutionContext;
use crate::executor::ExecutorOutput;
const UPGRADE_KAK: &str = include_str!("upgrade.kak");
@@ -13,19 +12,10 @@ pub fn upgrade_kak_plug(ctx: &ExecutionContext) -> Result<()> {
print_separator("Kakoune");
let mut command = ctx.run_type().execute(&kak);
command.args(["-ui", "dummy", "-e", UPGRADE_KAK]);
// TODO: Why suppress output for this command?
ctx.execute(kak).args(["-ui", "dummy", "-e", UPGRADE_KAK]).output()?;
let output = command.output()?;
if let ExecutorOutput::Wet(output) = output {
let status = output.status;
if !status.success() {
return Err(TopgradeError::ProcessFailed(status).into());
} else {
println!("Plugins upgraded")
}
}
println!("{}", t!("Plugins upgraded"));
Ok(())
}

View File

@@ -2,6 +2,7 @@ pub mod containers;
pub mod emacs;
pub mod generic;
pub mod git;
pub mod go;
pub mod kakoune;
pub mod node;
pub mod os;

View File

@@ -1,66 +1,101 @@
#![allow(unused_imports)]
#[cfg(unix)]
use std::os::unix::prelude::MetadataExt;
use std::fmt::Display;
#[cfg(target_os = "linux")]
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::process::Command;
use anyhow::Result;
use directories::BaseDirs;
use log::debug;
#[cfg(unix)]
use crate::HOME_DIR;
use color_eyre::eyre::Result;
#[cfg(target_os = "linux")]
use nix::unistd::Uid;
use rust_i18n::t;
use semver::Version;
use tracing::debug;
use crate::executor::{CommandExt, RunType};
use crate::terminal::print_separator;
use crate::command::CommandExt;
use crate::terminal::{print_info, print_separator};
use crate::utils::{require, PathExt};
use crate::{error::SkipStep, execution_context::ExecutionContext};
enum NPMVariant {
Npm,
Pnpm,
}
impl NPMVariant {
const fn short_name(&self) -> &str {
match self {
NPMVariant::Npm => "npm",
NPMVariant::Pnpm => "pnpm",
}
}
const fn is_npm(&self) -> bool {
matches!(self, NPMVariant::Npm)
}
}
impl Display for NPMVariant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.short_name())
}
}
#[allow(clippy::upper_case_acronyms)]
struct NPM {
command: PathBuf,
variant: NPMVariant,
}
impl NPM {
fn new(command: PathBuf) -> Self {
Self { command }
fn new(command: PathBuf, variant: NPMVariant) -> Self {
Self { command, variant }
}
/// Is the “NPM” version larger than 8.11.0?
fn is_npm_8(&self) -> bool {
let v = self.version();
self.variant.is_npm() && matches!(v, Ok(v) if v >= Version::new(8, 11, 0))
}
/// Get the most suitable “global location” argument
/// of this NPM instance.
///
/// If the “NPM” version is larger than 8.11.0, we use
/// `--location=global`; otherwise, use `-g`.
fn global_location_arg(&self) -> &str {
if self.is_npm_8() {
"--location=global"
} else {
"-g"
}
}
#[cfg(target_os = "linux")]
fn root(&self) -> Result<PathBuf> {
let version = self.version()?;
let args = if version < Version::new(8, 11, 0) {
["root", "-g"]
} else {
["root", "--location=global"]
};
let args = ["root", self.global_location_arg()];
Command::new(&self.command)
.args(args)
.check_output()
.map(|s| PathBuf::from(s.trim()))
.output_checked_utf8()
.map(|s| PathBuf::from(s.stdout.trim()))
}
fn version(&self) -> Result<Version> {
let version_str = Command::new(&self.command)
.args(["--version"])
.check_output()
.map(|s| s.trim().to_owned());
Version::parse(&version_str?).map_err(|err| err.into())
.output_checked_utf8()
.map(|s| s.stdout.trim().to_owned());
Version::parse(&version_str?).map_err(std::convert::Into::into)
}
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
print_separator("Node Package Manager");
let version = self.version()?;
let args = if version < Version::new(8, 11, 0) {
["update", "-g"]
} else {
["update", "--location=global"]
};
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
let args = ["update", self.global_location_arg()];
if use_sudo {
run_type.execute("sudo").args(args).check_run()?;
let sudo = ctx.require_sudo()?;
sudo.execute(ctx, &self.command)?.args(args).status_checked()?;
} else {
run_type.execute(&self.command).args(args).check_run()?;
ctx.execute(&self.command).args(args).status_checked()?;
}
Ok(())
@@ -70,7 +105,7 @@ impl NPM {
pub fn should_use_sudo(&self) -> Result<bool> {
let npm_root = self.root()?;
if !npm_root.exists() {
return Err(SkipStep(format!("NPM root at {} doesn't exist", npm_root.display(),)).into());
return Err(SkipStep(format!("{} root at {} doesn't exist", self.variant, npm_root.display())).into());
}
let metadata = std::fs::metadata(&npm_root)?;
@@ -82,15 +117,22 @@ impl NPM {
struct Yarn {
command: PathBuf,
yarn: Option<PathBuf>,
}
impl Yarn {
fn new(command: PathBuf) -> Self {
Self {
command,
yarn: require("yarn").ok(),
}
Self { command }
}
fn has_global_subcmd(&self) -> bool {
// Get the version of Yarn. After Yarn 2.x (berry),
// “yarn global” has been replaced with “yarn dlx”.
//
// As “yarn dlx” don't need to “upgrade”, we
// ignore the whole task if Yarn is 2.x or above.
let version = Command::new(&self.command).args(["--version"]).output_checked_utf8();
matches!(version, Ok(ver) if ver.stdout.starts_with('1') || ver.stdout.starts_with('0'))
}
#[cfg(target_os = "linux")]
@@ -98,22 +140,18 @@ impl Yarn {
let args = ["global", "dir"];
Command::new(&self.command)
.args(args)
.check_output()
.map(|s| PathBuf::from(s.trim()))
.output_checked_utf8()
.map(|s| PathBuf::from(s.stdout.trim()))
}
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
print_separator("Yarn Package Manager");
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
let args = ["global", "upgrade"];
if use_sudo {
run_type
.execute("sudo")
.arg(self.yarn.as_ref().unwrap_or(&self.command))
.args(args)
.check_run()?;
let sudo = ctx.require_sudo()?;
sudo.execute(ctx, &self.command)?.args(args).status_checked()?;
} else {
run_type.execute(&self.command).args(args).check_run()?;
ctx.execute(&self.command).args(args).status_checked()?;
}
Ok(())
@@ -123,7 +161,7 @@ impl Yarn {
pub fn should_use_sudo(&self) -> Result<bool> {
let yarn_root = self.root()?;
if !yarn_root.exists() {
return Err(SkipStep(format!("NPM root at {} doesn't exist", yarn_root.display(),)).into());
return Err(SkipStep(format!("Yarn root at {} doesn't exist", yarn_root.display(),)).into());
}
let metadata = std::fs::metadata(&yarn_root)?;
@@ -133,6 +171,88 @@ impl Yarn {
}
}
struct Deno {
command: PathBuf,
}
impl Deno {
fn new(command: PathBuf) -> Self {
Self { command }
}
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let mut args = vec![];
let version = ctx.config().deno_version();
if let Some(version) = version {
let bin_version = self.version()?;
if bin_version >= Version::new(2, 0, 0) {
args.push(version);
} else if bin_version >= Version::new(1, 6, 0) {
match version {
"stable" => { /* do nothing, as stable is the default channel to upgrade */ }
"rc" => {
return Err(SkipStep(
"Deno (1.6.0-2.0.0) cannot be upgraded to a release candidate".to_string(),
)
.into());
}
"canary" => args.push("--canary"),
_ => {
if Version::parse(version).is_err() {
return Err(SkipStep("Invalid Deno version".to_string()).into());
}
args.push("--version");
args.push(version);
}
}
} else if bin_version >= Version::new(1, 0, 0) {
match version {
"stable" | "rc" | "canary" => {
// Prior to v1.6.0, `deno upgrade` is not able fetch the latest tag version.
return Err(
SkipStep("Deno (1.0.0-1.6.0) cannot be upgraded to a named channel".to_string()).into(),
);
}
_ => {
if Version::parse(version).is_err() {
return Err(SkipStep("Invalid Deno version".to_string()).into());
}
args.push("--version");
args.push(version);
}
}
} else {
// v0.x cannot be upgraded with `deno upgrade` to v1.x or v2.x
// nor can be upgraded to a specific version.
return Err(SkipStep("Unsupported Deno version".to_string()).into());
}
}
ctx.execute(&self.command).arg("upgrade").args(args).status_checked()?;
Ok(())
}
/// Get the version of Deno.
///
/// This function will return the version of Deno installed on the system.
/// The version is parsed from the output of `deno -V`.
///
/// ```sh
/// deno -V # deno 1.6.0
/// ```
fn version(&self) -> Result<Version> {
let version_str = Command::new(&self.command)
.args(["-V"])
.output_checked_utf8()
.map(|s| s.stdout.trim().to_owned().split_off(5)); // remove "deno " prefix
Version::parse(&version_str?).map_err(std::convert::Into::into)
}
}
#[cfg(target_os = "linux")]
fn should_use_sudo(npm: &NPM, ctx: &ExecutionContext) -> Result<bool> {
if npm.should_use_sudo()? {
@@ -162,42 +282,108 @@ fn should_use_sudo_yarn(yarn: &Yarn, ctx: &ExecutionContext) -> Result<bool> {
}
pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
let npm = require("pnpm").or_else(|_| require("npm")).map(NPM::new)?;
let npm = require("npm").map(|b| NPM::new(b, NPMVariant::Npm))?;
print_separator(t!("Node Package Manager"));
#[cfg(target_os = "linux")]
{
npm.upgrade(ctx.run_type(), should_use_sudo(&npm, ctx)?)
npm.upgrade(ctx, should_use_sudo(&npm, ctx)?)
}
#[cfg(not(target_os = "linux"))]
{
npm.upgrade(ctx.run_type(), false)
npm.upgrade(ctx, false)
}
}
pub fn run_pnpm_upgrade(ctx: &ExecutionContext) -> Result<()> {
let pnpm = require("pnpm").map(|b| NPM::new(b, NPMVariant::Pnpm))?;
print_separator(t!("Performant Node Package Manager"));
#[cfg(target_os = "linux")]
{
pnpm.upgrade(ctx, should_use_sudo(&pnpm, ctx)?)
}
#[cfg(not(target_os = "linux"))]
{
pnpm.upgrade(ctx, false)
}
}
pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
let yarn = require("yarn").map(Yarn::new)?;
if !yarn.has_global_subcmd() {
debug!("Yarn is 2.x or above, skipping global upgrade");
return Ok(());
}
print_separator(t!("Yarn Package Manager"));
#[cfg(target_os = "linux")]
{
yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?)
yarn.upgrade(ctx, should_use_sudo_yarn(&yarn, ctx)?)
}
#[cfg(not(target_os = "linux"))]
{
yarn.upgrade(ctx.run_type(), false)
yarn.upgrade(ctx, false)
}
}
pub fn deno_upgrade(ctx: &ExecutionContext) -> Result<()> {
let deno = require("deno")?;
let deno_dir = ctx.base_dirs().home_dir().join(".deno");
let deno = require("deno").map(Deno::new)?;
let deno_dir = HOME_DIR.join(".deno");
if !deno.canonicalize()?.is_descendant_of(&deno_dir) {
let skip_reason = SkipStep("Deno installed outside of .deno directory".to_string());
if !deno.command.canonicalize()?.is_descendant_of(&deno_dir) {
let skip_reason = SkipStep(t!("Deno installed outside of .deno directory").to_string());
return Err(skip_reason.into());
}
print_separator("Deno");
ctx.run_type().execute(&deno).arg("upgrade").check_run()
deno.upgrade(ctx)
}
/// There is no `volta upgrade` command, so we need to upgrade each package
pub fn run_volta_packages_upgrade(ctx: &ExecutionContext) -> Result<()> {
let volta = require("volta")?;
print_separator("Volta");
if ctx.run_type().dry() {
print_info(t!("Updating Volta packages..."));
return Ok(());
}
let list_output = ctx
.execute(&volta)
.args(["list", "--format=plain"])
.output_checked_utf8()?
.stdout;
let installed_packages: Vec<&str> = list_output
.lines()
.filter_map(|line| {
// format is 'kind package@version ...'
let mut parts = line.split_whitespace();
parts.next();
let package_part = parts.next()?;
let version_index = package_part.rfind('@').unwrap_or(package_part.len());
Some(package_part[..version_index].trim())
})
.collect();
if installed_packages.is_empty() {
print_info(t!("No packages installed with Volta"));
return Ok(());
}
for package in &installed_packages {
ctx.execute(&volta).args(["install", package]).status_checked()?;
}
Ok(())
}

View File

@@ -1,8 +1,10 @@
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::terminal::print_separator;
use crate::utils::require;
use crate::Step;
use anyhow::Result;
use crate::utils::which;
use color_eyre::Result;
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
//let pkg = require("pkg")?;
@@ -10,28 +12,26 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator("Termux Packages");
let is_nala = pkg.end_with("nala");
let is_nala = pkg.ends_with("nala");
let mut command = ctx.run_type().execute(&pkg);
let mut command = ctx.execute(&pkg);
command.arg("upgrade");
if ctx.config().yes(Step::System) {
command.arg("-y");
}
command.check_run()?;
command.status_checked()?;
if !is_nala {
if ctx.config().cleanup() {
ctx.run_type().execute(&pkg).arg("clean").check_run()?;
if !is_nala && ctx.config().cleanup() {
ctx.execute(&pkg).arg("clean").status_checked()?;
let apt = require("apt")?;
let mut command = ctx.run_type().execute(&apt);
command.arg("autoremove");
if ctx.config().yes(Step::System) {
command.arg("-y");
}
command.check_run()?;
let apt = require("apt")?;
let mut command = ctx.execute(apt);
command.arg("autoremove");
if ctx.config().yes(Step::System) {
command.arg("-y");
}
command.status_checked()?;
}
Ok(())

View File

@@ -1,15 +1,18 @@
use std::env::var_os;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::Command;
use anyhow::Result;
use color_eyre::eyre;
use color_eyre::eyre::{Context, Result};
use rust_i18n::t;
use walkdir::WalkDir;
use crate::command::CommandExt;
use crate::error::TopgradeError;
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::utils::which;
use crate::{config, Step};
use crate::{config, output_changed_message};
fn get_execution_path() -> OsString {
let mut path = OsString::from("/usr/bin:");
@@ -29,14 +32,12 @@ pub struct YayParu {
impl ArchPackageManager for YayParu {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
if ctx.config().show_arch_news() {
Command::new(&self.executable)
ctx.execute(&self.executable)
.arg("-Pw")
.spawn()
.and_then(|mut p| p.wait())
.ok();
.status_checked_with_codes(&[1, 0])?;
}
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command
.arg("--pacman")
@@ -48,15 +49,15 @@ impl ArchPackageManager for YayParu {
if ctx.config().yes(Step::System) {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
if ctx.config().cleanup() {
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command.arg("--pacman").arg(&self.pacman).arg("-Scc");
if ctx.config().yes(Step::System) {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
}
Ok(())
@@ -72,13 +73,44 @@ impl YayParu {
}
}
pub struct GarudaUpdate {
executable: PathBuf,
}
impl ArchPackageManager for GarudaUpdate {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let mut command = ctx.execute(&self.executable);
command
.env("PATH", get_execution_path())
.env("UPDATE_AUR", "1")
.env("SKIP_MIRRORLIST", "1");
if ctx.config().yes(Step::System) {
command.env("PACMAN_NOCONFIRM", "1");
}
command.args(ctx.config().garuda_update_arguments().split_whitespace());
command.status_checked()?;
Ok(())
}
}
impl GarudaUpdate {
fn get() -> Option<Self> {
Some(Self {
executable: which("garuda-update")?,
})
}
}
pub struct Trizen {
executable: PathBuf,
}
impl ArchPackageManager for Trizen {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command
.arg("-Syu")
@@ -88,15 +120,15 @@ impl ArchPackageManager for Trizen {
if ctx.config().yes(Step::System) {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
if ctx.config().cleanup() {
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command.arg("-Sc");
if ctx.config().yes(Step::System) {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
}
Ok(())
@@ -112,29 +144,26 @@ impl Trizen {
}
pub struct Pacman {
sudo: PathBuf,
executable: PathBuf,
}
impl ArchPackageManager for Pacman {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let mut command = ctx.run_type().execute(&self.sudo);
command
.arg(&self.executable)
.arg("-Syu")
.env("PATH", get_execution_path());
let sudo = ctx.require_sudo()?;
let mut command = sudo.execute(ctx, &self.executable)?;
command.arg("-Syu").env("PATH", get_execution_path());
if ctx.config().yes(Step::System) {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
if ctx.config().cleanup() {
let mut command = ctx.run_type().execute(&self.sudo);
command.arg(&self.executable).arg("-Scc");
let mut command = sudo.execute(ctx, &self.executable)?;
command.arg("-Scc");
if ctx.config().yes(Step::System) {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
}
Ok(())
@@ -142,10 +171,9 @@ impl ArchPackageManager for Pacman {
}
impl Pacman {
pub fn get(ctx: &ExecutionContext) -> Option<Self> {
pub fn get() -> Option<Self> {
Some(Self {
executable: which("powerpill").unwrap_or_else(|| PathBuf::from("pacman")),
sudo: ctx.sudo().to_owned()?,
})
}
}
@@ -164,7 +192,7 @@ impl Pikaur {
impl ArchPackageManager for Pikaur {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command
.arg("-Syu")
@@ -175,15 +203,15 @@ impl ArchPackageManager for Pikaur {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
if ctx.config().cleanup() {
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command.arg("-Sc");
if ctx.config().yes(Step::System) {
command.arg("--noconfirm");
}
command.check_run()?;
command.status_checked()?;
}
Ok(())
@@ -203,7 +231,7 @@ impl Pamac {
}
impl ArchPackageManager for Pamac {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command
.arg("upgrade")
@@ -214,15 +242,15 @@ impl ArchPackageManager for Pamac {
command.arg("--no-confirm");
}
command.check_run()?;
command.status_checked()?;
if ctx.config().cleanup() {
let mut command = ctx.run_type().execute(&self.executable);
let mut command = ctx.execute(&self.executable);
command.arg("clean");
if ctx.config().yes(Step::System) {
command.arg("--no-confirm");
}
command.check_run()?;
command.status_checked()?;
}
Ok(())
@@ -231,46 +259,67 @@ impl ArchPackageManager for Pamac {
pub struct Aura {
executable: PathBuf,
sudo: PathBuf,
}
impl Aura {
fn get(ctx: &ExecutionContext) -> Option<Self> {
fn get() -> Option<Self> {
Some(Self {
executable: which("aura")?,
sudo: ctx.sudo().to_owned()?,
})
}
}
impl ArchPackageManager for Aura {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let sudo = which("sudo").unwrap_or(PathBuf::new());
let mut aur_update = ctx.run_type().execute(&sudo);
use semver::Version;
if sudo.ends_with("sudo") {
aur_update
.arg(&self.executable)
.arg("-Au")
let version_cmd_output = ctx.execute(&self.executable).arg("--version").output_checked_utf8()?;
// Output will be something like: "aura x.x.x\n"
let version_cmd_stdout = version_cmd_output.stdout;
let version_str = version_cmd_stdout.trim_start_matches("aura ").trim_end();
let version = Version::parse(version_str)
.wrap_err_with(|| output_changed_message!("aura --version", "invalid version"))?;
// Aura, since version 4.0.6, no longer needs sudo.
//
// https://github.com/fosskers/aura/releases/tag/v4.0.6
let version_no_sudo = Version::new(4, 0, 6);
if version >= version_no_sudo {
let mut cmd = ctx.execute(&self.executable);
cmd.arg("-Au")
.args(ctx.config().aura_aur_arguments().split_whitespace());
if ctx.config().yes(Step::System) {
aur_update.arg("--noconfirm");
cmd.arg("--noconfirm");
}
cmd.status_checked()?;
aur_update.check_run()?;
let mut cmd = ctx.execute(&self.executable);
cmd.arg("-Syu")
.args(ctx.config().aura_pacman_arguments().split_whitespace());
if ctx.config().yes(Step::System) {
cmd.arg("--noconfirm");
}
cmd.status_checked()?;
} else {
println!("Aura requires sudo installed to work with AUR packages")
}
let sudo = ctx.require_sudo()?;
let mut pacman_update = ctx.run_type().execute(&self.sudo);
pacman_update
.arg(&self.executable)
.arg("-Syu")
.args(ctx.config().aura_pacman_arguments().split_whitespace());
if ctx.config().yes(Step::System) {
pacman_update.arg("--noconfirm");
let mut cmd = sudo.execute(ctx, &self.executable)?;
cmd.arg("-Au")
.args(ctx.config().aura_aur_arguments().split_whitespace());
if ctx.config().yes(Step::System) {
cmd.arg("--noconfirm");
}
cmd.status_checked()?;
let mut cmd = sudo.execute(ctx, &self.executable)?;
cmd.arg("-Syu")
.args(ctx.config().aura_pacman_arguments().split_whitespace());
if ctx.config().yes(Step::System) {
cmd.arg("--noconfirm");
}
cmd.status_checked()?;
}
pacman_update.check_run()?;
Ok(())
}
@@ -284,27 +333,29 @@ pub fn get_arch_package_manager(ctx: &ExecutionContext) -> Option<Box<dyn ArchPa
let pacman = which("powerpill").unwrap_or_else(|| PathBuf::from("pacman"));
match ctx.config().arch_package_manager() {
config::ArchPackageManager::Autodetect => YayParu::get("paru", &pacman)
config::ArchPackageManager::Autodetect => GarudaUpdate::get()
.map(box_package_manager)
.or_else(|| YayParu::get("paru", &pacman).map(box_package_manager))
.or_else(|| YayParu::get("yay", &pacman).map(box_package_manager))
.or_else(|| Trizen::get().map(box_package_manager))
.or_else(|| Pikaur::get().map(box_package_manager))
.or_else(|| Pamac::get().map(box_package_manager))
.or_else(|| Pacman::get(ctx).map(box_package_manager))
.or_else(|| Aura::get(ctx).map(box_package_manager)),
.or_else(|| Pacman::get().map(box_package_manager))
.or_else(|| Aura::get().map(box_package_manager)),
config::ArchPackageManager::GarudaUpdate => GarudaUpdate::get().map(box_package_manager),
config::ArchPackageManager::Trizen => Trizen::get().map(box_package_manager),
config::ArchPackageManager::Paru => YayParu::get("paru", &pacman).map(box_package_manager),
config::ArchPackageManager::Yay => YayParu::get("yay", &pacman).map(box_package_manager),
config::ArchPackageManager::Pacman => Pacman::get(ctx).map(box_package_manager),
config::ArchPackageManager::Pacman => Pacman::get().map(box_package_manager),
config::ArchPackageManager::Pikaur => Pikaur::get().map(box_package_manager),
config::ArchPackageManager::Pamac => Pamac::get().map(box_package_manager),
config::ArchPackageManager::Aura => Aura::get(ctx).map(box_package_manager),
config::ArchPackageManager::Aura => Aura::get().map(box_package_manager),
}
}
pub fn upgrade_arch_linux(ctx: &ExecutionContext) -> Result<()> {
let package_manager =
get_arch_package_manager(ctx).ok_or_else(|| anyhow::Error::from(TopgradeError::FailedGettingPackageManager))?;
get_arch_package_manager(ctx).ok_or_else(|| eyre::Report::from(TopgradeError::FailedGettingPackageManager))?;
package_manager.upgrade(ctx)
}
@@ -321,7 +372,7 @@ pub fn show_pacnew() {
.peekable();
if iter.peek().is_some() {
println!("\nPacman backup configuration files found:");
println!("\n{}", t!("Pacman backup configuration files found:"));
for entry in iter {
println!("{}", entry.path().display());

View File

@@ -1,26 +1,35 @@
use crate::executor::RunType;
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::terminal::print_separator;
use crate::utils::require_option;
use anyhow::Result;
use std::path::PathBuf;
use std::process::Command;
use color_eyre::eyre::Result;
use rust_i18n::t;
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("DrgaonFly BSD Packages");
run_type
.execute(sudo)
.args(&["/usr/local/sbin/pkg", "upgrade"])
.check_run()
}
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("DragonFly BSD Packages"));
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
if let Some(sudo) = sudo {
println!();
Command::new(sudo)
.args(&["/usr/local/sbin/pkg", "audit", "-Fr"])
.spawn()?
.wait()?;
let sudo = ctx.require_sudo()?;
let mut cmd = sudo.execute(ctx, "/usr/local/sbin/pkg")?;
cmd.arg("upgrade");
if ctx.config().yes(Step::System) {
cmd.arg("-y");
}
Ok(())
cmd.status_checked()
}
pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("DragonFly BSD Audit"));
let sudo = ctx.require_sudo()?;
sudo.execute(ctx, "/usr/local/sbin/pkg")?
.args(["audit", "-Fr"])
.status_checked_with(|status| {
if !status.success() {
println!(
"{}",
t!("The package audit was successful, but vulnerable packages still remain on the system")
);
}
Ok(())
})
}

View File

@@ -1,32 +1,36 @@
use crate::executor::RunType;
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::terminal::print_separator;
use crate::utils::require_option;
use anyhow::Result;
use std::path::PathBuf;
use std::process::Command;
use color_eyre::Result;
use rust_i18n::t;
pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("FreeBSD Update");
run_type
.execute(sudo)
.args(&["/usr/sbin/freebsd-update", "fetch", "install"])
.check_run()
pub fn upgrade_freebsd(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("FreeBSD Update"));
let sudo = ctx.require_sudo()?;
sudo.execute(ctx, "/usr/sbin/freebsd-update")?
.args(["fetch", "install"])
.status_checked()
}
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("FreeBSD Packages");
run_type.execute(sudo).args(&["/usr/sbin/pkg", "upgrade"]).check_run()
}
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("FreeBSD Packages"));
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
if let Some(sudo) = sudo {
println!();
Command::new(sudo)
.args(&["/usr/sbin/pkg", "audit", "-Fr"])
.spawn()?
.wait()?;
let sudo = ctx.require_sudo()?;
let mut command = sudo.execute(ctx, "/usr/sbin/pkg")?;
command.arg("upgrade");
if ctx.config().yes(Step::System) {
command.arg("-y");
}
Ok(())
command.status_checked()
}
pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("FreeBSD Audit"));
let sudo = ctx.require_sudo()?;
sudo.execute(ctx, "/usr/sbin/pkg")?
.args(["audit", "-Fr"])
.status_checked()
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,77 +1,74 @@
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::executor::{CommandExt, RunType};
use crate::step::Step;
use crate::terminal::{print_separator, prompt_yesno};
use crate::{error::TopgradeError, utils::require, Step};
use anyhow::Result;
use log::debug;
use crate::utils::require;
use color_eyre::eyre::Result;
use rust_i18n::t;
use std::collections::HashSet;
use std::fs;
use std::process::Command;
use tracing::debug;
pub fn run_macports(ctx: &ExecutionContext) -> Result<()> {
require("port")?;
let sudo = ctx.sudo().as_ref().unwrap();
let port = require("port")?;
print_separator("MacPorts");
ctx.run_type().execute(sudo).args(&["port", "selfupdate"]).check_run()?;
ctx.run_type()
.execute(sudo)
.args(&["port", "-u", "upgrade", "outdated"])
.check_run()?;
let sudo = ctx.require_sudo()?;
sudo.execute(ctx, &port)?.arg("selfupdate").status_checked()?;
sudo.execute(ctx, &port)?
.args(["-u", "upgrade", "outdated"])
.status_checked()?;
if ctx.config().cleanup() {
ctx.run_type()
.execute(sudo)
.args(&["port", "-N", "reclaim"])
.check_run()?;
sudo.execute(ctx, &port)?.args(["-N", "reclaim"]).status_checked()?;
}
Ok(())
}
pub fn run_mas(run_type: RunType) -> Result<()> {
pub fn run_mas(ctx: &ExecutionContext) -> Result<()> {
let mas = require("mas")?;
print_separator("macOS App Store");
print_separator(t!("macOS App Store"));
run_type.execute(mas).arg("upgrade").check_run()
ctx.execute(mas).arg("upgrade").status_checked()
}
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
print_separator("macOS system update");
print_separator(t!("macOS system update"));
let should_ask = !(ctx.config().yes(Step::System)) || (ctx.config().dry_run());
let should_ask = !(ctx.config().yes(Step::System) || ctx.run_type().dry());
if should_ask {
println!("Finding available software");
println!("{}", t!("Finding available software"));
if system_update_available()? {
let answer = prompt_yesno("A system update is available. Do you wish to install it?")?;
let answer = prompt_yesno(t!("A system update is available. Do you wish to install it?").as_ref())?;
if !answer {
return Ok(());
}
println!();
} else {
println!("No new software available.");
println!("{}", t!("No new software available."));
return Ok(());
}
}
let mut command = ctx.run_type().execute("softwareupdate");
command.args(&["--install", "--all"]);
let mut command = ctx.execute("softwareupdate");
command.args(["--install", "--all"]);
if should_ask {
command.arg("--no-scan");
}
command.check_run()
command.status_checked()
}
fn system_update_available() -> Result<bool> {
let output = Command::new("softwareupdate").arg("--list").output()?;
let output = Command::new("softwareupdate").arg("--list").output_checked_utf8()?;
debug!("{:?}", output);
let status = output.status;
if !status.success() {
return Err(TopgradeError::ProcessFailed(status).into());
}
let string_output = String::from_utf8(output.stderr)?;
debug!("{:?}", string_output);
Ok(!string_output.contains("No new software available"))
Ok(!output.stderr.contains("No new software available"))
}
pub fn run_sparkle(ctx: &ExecutionContext) -> Result<()> {
@@ -81,15 +78,145 @@ pub fn run_sparkle(ctx: &ExecutionContext) -> Result<()> {
for application in (fs::read_dir("/Applications")?).flatten() {
let probe = Command::new(&sparkle)
.args(&["--probe", "--application"])
.args(["--probe", "--application"])
.arg(application.path())
.check_output();
.output_checked_utf8();
if probe.is_ok() {
let mut command = ctx.run_type().execute(&sparkle);
command.args(&["bundle", "--check-immediately", "--application"]);
let mut command = ctx.execute(&sparkle);
command.args(["bundle", "--check-immediately", "--application"]);
command.arg(application.path());
command.spawn()?.wait()?;
command.status_checked()?;
}
}
Ok(())
}
pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
let xcodes = require("xcodes")?;
print_separator("Xcodes");
let should_ask = !(ctx.config().yes(Step::Xcodes) || ctx.run_type().dry());
let releases = ctx.execute(&xcodes).args(["update"]).output_checked_utf8()?.stdout;
let releases_installed: Vec<String> = releases
.lines()
.filter(|r| r.contains("(Installed)"))
.map(String::from)
.collect();
if releases_installed.is_empty() {
println!("{}", t!("No Xcode releases installed."));
return Ok(());
}
let (installed_gm, installed_beta, installed_regular) =
releases_installed
.iter()
.fold((false, false, false), |(gm, beta, regular), release| {
(
gm || release.contains("GM") || release.contains("Release Candidate"),
beta || release.contains("Beta"),
regular
|| !(release.contains("GM")
|| release.contains("Release Candidate")
|| release.contains("Beta")),
)
});
let releases_gm = releases
.lines()
.filter(|&r| r.matches("GM").count() > 0 || r.matches("Release Candidate").count() > 0)
.map(String::from)
.collect();
let releases_beta = releases
.lines()
.filter(|&r| r.matches("Beta").count() > 0)
.map(String::from)
.collect();
let releases_regular = releases
.lines()
.filter(|&r| {
r.matches("GM").count() == 0
&& r.matches("Release Candidate").count() == 0
&& r.matches("Beta").count() == 0
})
.map(String::from)
.collect();
if installed_gm {
process_xcodes_releases(releases_gm, should_ask, ctx)?;
}
if installed_beta {
process_xcodes_releases(releases_beta, should_ask, ctx)?;
}
if installed_regular {
process_xcodes_releases(releases_regular, should_ask, ctx)?;
}
let releases_new = ctx.execute(&xcodes).args(["list"]).output_checked_utf8()?.stdout;
let releases_gm_new_installed: HashSet<_> = releases_new
.lines()
.filter(|release| {
release.contains("(Installed)") && (release.contains("GM") || release.contains("Release Candidate"))
})
.collect();
let releases_beta_new_installed: HashSet<_> = releases_new
.lines()
.filter(|release| release.contains("(Installed)") && release.contains("Beta"))
.collect();
let releases_regular_new_installed: HashSet<_> = releases_new
.lines()
.filter(|release| {
release.contains("(Installed)")
&& !(release.contains("GM") || release.contains("Release Candidate") || release.contains("Beta"))
})
.collect();
for releases_new_installed in [
releases_gm_new_installed,
releases_beta_new_installed,
releases_regular_new_installed,
] {
if should_ask && releases_new_installed.len() == 2 {
let answer_uninstall =
prompt_yesno(t!("Would you like to move the former Xcode release to the trash?").as_ref())?;
if answer_uninstall {
let _ = ctx
.execute(&xcodes)
.args([
"uninstall",
releases_new_installed.iter().next().copied().unwrap_or_default(),
])
.status_checked();
}
}
}
Ok(())
}
pub fn process_xcodes_releases(releases_filtered: Vec<String>, should_ask: bool, ctx: &ExecutionContext) -> Result<()> {
let xcodes = require("xcodes")?;
if releases_filtered.last().map_or(true, |s| !s.contains("(Installed)")) && !releases_filtered.is_empty() {
println!(
"{} {}",
t!("New Xcode release detected:"),
releases_filtered.last().cloned().unwrap_or_default()
);
if should_ask {
let answer_install = prompt_yesno(t!("Would you like to install it?").as_ref())?;
if answer_install {
let _ = ctx
.execute(xcodes)
.args(["install", &releases_filtered.last().cloned().unwrap_or_default()])
.status_checked();
}
println!();
}
}
Ok(())
}

View File

@@ -14,7 +14,7 @@ pub mod macos;
pub mod openbsd;
#[cfg(unix)]
pub mod unix;
#[cfg(target_os = "windows")]
#[cfg(windows)]
pub mod windows;
#[cfg(windows)]

View File

@@ -1,17 +1,49 @@
use crate::executor::RunType;
use crate::command::CommandExt;
use crate::execution_context::ExecutionContext;
use crate::terminal::print_separator;
use crate::utils::require_option;
use anyhow::Result;
use std::path::PathBuf;
use color_eyre::eyre::Result;
use rust_i18n::t;
use std::fs;
use tracing::debug;
pub fn upgrade_openbsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("OpenBSD Update");
run_type.execute(sudo).args(&["/usr/sbin/sysupgrade", "-n"]).check_run()
fn is_openbsd_current() -> Result<bool> {
let motd_content = fs::read_to_string("/etc/motd")?;
let is_current = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
debug!("OpenBSD is -current/-beta: {is_current}");
Ok(is_current)
}
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo, String::from("No sudo detected"))?;
print_separator("OpenBSD Packages");
run_type.execute(sudo).args(&["/usr/sbin/pkg_add", "-u"]).check_run()
pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("OpenBSD Update"));
let sudo = ctx.require_sudo()?;
let is_current = is_openbsd_current()?;
if is_current {
sudo.execute(ctx, "/usr/sbin/sysupgrade")?.arg("-sn").status_checked()
} else {
sudo.execute(ctx, "/usr/sbin/syspatch")?.status_checked()
}
}
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("OpenBSD Packages"));
let sudo = ctx.require_sudo()?;
let is_current = is_openbsd_current()?;
if ctx.config().cleanup() {
sudo.execute(ctx, "/usr/sbin/pkg_delete")?.arg("-ac").status_checked()?;
}
let mut command = sudo.execute(ctx, "/usr/sbin/pkg_add")?;
command.arg("-u");
if is_current {
command.arg("-Dsnap");
}
command.status_checked()
}

View File

@@ -6,4 +6,4 @@ VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
HOME_URL="https://amazonlinux.com/"

View File

@@ -1,6 +0,0 @@
NAME="Anarchy Linux"
PRETTY_NAME="Anarchy Linux"
ID=anarchy
ID_LIKE=anarchylinux
ANSI_COLOR="0;36"
HOME_URL="https://anarchylinux.org/"

View File

@@ -1,10 +0,0 @@
NAME="Antergos Linux"
VERSION="18.7-ISO-Rolling"
ID="antergos"
ID_LIKE="arch"
PRETTY_NAME="Antergos Linux"
CPE_NAME="cpe:/o:antergosproject:antergos:18.7"
ANSI_COLOR="1;34;40"
HOME_URL="antergos.com"
SUPPORT_URL="forum.antergos.com"
BUG_REPORT_URL="@antergos"

View File

@@ -0,0 +1,10 @@
PRETTY_NAME="AOSC OS (12.2.2)"
NAME="AOSC OS"
VERSION_ID="12.2.2"
VERSION="12.2.2 (localhost)"
BUILD_ID="20250916"
ID=aosc
ANSI_COLOR="1;36"
HOME_URL="https://aosc.io/"
SUPPORT_URL="https://github.com/AOSC-Dev/aosc-os-abbs"
BUG_REPORT_URL="https://github.com/AOSC-Dev/aosc-os-abbs/issues"

View File

@@ -8,4 +8,4 @@ HOME_URL="https://www.archlinux32.org/"
DOCUMENTATION_URL="https://wiki.archlinux.org/"
SUPPORT_URL="https://bbs.archlinux32.org/"
BUG_REPORT_URL="https://bugs.archlinux32.org/"
LOGO=archlinux
LOGO=archlinux

View File

@@ -0,0 +1,23 @@
NAME="Aurora"
VERSION="latest-41.20250210.4 (Kinoite)"
RELEASE_TYPE=stable
ID=aurora
ID_LIKE="fedora"
VERSION_ID=41
VERSION_CODENAME=""
PLATFORM_ID="platform:f41"
PRETTY_NAME="Aurora (Version: latest-41.20250210.4 / FROM Fedora Kinoite 41)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:universal-blue:aurora:41"
DEFAULT_HOSTNAME="aurora"
HOME_URL="https://getaurora.dev/"
DOCUMENTATION_URL="https://docs.getaurora.dev"
SUPPORT_URL="https://github.com/ublue-os/aurora/issues/"
BUG_REPORT_URL="https://github.com/ublue-os/aurora/issues/"
SUPPORT_END=2025-12-15
VARIANT="Kinoite"
VARIANT_ID=aurora
OSTREE_VERSION='latest-41.20250210.4'
BUILD_ID="fc1570c"
IMAGE_ID="aurora"

View File

@@ -0,0 +1,25 @@
NAME="Bazzite"
VERSION="41.20250208.0 (Kinoite)"
RELEASE_TYPE=stable
ID=bazzite
ID_LIKE="fedora"
VERSION_ID=41
VERSION_CODENAME="Holographic"
PLATFORM_ID="platform:f41"
PRETTY_NAME="Bazzite 41 (FROM Fedora Kinoite)"
ANSI_COLOR="0;38;2;138;43;226"
LOGO=bazzite-logo-icon
CPE_NAME="cpe:/o:universal-blue:bazzite:41"
DEFAULT_HOSTNAME="bazzite"
HOME_URL="https://bazzite.gg"
DOCUMENTATION_URL="https://docs.bazzite.gg"
SUPPORT_URL="https://discord.bazzite.gg"
BUG_REPORT_URL="https://github.com/ublue-os/bazzite/issues/"
SUPPORT_END=2025-12-15
VARIANT="Kinoite"
VARIANT_ID=bazzite-nvidia-open
OSTREE_VERSION='41.20250208.0'
BUILD_ID="Stable (F41.20250208)"
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"
BUILD_ID="Stable (F41.20250208)"
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"

View File

@@ -0,0 +1,24 @@
NAME="Bluefin"
VERSION="41.20250216.1 (Silverblue)"
RELEASE_TYPE=stable
ID=bluefin
ID_LIKE="fedora"
VERSION_ID=41
VERSION_CODENAME="Archaeopteryx"
PLATFORM_ID="platform:f41"
PRETTY_NAME="Bluefin (Version: 41.20250216.1 / FROM Fedora Silverblue 41)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:universal-blue:bluefin:41"
DEFAULT_HOSTNAME="bluefin"
HOME_URL="https://projectbluefin.io"
DOCUMENTATION_URL="https://docs.projectbluefin.io"
SUPPORT_URL="https://github.com/ublue-os/bluefin/issues/"
BUG_REPORT_URL="https://github.com/ublue-os/bluefin/issues/"
SUPPORT_END=2025-12-15
VARIANT="Silverblue"
VARIANT_ID=bluefin
OSTREE_VERSION='41.20250216.1'
BUILD_ID="185146a"
IMAGE_ID="bluefin"
IMAGE_VERSION="41.20250216.1"

View File

@@ -0,0 +1,11 @@
NAME="CachyOS Linux"
PRETTY_NAME="CachyOS"
ID=cachyos
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://cachyos.org/"
DOCUMENTATION_URL="https://wiki.cachyos.org/"
SUPPORT_URL="https://discuss.cachyos.org/"
BUG_REPORT_URL="https://github.com/cachyos"
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
LOGO=cachyos

View File

@@ -13,4 +13,3 @@ CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

View File

@@ -0,0 +1,23 @@
NAME="Fedora Linux"
VERSION="41.20250117.3.0 (CoreOS)"
RELEASE_TYPE=stable
ID=fedora
VERSION_ID=41
VERSION_CODENAME=""
PLATFORM_ID="platform:f41"
PRETTY_NAME="Fedora CoreOS 41.20250117.3.0 (uCore)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:41"
HOME_URL="https://getfedora.org/coreos/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora-coreos/"
SUPPORT_URL="https://github.com/coreos/fedora-coreos-tracker/"
BUG_REPORT_URL="https://github.com/coreos/fedora-coreos-tracker/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=41
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=41
SUPPORT_END=2025-12-15
VARIANT="CoreOS"
VARIANT_ID=coreos
OSTREE_VERSION='41.20250117.3.0'

View File

@@ -1,8 +1,9 @@
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="http://www.debian.org/"
SUPPORT_URL="http://www.debian.org/support"
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

View File

@@ -0,0 +1,8 @@
PRETTY_NAME="Deepin 20.9"
NAME="Deepin"
VERSION_ID="20.9"
VERSION="20.9"
VERSION_CODENAME="apricot"
ID=Deepin
HOME_URL="https://www.deepin.org/"
BUG_REPORT_URL="https://bbs.deepin.org/"

View File

@@ -0,0 +1,22 @@
NAME="Fedora Linux"
VERSION="39.20240415.0 (IoT Edition)"
ID=fedora
VERSION_ID=39
VERSION_CODENAME=""
PLATFORM_ID="platform:f39"
PRETTY_NAME="Fedora Linux 39.20240415.0 (IoT Edition)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:39"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f39/system-administrators-guide/"
SUPPORT_URL="https://ask.fedoraproject.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=39
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=39
SUPPORT_END=2024-11-12
VARIANT="IoT Edition"
VARIANT_ID=iot
OSTREE_VERSION='39.20240415.0'

Some files were not shown because too many files have changed in this diff Show More