mnenv 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/PROPOSAL.md +197 -0
- data/README.adoc +168 -461
- data/Rakefile +7 -4
- data/bin/Install-Mnenv.ps1 +145 -0
- data/bin/mnenv-installer +72 -0
- data/completions/bash +47 -0
- data/completions/fish +29 -0
- data/completions/powershell.ps1 +94 -0
- data/completions/zsh +43 -0
- data/lib/mnenv/binary_repository.rb +189 -0
- data/lib/mnenv/chocolatey.rb +7 -0
- data/lib/mnenv/cli.rb +110 -10
- data/lib/mnenv/commands/available_command.rb +169 -0
- data/lib/mnenv/commands/chocolatey_command.rb +4 -5
- data/lib/mnenv/commands/gemfile_command.rb +4 -5
- data/lib/mnenv/commands/homebrew_command.rb +4 -5
- data/lib/mnenv/commands/install_command.rb +234 -0
- data/lib/mnenv/commands/snap_command.rb +5 -7
- data/lib/mnenv/commands/uninstall_command.rb +111 -0
- data/lib/mnenv/commands/version_command.rb +167 -0
- data/lib/mnenv/commands.rb +9 -4
- data/lib/mnenv/gemfile/extractor.rb +10 -3
- data/lib/mnenv/gemfile.rb +8 -0
- data/lib/mnenv/gemfile_repository.rb +0 -2
- data/lib/mnenv/homebrew.rb +7 -0
- data/lib/mnenv/installer/base.rb +62 -0
- data/lib/mnenv/installer/factory.rb +46 -0
- data/lib/mnenv/installer.rb +12 -0
- data/lib/mnenv/installers/binary_installer.rb +242 -0
- data/lib/mnenv/installers/gemfile_installer.rb +76 -0
- data/lib/mnenv/json_formatter.rb +3 -13
- data/lib/mnenv/logger.rb +9 -1
- data/lib/mnenv/models/binary_version.rb +78 -0
- data/lib/mnenv/models/chocolatey_version.rb +7 -0
- data/lib/mnenv/models/gemfile_version.rb +19 -5
- data/lib/mnenv/models/homebrew_version.rb +7 -0
- data/lib/mnenv/models/snap_version.rb +8 -0
- data/lib/mnenv/models/version.rb +16 -0
- data/lib/mnenv/models.rb +7 -5
- data/lib/mnenv/paths.rb +69 -0
- data/lib/mnenv/platform_detector.rb +109 -0
- data/lib/mnenv/repository.rb +50 -35
- data/lib/mnenv/resolver +72 -0
- data/lib/mnenv/shells/base.rb +32 -0
- data/lib/mnenv/shells/bash.rb +72 -0
- data/lib/mnenv/shells/cmd.rb +108 -0
- data/lib/mnenv/shells/factory.rb +82 -0
- data/lib/mnenv/shells/power_shell.rb +110 -0
- data/lib/mnenv/shim_manager.rb +121 -0
- data/lib/mnenv/snap.rb +7 -0
- data/lib/mnenv/snap_repository.rb +2 -19
- data/lib/mnenv/source_registry.rb +69 -0
- data/lib/mnenv/sources.rb +46 -0
- data/lib/mnenv/version.rb +1 -1
- data/lib/mnenv/version_resolver.rb +108 -0
- data/lib/mnenv/versions_manager.rb +92 -0
- data/lib/mnenv.rb +6 -0
- data/mnenv.gemspec +4 -1
- data/scripts/cross-source-switching-test.sh +214 -0
- data/scripts/integration-test.sh +89 -0
- data/scripts/version-switching-test.sh +151 -0
- metadata +85 -247
- data/data/chocolatey/versions.yaml +0 -812
- data/data/gemfile/v1.1.6/Gemfile +0 -4
- data/data/gemfile/v1.1.6/Gemfile.lock.archived +0 -232
- data/data/gemfile/v1.1.7/Gemfile +0 -4
- data/data/gemfile/v1.1.7/Gemfile.lock.archived +0 -235
- data/data/gemfile/v1.1.8/Gemfile +0 -4
- data/data/gemfile/v1.1.8/Gemfile.lock.archived +0 -238
- data/data/gemfile/v1.10.0/Gemfile +0 -5
- data/data/gemfile/v1.10.0/Gemfile.lock.archived +0 -930
- data/data/gemfile/v1.10.1/Gemfile +0 -5
- data/data/gemfile/v1.10.1/Gemfile.lock.archived +0 -929
- data/data/gemfile/v1.10.10/Gemfile +0 -5
- data/data/gemfile/v1.10.10/Gemfile.lock.archived +0 -973
- data/data/gemfile/v1.10.11/Gemfile +0 -5
- data/data/gemfile/v1.10.11/Gemfile.lock.archived +0 -975
- data/data/gemfile/v1.10.2/Gemfile +0 -5
- data/data/gemfile/v1.10.2/Gemfile.lock.archived +0 -939
- data/data/gemfile/v1.10.3/Gemfile +0 -5
- data/data/gemfile/v1.10.3/Gemfile.lock.archived +0 -946
- data/data/gemfile/v1.10.5/Gemfile +0 -5
- data/data/gemfile/v1.10.5/Gemfile.lock.archived +0 -958
- data/data/gemfile/v1.10.6/Gemfile +0 -5
- data/data/gemfile/v1.10.6/Gemfile.lock.archived +0 -969
- data/data/gemfile/v1.10.7/Gemfile +0 -5
- data/data/gemfile/v1.10.7/Gemfile.lock.archived +0 -969
- data/data/gemfile/v1.10.8/Gemfile +0 -5
- data/data/gemfile/v1.10.8/Gemfile.lock.archived +0 -968
- data/data/gemfile/v1.10.9/Gemfile +0 -5
- data/data/gemfile/v1.10.9/Gemfile.lock.archived +0 -972
- data/data/gemfile/v1.11.0/Gemfile +0 -5
- data/data/gemfile/v1.11.0/Gemfile.lock.archived +0 -971
- data/data/gemfile/v1.11.1/Gemfile +0 -5
- data/data/gemfile/v1.11.1/Gemfile.lock.archived +0 -975
- data/data/gemfile/v1.11.4/Gemfile +0 -5
- data/data/gemfile/v1.11.4/Gemfile.lock.archived +0 -1046
- data/data/gemfile/v1.11.5/Gemfile +0 -5
- data/data/gemfile/v1.11.5/Gemfile.lock.archived +0 -1047
- data/data/gemfile/v1.12.10/Gemfile +0 -3
- data/data/gemfile/v1.12.10/Gemfile.lock.archived +0 -1073
- data/data/gemfile/v1.12.3/Gemfile +0 -3
- data/data/gemfile/v1.12.3/Gemfile.lock.archived +0 -1050
- data/data/gemfile/v1.12.4/Gemfile +0 -3
- data/data/gemfile/v1.12.4/Gemfile.lock.archived +0 -1056
- data/data/gemfile/v1.12.5/Gemfile +0 -3
- data/data/gemfile/v1.12.5/Gemfile.lock.archived +0 -1054
- data/data/gemfile/v1.12.6/Gemfile +0 -3
- data/data/gemfile/v1.12.6/Gemfile.lock.archived +0 -1056
- data/data/gemfile/v1.12.8/Gemfile +0 -3
- data/data/gemfile/v1.12.8/Gemfile.lock.archived +0 -1063
- data/data/gemfile/v1.13.0/Gemfile +0 -3
- data/data/gemfile/v1.13.0/Gemfile.lock.archived +0 -1074
- data/data/gemfile/v1.13.2/Gemfile +0 -3
- data/data/gemfile/v1.13.2/Gemfile.lock.archived +0 -899
- data/data/gemfile/v1.13.3/Gemfile +0 -3
- data/data/gemfile/v1.13.3/Gemfile.lock.archived +0 -938
- data/data/gemfile/v1.13.4/Gemfile +0 -3
- data/data/gemfile/v1.13.4/Gemfile.lock.archived +0 -938
- data/data/gemfile/v1.13.5/Gemfile +0 -3
- data/data/gemfile/v1.13.5/Gemfile.lock.archived +0 -944
- data/data/gemfile/v1.13.7/Gemfile +0 -3
- data/data/gemfile/v1.13.7/Gemfile.lock.archived +0 -944
- data/data/gemfile/v1.13.8/Gemfile +0 -3
- data/data/gemfile/v1.13.8/Gemfile.lock.archived +0 -944
- data/data/gemfile/v1.13.9/Gemfile +0 -3
- data/data/gemfile/v1.13.9/Gemfile.lock.archived +0 -956
- data/data/gemfile/v1.14.3/Gemfile +0 -3
- data/data/gemfile/v1.14.3/Gemfile.lock.archived +0 -950
- data/data/gemfile/v1.2.12/Gemfile +0 -3
- data/data/gemfile/v1.2.12/Gemfile.lock.archived +0 -283
- data/data/gemfile/v1.2.2/Gemfile +0 -4
- data/data/gemfile/v1.2.2/Gemfile.lock.archived +0 -224
- data/data/gemfile/v1.2.3/Gemfile +0 -4
- data/data/gemfile/v1.2.3/Gemfile.lock.archived +0 -231
- data/data/gemfile/v1.2.6/Gemfile +0 -4
- data/data/gemfile/v1.2.6/Gemfile.lock.archived +0 -239
- data/data/gemfile/v1.2.8/Gemfile +0 -4
- data/data/gemfile/v1.2.8/Gemfile.lock.archived +0 -233
- data/data/gemfile/v1.2.9/Gemfile +0 -4
- data/data/gemfile/v1.2.9/Gemfile.lock.archived +0 -245
- data/data/gemfile/v1.3.1/Gemfile +0 -3
- data/data/gemfile/v1.3.1/Gemfile.lock.archived +0 -296
- data/data/gemfile/v1.3.2/Gemfile +0 -3
- data/data/gemfile/v1.3.2/Gemfile.lock.archived +0 -296
- data/data/gemfile/v1.3.4/Gemfile +0 -3
- data/data/gemfile/v1.3.4/Gemfile.lock.archived +0 -284
- data/data/gemfile/v1.3.5/Gemfile +0 -3
- data/data/gemfile/v1.3.5/Gemfile.lock.archived +0 -284
- data/data/gemfile/v1.3.6/Gemfile +0 -3
- data/data/gemfile/v1.3.6/Gemfile.lock.archived +0 -286
- data/data/gemfile/v1.3.9/Gemfile +0 -3
- data/data/gemfile/v1.3.9/Gemfile.lock.archived +0 -334
- data/data/gemfile/v1.4.0/Gemfile +0 -3
- data/data/gemfile/v1.4.0/Gemfile.lock.archived +0 -330
- data/data/gemfile/v1.4.10/Gemfile +0 -4
- data/data/gemfile/v1.4.10/Gemfile.lock.archived +0 -461
- data/data/gemfile/v1.4.11/Gemfile +0 -4
- data/data/gemfile/v1.4.11/Gemfile.lock.archived +0 -452
- data/data/gemfile/v1.4.12/Gemfile +0 -4
- data/data/gemfile/v1.4.12/Gemfile.lock.archived +0 -452
- data/data/gemfile/v1.4.13/Gemfile +0 -4
- data/data/gemfile/v1.4.13/Gemfile.lock.archived +0 -455
- data/data/gemfile/v1.4.14/Gemfile +0 -4
- data/data/gemfile/v1.4.14/Gemfile.lock.archived +0 -456
- data/data/gemfile/v1.4.18/Gemfile +0 -3
- data/data/gemfile/v1.4.18/Gemfile.lock.archived +0 -486
- data/data/gemfile/v1.4.3/Gemfile +0 -3
- data/data/gemfile/v1.4.3/Gemfile.lock.archived +0 -339
- data/data/gemfile/v1.4.4/Gemfile +0 -3
- data/data/gemfile/v1.4.4/Gemfile.lock.archived +0 -339
- data/data/gemfile/v1.4.5/Gemfile +0 -3
- data/data/gemfile/v1.4.5/Gemfile.lock.archived +0 -348
- data/data/gemfile/v1.4.6/Gemfile +0 -3
- data/data/gemfile/v1.4.6/Gemfile.lock.archived +0 -357
- data/data/gemfile/v1.4.7/Gemfile +0 -3
- data/data/gemfile/v1.4.7/Gemfile.lock.archived +0 -391
- data/data/gemfile/v1.4.8/Gemfile +0 -3
- data/data/gemfile/v1.4.8/Gemfile.lock.archived +0 -445
- data/data/gemfile/v1.4.9/Gemfile +0 -3
- data/data/gemfile/v1.4.9/Gemfile.lock.archived +0 -448
- data/data/gemfile/v1.5.0/Gemfile +0 -3
- data/data/gemfile/v1.5.0/Gemfile.lock.archived +0 -478
- data/data/gemfile/v1.5.10/Gemfile +0 -3
- data/data/gemfile/v1.5.10/Gemfile.lock.archived +0 -668
- data/data/gemfile/v1.5.11/Gemfile +0 -3
- data/data/gemfile/v1.5.11/Gemfile.lock.archived +0 -668
- data/data/gemfile/v1.5.15/Gemfile +0 -3
- data/data/gemfile/v1.5.15/Gemfile.lock.archived +0 -686
- data/data/gemfile/v1.5.16/Gemfile +0 -3
- data/data/gemfile/v1.5.16/Gemfile.lock.archived +0 -684
- data/data/gemfile/v1.5.17/Gemfile +0 -3
- data/data/gemfile/v1.5.17/Gemfile.lock.archived +0 -684
- data/data/gemfile/v1.5.18/Gemfile +0 -5
- data/data/gemfile/v1.5.18/Gemfile.lock.archived +0 -691
- data/data/gemfile/v1.5.19/Gemfile +0 -5
- data/data/gemfile/v1.5.19/Gemfile.lock.archived +0 -703
- data/data/gemfile/v1.5.20/Gemfile +0 -5
- data/data/gemfile/v1.5.20/Gemfile.lock.archived +0 -703
- data/data/gemfile/v1.5.21/Gemfile +0 -5
- data/data/gemfile/v1.5.21/Gemfile.lock.archived +0 -707
- data/data/gemfile/v1.5.22/Gemfile +0 -5
- data/data/gemfile/v1.5.22/Gemfile.lock.archived +0 -707
- data/data/gemfile/v1.5.23/Gemfile +0 -5
- data/data/gemfile/v1.5.23/Gemfile.lock.archived +0 -711
- data/data/gemfile/v1.5.24/Gemfile +0 -5
- data/data/gemfile/v1.5.24/Gemfile.lock.archived +0 -711
- data/data/gemfile/v1.5.3/Gemfile +0 -3
- data/data/gemfile/v1.5.3/Gemfile.lock.archived +0 -651
- data/data/gemfile/v1.5.4/Gemfile +0 -3
- data/data/gemfile/v1.5.4/Gemfile.lock.archived +0 -657
- data/data/gemfile/v1.5.5/Gemfile +0 -3
- data/data/gemfile/v1.5.5/Gemfile.lock.archived +0 -657
- data/data/gemfile/v1.5.6/Gemfile +0 -3
- data/data/gemfile/v1.5.6/Gemfile.lock.archived +0 -657
- data/data/gemfile/v1.5.7/Gemfile +0 -3
- data/data/gemfile/v1.5.7/Gemfile.lock.archived +0 -657
- data/data/gemfile/v1.5.8/Gemfile +0 -3
- data/data/gemfile/v1.5.8/Gemfile.lock.archived +0 -655
- data/data/gemfile/v1.5.9/Gemfile +0 -3
- data/data/gemfile/v1.5.9/Gemfile.lock.archived +0 -656
- data/data/gemfile/v1.6.1/Gemfile +0 -5
- data/data/gemfile/v1.6.1/Gemfile.lock.archived +0 -721
- data/data/gemfile/v1.6.10/Gemfile +0 -5
- data/data/gemfile/v1.6.10/Gemfile.lock.archived +0 -744
- data/data/gemfile/v1.6.11/Gemfile +0 -5
- data/data/gemfile/v1.6.11/Gemfile.lock.archived +0 -744
- data/data/gemfile/v1.6.12/Gemfile +0 -5
- data/data/gemfile/v1.6.12/Gemfile.lock.archived +0 -745
- data/data/gemfile/v1.6.13/Gemfile +0 -5
- data/data/gemfile/v1.6.13/Gemfile.lock.archived +0 -745
- data/data/gemfile/v1.6.14/Gemfile +0 -5
- data/data/gemfile/v1.6.14/Gemfile.lock.archived +0 -754
- data/data/gemfile/v1.6.15/Gemfile +0 -5
- data/data/gemfile/v1.6.15/Gemfile.lock.archived +0 -757
- data/data/gemfile/v1.6.2/Gemfile +0 -5
- data/data/gemfile/v1.6.2/Gemfile.lock.archived +0 -718
- data/data/gemfile/v1.6.3/Gemfile +0 -5
- data/data/gemfile/v1.6.3/Gemfile.lock.archived +0 -728
- data/data/gemfile/v1.6.4/Gemfile +0 -5
- data/data/gemfile/v1.6.4/Gemfile.lock.archived +0 -730
- data/data/gemfile/v1.6.5/Gemfile +0 -5
- data/data/gemfile/v1.6.5/Gemfile.lock.archived +0 -733
- data/data/gemfile/v1.6.6/Gemfile +0 -5
- data/data/gemfile/v1.6.6/Gemfile.lock.archived +0 -733
- data/data/gemfile/v1.6.7/Gemfile +0 -5
- data/data/gemfile/v1.6.7/Gemfile.lock.archived +0 -733
- data/data/gemfile/v1.6.9/Gemfile +0 -5
- data/data/gemfile/v1.6.9/Gemfile.lock.archived +0 -744
- data/data/gemfile/v1.7.0/Gemfile +0 -5
- data/data/gemfile/v1.7.0/Gemfile.lock.archived +0 -750
- data/data/gemfile/v1.7.1/Gemfile +0 -5
- data/data/gemfile/v1.7.1/Gemfile.lock.archived +0 -750
- data/data/gemfile/v1.7.2/Gemfile +0 -5
- data/data/gemfile/v1.7.2/Gemfile.lock.archived +0 -747
- data/data/gemfile/v1.7.3/Gemfile +0 -5
- data/data/gemfile/v1.7.3/Gemfile.lock.archived +0 -755
- data/data/gemfile/v1.7.4/Gemfile +0 -5
- data/data/gemfile/v1.7.4/Gemfile.lock.archived +0 -756
- data/data/gemfile/v1.7.5/Gemfile +0 -5
- data/data/gemfile/v1.7.5/Gemfile.lock.archived +0 -759
- data/data/gemfile/v1.7.6/Gemfile +0 -5
- data/data/gemfile/v1.7.6/Gemfile.lock.archived +0 -768
- data/data/gemfile/v1.8.10/Gemfile +0 -5
- data/data/gemfile/v1.8.10/Gemfile.lock.archived +0 -792
- data/data/gemfile/v1.8.11/Gemfile +0 -5
- data/data/gemfile/v1.8.11/Gemfile.lock.archived +0 -862
- data/data/gemfile/v1.8.3/Gemfile +0 -5
- data/data/gemfile/v1.8.3/Gemfile.lock.archived +0 -773
- data/data/gemfile/v1.8.4/Gemfile +0 -5
- data/data/gemfile/v1.8.4/Gemfile.lock.archived +0 -768
- data/data/gemfile/v1.8.5/Gemfile +0 -5
- data/data/gemfile/v1.8.5/Gemfile.lock.archived +0 -768
- data/data/gemfile/v1.8.6/Gemfile +0 -5
- data/data/gemfile/v1.8.6/Gemfile.lock.archived +0 -777
- data/data/gemfile/v1.8.7/Gemfile +0 -5
- data/data/gemfile/v1.8.7/Gemfile.lock.archived +0 -777
- data/data/gemfile/v1.8.8/Gemfile +0 -5
- data/data/gemfile/v1.8.8/Gemfile.lock.archived +0 -778
- data/data/gemfile/v1.8.9/Gemfile +0 -5
- data/data/gemfile/v1.8.9/Gemfile.lock.archived +0 -775
- data/data/gemfile/v1.9.0/Gemfile +0 -5
- data/data/gemfile/v1.9.0/Gemfile.lock.archived +0 -871
- data/data/gemfile/v1.9.1/Gemfile +0 -5
- data/data/gemfile/v1.9.1/Gemfile.lock.archived +0 -906
- data/data/gemfile/v1.9.2/Gemfile +0 -5
- data/data/gemfile/v1.9.2/Gemfile.lock.archived +0 -898
- data/data/gemfile/v1.9.3/Gemfile +0 -5
- data/data/gemfile/v1.9.3/Gemfile.lock.archived +0 -898
- data/data/gemfile/v1.9.4/Gemfile +0 -5
- data/data/gemfile/v1.9.4/Gemfile.lock.archived +0 -901
- data/data/gemfile/v1.9.5/Gemfile +0 -5
- data/data/gemfile/v1.9.5/Gemfile.lock.archived +0 -903
- data/data/gemfile/v1.9.6/Gemfile +0 -5
- data/data/gemfile/v1.9.6/Gemfile.lock.archived +0 -900
- data/data/gemfile/v1.9.7/Gemfile +0 -5
- data/data/gemfile/v1.9.7/Gemfile.lock.archived +0 -922
- data/data/gemfile/v1.9.8/Gemfile +0 -5
- data/data/gemfile/v1.9.8/Gemfile.lock.archived +0 -933
- data/data/gemfile/versions.yaml +0 -751
- data/data/homebrew/versions.yaml +0 -567
- data/data/snap/github_tags.json +0 -42
- data/data/snap/versions.yaml +0 -589
- data/snapcraft-list-copied-from-site.md +0 -101
data/lib/mnenv/cli.rb
CHANGED
|
@@ -2,18 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
require 'thor'
|
|
4
4
|
require 'json'
|
|
5
|
-
require_relative 'models'
|
|
6
|
-
require_relative 'commands'
|
|
7
|
-
require_relative 'json_formatter'
|
|
8
|
-
require_relative 'gemfile_repository'
|
|
9
|
-
require_relative 'snap_repository'
|
|
10
|
-
require_relative 'homebrew_repository'
|
|
11
|
-
require_relative 'chocolatey_repository'
|
|
12
5
|
|
|
13
6
|
module Mnenv
|
|
7
|
+
# Autoload constants for lazy loading
|
|
8
|
+
autoload :VERSION, 'mnenv/version'
|
|
9
|
+
autoload :GemfileRepository, 'mnenv/gemfile_repository'
|
|
10
|
+
autoload :SnapRepository, 'mnenv/snap_repository'
|
|
11
|
+
autoload :HomebrewRepository, 'mnenv/homebrew_repository'
|
|
12
|
+
autoload :ChocolateyRepository, 'mnenv/chocolatey_repository'
|
|
13
|
+
autoload :GemfileCommand, 'mnenv/commands/gemfile_command'
|
|
14
|
+
autoload :SnapCommand, 'mnenv/commands/snap_command'
|
|
15
|
+
autoload :HomebrewCommand, 'mnenv/commands/homebrew_command'
|
|
16
|
+
autoload :ChocolateyCommand, 'mnenv/commands/chocolatey_command'
|
|
17
|
+
autoload :InstallCommand, 'mnenv/commands/install_command'
|
|
18
|
+
autoload :VersionCommand, 'mnenv/commands/version_command'
|
|
19
|
+
autoload :UninstallCommand, 'mnenv/commands/uninstall_command'
|
|
20
|
+
autoload :JsonFormatter, 'mnenv/json_formatter'
|
|
21
|
+
autoload :ShimManager, 'mnenv/shim_manager'
|
|
22
|
+
autoload :BinaryRepository, 'mnenv/binary_repository'
|
|
23
|
+
|
|
14
24
|
class Cli < Thor
|
|
15
25
|
package_name 'mnenv'
|
|
16
26
|
|
|
27
|
+
# Global options
|
|
28
|
+
class_option :verbose, type: :boolean, default: false, desc: 'Enable verbose output'
|
|
29
|
+
class_option :'data-dir', type: :string, desc: 'Path to data directory (default: uses ~/.mnenv/versions/data)'
|
|
30
|
+
|
|
31
|
+
# Track verbose mode and data_dir for use in other classes
|
|
32
|
+
class << self
|
|
33
|
+
def verbose?
|
|
34
|
+
@verbose ||= false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
attr_accessor :data_dir
|
|
38
|
+
|
|
39
|
+
attr_writer :verbose
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def initialize(*args)
|
|
43
|
+
super
|
|
44
|
+
self.class.verbose = options[:verbose]
|
|
45
|
+
self.class.data_dir = options[:'data-dir']
|
|
46
|
+
end
|
|
47
|
+
|
|
17
48
|
# Platform subcommands
|
|
18
49
|
desc 'gemfile SUBCOMMAND', 'Manage Ruby (Gemfile) versions'
|
|
19
50
|
subcommand 'gemfile', GemfileCommand
|
|
@@ -27,12 +58,75 @@ module Mnenv
|
|
|
27
58
|
desc 'chocolatey SUBCOMMAND', 'Manage Chocolatey versions'
|
|
28
59
|
subcommand 'chocolatey', ChocolateyCommand
|
|
29
60
|
|
|
61
|
+
# Interactive installation commands
|
|
62
|
+
desc 'install [VERSION]', 'Install a Metanorma version'
|
|
63
|
+
method_option :source, type: :string, enum: %w[gemfile binary], default: 'gemfile',
|
|
64
|
+
desc: 'Installation source (gemfile or binary)'
|
|
65
|
+
method_option :interactive, type: :boolean, aliases: '-i', default: false,
|
|
66
|
+
desc: 'Interactive mode for version selection'
|
|
67
|
+
method_option :list, type: :boolean, aliases: '-l', default: false,
|
|
68
|
+
desc: 'List all available Metanorma versions'
|
|
69
|
+
def install(version = nil)
|
|
70
|
+
cmd = InstallCommand.new
|
|
71
|
+
cmd.options = Thor::CoreExt::HashWithIndifferentAccess.new(options.merge(version: version))
|
|
72
|
+
cmd.install(version)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
desc 'use [VERSION]', 'Set Metanorma version for current shell session'
|
|
76
|
+
method_option :source, type: :string, enum: %w[gemfile binary],
|
|
77
|
+
desc: 'Source type (gemfile or binary)'
|
|
78
|
+
method_option :interactive, type: :boolean, aliases: '-i', default: false,
|
|
79
|
+
desc: 'Interactive mode for version selection'
|
|
80
|
+
def use(version = nil)
|
|
81
|
+
cmd = VersionCommand.new
|
|
82
|
+
cmd.options = options
|
|
83
|
+
cmd.use(version)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
desc 'global [VERSION]', 'Set default Metanorma version globally'
|
|
87
|
+
method_option :source, type: :string, enum: %w[gemfile binary],
|
|
88
|
+
desc: 'Source type (gemfile or binary)'
|
|
89
|
+
method_option :interactive, type: :boolean, aliases: '-i', default: false,
|
|
90
|
+
desc: 'Interactive mode for version selection'
|
|
91
|
+
def global(version = nil)
|
|
92
|
+
cmd = VersionCommand.new
|
|
93
|
+
cmd.options = options
|
|
94
|
+
cmd.global(version)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
desc 'local [VERSION]', 'Set Metanorma version for current directory'
|
|
98
|
+
method_option :source, type: :string, enum: %w[gemfile binary],
|
|
99
|
+
desc: 'Source type (gemfile or binary)'
|
|
100
|
+
method_option :interactive, type: :boolean, aliases: '-i', default: false,
|
|
101
|
+
desc: 'Interactive mode for version selection'
|
|
102
|
+
def local(version = nil)
|
|
103
|
+
cmd = VersionCommand.new
|
|
104
|
+
cmd.options = options
|
|
105
|
+
cmd.local(version)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
desc 'versions', 'List all installed Metanorma versions'
|
|
109
|
+
def versions
|
|
110
|
+
cmd = VersionCommand.new
|
|
111
|
+
cmd.versions
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
desc 'uninstall VERSION', 'Uninstall a Metanorma version'
|
|
115
|
+
method_option :force, type: :boolean, aliases: '-f', default: false,
|
|
116
|
+
desc: 'Force uninstallation without confirmation'
|
|
117
|
+
def uninstall(version)
|
|
118
|
+
cmd = UninstallCommand.new
|
|
119
|
+
cmd.options = options
|
|
120
|
+
cmd.uninstall(version)
|
|
121
|
+
end
|
|
122
|
+
|
|
30
123
|
# General commands
|
|
31
124
|
PLATFORM_REPOSITORIES = {
|
|
32
125
|
'gemfile' => GemfileRepository,
|
|
33
126
|
'snap' => SnapRepository,
|
|
34
127
|
'homebrew' => HomebrewRepository,
|
|
35
|
-
'chocolatey' => ChocolateyRepository
|
|
128
|
+
'chocolatey' => ChocolateyRepository,
|
|
129
|
+
'binary' => BinaryRepository
|
|
36
130
|
}.freeze
|
|
37
131
|
|
|
38
132
|
desc 'info PLATFORM VERSION', 'Get details for a specific version'
|
|
@@ -54,8 +148,6 @@ module Mnenv
|
|
|
54
148
|
|
|
55
149
|
case options[:format]
|
|
56
150
|
when 'json'
|
|
57
|
-
require_relative 'json_formatter'
|
|
58
|
-
require 'json'
|
|
59
151
|
output = JsonFormatter.format_version(version_obj)
|
|
60
152
|
output['platform'] = platform
|
|
61
153
|
puts JSON.pretty_generate(output)
|
|
@@ -66,6 +158,7 @@ module Mnenv
|
|
|
66
158
|
puts " Parsed: #{version_obj.parsed_at || 'N/A'}"
|
|
67
159
|
version_obj.to_h.each do |k, v|
|
|
68
160
|
next if %w[version published_at parsed_at].include?(k)
|
|
161
|
+
|
|
69
162
|
puts " #{k}: #{v}"
|
|
70
163
|
end
|
|
71
164
|
end
|
|
@@ -120,5 +213,12 @@ module Mnenv
|
|
|
120
213
|
def version
|
|
121
214
|
puts "mnenv #{Mnenv::VERSION}"
|
|
122
215
|
end
|
|
216
|
+
|
|
217
|
+
desc 'update', 'Update version data from metanorma/versions repository'
|
|
218
|
+
def update
|
|
219
|
+
puts 'Updating version data...'
|
|
220
|
+
Repository.update_versions
|
|
221
|
+
puts 'Version data updated successfully.'
|
|
222
|
+
end
|
|
123
223
|
end
|
|
124
224
|
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require_relative '../version'
|
|
5
|
+
require_relative '../binary_repository'
|
|
6
|
+
|
|
7
|
+
module Mnenv
|
|
8
|
+
class AvailableCommand < Thor
|
|
9
|
+
namespace :available
|
|
10
|
+
|
|
11
|
+
class_option :source, type: :string, enum: %w[gemfile binary all], default: 'all',
|
|
12
|
+
desc: 'Source type to show (gemfile, binary, or all)'
|
|
13
|
+
class_option :format, type: :string, aliases: '-f', default: 'text',
|
|
14
|
+
desc: 'Output format (text or json)'
|
|
15
|
+
|
|
16
|
+
desc 'gemfile', 'List available Metanorma versions from RubyGems (gemfile method)'
|
|
17
|
+
method_option :format, type: :string, aliases: '-f', default: 'text'
|
|
18
|
+
def gemfile
|
|
19
|
+
repo = GemfileRepository.new
|
|
20
|
+
versions = repo.all.sort.reverse
|
|
21
|
+
|
|
22
|
+
show_available_versions('gemfile', versions)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc 'binary', 'List available Metanorma versions from GitHub releases (binary method)'
|
|
26
|
+
method_option :format, type: :string, aliases: '-f', default: 'text'
|
|
27
|
+
def binary
|
|
28
|
+
repo = BinaryRepository.new
|
|
29
|
+
versions = repo.all
|
|
30
|
+
|
|
31
|
+
show_available_versions('binary', versions)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc 'all', 'List all available Metanorma versions from all sources'
|
|
35
|
+
method_option :format, type: :string, aliases: '-f', default: 'text'
|
|
36
|
+
def all
|
|
37
|
+
case options[:format]
|
|
38
|
+
when 'json'
|
|
39
|
+
output = {}
|
|
40
|
+
output['gemfile'] = format_versions_json(GemfileRepository.new.all.sort.reverse)
|
|
41
|
+
output['binary'] = format_versions_json(BinaryRepository.new.all)
|
|
42
|
+
puts JSON.pretty_generate(output)
|
|
43
|
+
else
|
|
44
|
+
puts "\n=== Gemfile (RubyGems) ==="
|
|
45
|
+
gemfile
|
|
46
|
+
|
|
47
|
+
puts "\n=== Binary (packed-mn releases) ==="
|
|
48
|
+
binary
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
default_task :all
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def show_available_versions(source, versions)
|
|
57
|
+
current_version, current_source = resolve_current
|
|
58
|
+
|
|
59
|
+
case options[:format]
|
|
60
|
+
when 'json'
|
|
61
|
+
output = {
|
|
62
|
+
'source' => source,
|
|
63
|
+
'versions' => format_versions_json(versions)
|
|
64
|
+
}
|
|
65
|
+
puts JSON.pretty_generate(output)
|
|
66
|
+
else
|
|
67
|
+
puts "Available Metanorma versions (source: #{source}):"
|
|
68
|
+
|
|
69
|
+
versions.each do |v|
|
|
70
|
+
# Check if installed
|
|
71
|
+
version_dir = File.expand_path("~/.mnenv/versions/#{v.version}")
|
|
72
|
+
installed = Dir.exist?(version_dir)
|
|
73
|
+
|
|
74
|
+
# Check installed source
|
|
75
|
+
installed_source = if installed
|
|
76
|
+
source_file = File.join(version_dir, 'source')
|
|
77
|
+
File.exist?(source_file) ? File.read(source_file).strip : 'unknown'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Check if currently active
|
|
81
|
+
is_current = installed && v.version == current_version && installed_source == current_source
|
|
82
|
+
|
|
83
|
+
# Build status indicator
|
|
84
|
+
status_parts = []
|
|
85
|
+
status_parts << 'current' if is_current
|
|
86
|
+
status_parts << 'installed' if installed && !is_current
|
|
87
|
+
status = status_parts.empty? ? '' : " [#{status_parts.join(', ')}]"
|
|
88
|
+
|
|
89
|
+
# Show installed source if different
|
|
90
|
+
source_info = if installed && installed_source && installed_source != source
|
|
91
|
+
" (as #{installed_source})"
|
|
92
|
+
elsif installed && installed_source == source
|
|
93
|
+
''
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Version display with padding
|
|
97
|
+
version_display = v.display_name
|
|
98
|
+
marker = is_current ? '*' : ' '
|
|
99
|
+
padding = ' ' * (15 - version_display.length - status.length)
|
|
100
|
+
|
|
101
|
+
puts " #{marker} #{version_display}#{padding}#{status}#{source_info}"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def format_versions_json(versions)
|
|
107
|
+
versions.map do |v|
|
|
108
|
+
version_dir = File.expand_path("~/.mnenv/versions/#{v.version}")
|
|
109
|
+
installed = Dir.exist?(version_dir)
|
|
110
|
+
installed_source = if installed
|
|
111
|
+
source_file = File.join(version_dir, 'source')
|
|
112
|
+
File.exist?(source_file) ? File.read(source_file).strip : nil
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
{
|
|
116
|
+
'version' => v.version,
|
|
117
|
+
'display_name' => v.display_name,
|
|
118
|
+
'published_at' => v.published_at&.iso8601,
|
|
119
|
+
'installed' => installed,
|
|
120
|
+
'installed_source' => installed_source
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def resolve_current
|
|
126
|
+
# Get current version
|
|
127
|
+
version = ENV['METANORMA_VERSION']
|
|
128
|
+
unless version
|
|
129
|
+
# Check .metanorma-version file
|
|
130
|
+
dir = Dir.pwd
|
|
131
|
+
while dir && dir != '/'
|
|
132
|
+
if File.exist?(File.join(dir, '.metanorma-version'))
|
|
133
|
+
version = File.read(File.join(dir, '.metanorma-version')).strip
|
|
134
|
+
break
|
|
135
|
+
end
|
|
136
|
+
dir = File.dirname(dir)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Check global version
|
|
140
|
+
version ||= begin
|
|
141
|
+
global_version_file = File.expand_path('~/.mnenv/version')
|
|
142
|
+
File.read(global_version_file).strip if File.exist?(global_version_file)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Get current source
|
|
147
|
+
source = ENV['METANORMA_SOURCE']
|
|
148
|
+
unless source
|
|
149
|
+
# Check .metanorma-source file
|
|
150
|
+
dir = Dir.pwd
|
|
151
|
+
while dir && dir != '/'
|
|
152
|
+
if File.exist?(File.join(dir, '.metanorma-source'))
|
|
153
|
+
source = File.read(File.join(dir, '.metanorma-source')).strip
|
|
154
|
+
break
|
|
155
|
+
end
|
|
156
|
+
dir = File.dirname(dir)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Check global source
|
|
160
|
+
source ||= begin
|
|
161
|
+
global_source_file = File.expand_path('~/.mnenv/source')
|
|
162
|
+
File.read(global_source_file).strip if File.exist?(global_source_file)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
[version, source]
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -4,12 +4,14 @@ require 'thor'
|
|
|
4
4
|
require 'json'
|
|
5
5
|
|
|
6
6
|
module Mnenv
|
|
7
|
+
autoload :ChocolateyRepository, 'mnenv/chocolatey_repository'
|
|
8
|
+
autoload :JsonFormatter, 'mnenv/json_formatter'
|
|
9
|
+
autoload :Chocolatey, 'mnenv/chocolatey'
|
|
10
|
+
|
|
7
11
|
class ChocolateyCommand < Thor
|
|
8
12
|
desc 'list', 'List all Chocolatey versions'
|
|
9
13
|
method_option :format, type: :string, aliases: '-f', default: 'text'
|
|
10
14
|
def list
|
|
11
|
-
require_relative '../chocolatey_repository'
|
|
12
|
-
require_relative '../json_formatter'
|
|
13
15
|
repo = ChocolateyRepository.new
|
|
14
16
|
versions = repo.all
|
|
15
17
|
|
|
@@ -25,7 +27,6 @@ module Mnenv
|
|
|
25
27
|
|
|
26
28
|
desc 'refresh', 'Fetch and add new Chocolatey versions'
|
|
27
29
|
def refresh
|
|
28
|
-
require_relative '../chocolatey/fetcher'
|
|
29
30
|
fetcher = Chocolatey::Fetcher.new
|
|
30
31
|
existing = fetcher.repository.all.map(&:version)
|
|
31
32
|
remote_versions = fetcher.fetch_all
|
|
@@ -41,7 +42,6 @@ module Mnenv
|
|
|
41
42
|
|
|
42
43
|
desc 'revamp', 'Re-fetch all Chocolatey versions'
|
|
43
44
|
def revamp
|
|
44
|
-
require_relative '../chocolatey/fetcher'
|
|
45
45
|
fetcher = Chocolatey::Fetcher.new
|
|
46
46
|
versions = fetcher.fetch_and_save
|
|
47
47
|
puts "Revamped #{versions.size} Chocolatey versions"
|
|
@@ -49,7 +49,6 @@ module Mnenv
|
|
|
49
49
|
|
|
50
50
|
desc 'update VERSION', 'Update a specific Chocolatey version'
|
|
51
51
|
def update(version)
|
|
52
|
-
require_relative '../chocolatey/fetcher'
|
|
53
52
|
fetcher = Chocolatey::Fetcher.new
|
|
54
53
|
versions = fetcher.fetch_all
|
|
55
54
|
target = versions.find { |v| v.version == version }
|
|
@@ -4,12 +4,14 @@ require 'thor'
|
|
|
4
4
|
require 'json'
|
|
5
5
|
|
|
6
6
|
module Mnenv
|
|
7
|
+
autoload :GemfileRepository, 'mnenv/gemfile_repository'
|
|
8
|
+
autoload :JsonFormatter, 'mnenv/json_formatter'
|
|
9
|
+
autoload :Gemfile, 'mnenv/gemfile'
|
|
10
|
+
|
|
7
11
|
class GemfileCommand < Thor
|
|
8
12
|
desc 'list', 'List all Gemfile (Ruby) versions'
|
|
9
13
|
method_option :format, type: :string, aliases: '-f', default: 'text'
|
|
10
14
|
def list
|
|
11
|
-
require_relative '../gemfile_repository'
|
|
12
|
-
require_relative '../json_formatter'
|
|
13
15
|
repo = GemfileRepository.new
|
|
14
16
|
versions = repo.all
|
|
15
17
|
|
|
@@ -25,21 +27,18 @@ module Mnenv
|
|
|
25
27
|
|
|
26
28
|
desc 'refresh', 'Extract new Gemfiles (incremental mode)'
|
|
27
29
|
def refresh
|
|
28
|
-
require_relative '../gemfile/extractor'
|
|
29
30
|
extractor = Gemfile::Extractor.new(mode: :incremental)
|
|
30
31
|
extractor.run
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
desc 'revamp', 'Re-extract all Gemfiles'
|
|
34
35
|
def revamp
|
|
35
|
-
require_relative '../gemfile/extractor'
|
|
36
36
|
extractor = Gemfile::Extractor.new(mode: :revamp)
|
|
37
37
|
extractor.run
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
desc 'update VERSION', 'Re-extract specific version'
|
|
41
41
|
def update(version)
|
|
42
|
-
require_relative '../gemfile/extractor'
|
|
43
42
|
extractor = Gemfile::Extractor.new(mode: :replace, target_version: version)
|
|
44
43
|
extractor.run
|
|
45
44
|
end
|
|
@@ -4,12 +4,14 @@ require 'thor'
|
|
|
4
4
|
require 'json'
|
|
5
5
|
|
|
6
6
|
module Mnenv
|
|
7
|
+
autoload :HomebrewRepository, 'mnenv/homebrew_repository'
|
|
8
|
+
autoload :JsonFormatter, 'mnenv/json_formatter'
|
|
9
|
+
autoload :Homebrew, 'mnenv/homebrew'
|
|
10
|
+
|
|
7
11
|
class HomebrewCommand < Thor
|
|
8
12
|
desc 'list', 'List all Homebrew versions'
|
|
9
13
|
method_option :format, type: :string, aliases: '-f', default: 'text'
|
|
10
14
|
def list
|
|
11
|
-
require_relative '../homebrew_repository'
|
|
12
|
-
require_relative '../json_formatter'
|
|
13
15
|
repo = HomebrewRepository.new
|
|
14
16
|
versions = repo.all
|
|
15
17
|
|
|
@@ -25,7 +27,6 @@ module Mnenv
|
|
|
25
27
|
|
|
26
28
|
desc 'refresh', 'Fetch and add new Homebrew versions'
|
|
27
29
|
def refresh
|
|
28
|
-
require_relative '../homebrew/fetcher'
|
|
29
30
|
fetcher = Homebrew::Fetcher.new
|
|
30
31
|
existing = fetcher.repository.all.map(&:version)
|
|
31
32
|
remote_versions = fetcher.fetch_all
|
|
@@ -41,7 +42,6 @@ module Mnenv
|
|
|
41
42
|
|
|
42
43
|
desc 'revamp', 'Re-fetch all Homebrew versions'
|
|
43
44
|
def revamp
|
|
44
|
-
require_relative '../homebrew/fetcher'
|
|
45
45
|
fetcher = Homebrew::Fetcher.new
|
|
46
46
|
versions = fetcher.fetch_and_save
|
|
47
47
|
puts "Revamped #{versions.size} Homebrew versions"
|
|
@@ -49,7 +49,6 @@ module Mnenv
|
|
|
49
49
|
|
|
50
50
|
desc 'update VERSION', 'Update a specific Homebrew version'
|
|
51
51
|
def update(version)
|
|
52
|
-
require_relative '../homebrew/fetcher'
|
|
53
52
|
fetcher = Homebrew::Fetcher.new
|
|
54
53
|
versions = fetcher.fetch_all
|
|
55
54
|
target = versions.find { |v| v.version == version }
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tty/prompt'
|
|
4
|
+
require_relative '../installer'
|
|
5
|
+
require_relative '../binary_repository'
|
|
6
|
+
|
|
7
|
+
module Mnenv
|
|
8
|
+
class InstallCommand < Thor
|
|
9
|
+
namespace :install
|
|
10
|
+
|
|
11
|
+
class_option :source, type: :string, enum: %w[gemfile binary], default: 'gemfile',
|
|
12
|
+
desc: 'Installation source (gemfile or binary)'
|
|
13
|
+
class_option :interactive, type: :boolean, aliases: '-i', default: false,
|
|
14
|
+
desc: 'Interactive mode for version selection'
|
|
15
|
+
|
|
16
|
+
desc 'VERSION', 'Install a specific Metanorma version'
|
|
17
|
+
method_option :source, type: :string, enum: %w[gemfile binary], default: 'gemfile',
|
|
18
|
+
desc: 'Installation source (gemfile or binary)'
|
|
19
|
+
method_option :interactive, type: :boolean, aliases: '-i', default: false,
|
|
20
|
+
desc: 'Interactive mode for version selection'
|
|
21
|
+
method_option :list, type: :boolean, aliases: '-l', default: false,
|
|
22
|
+
desc: 'List all available Metanorma versions'
|
|
23
|
+
def install(version = nil)
|
|
24
|
+
# If --list flag is provided, show available versions and exit
|
|
25
|
+
return list_available_versions if options[:list]
|
|
26
|
+
|
|
27
|
+
# If no version provided or interactive mode, prompt for selection
|
|
28
|
+
if options[:interactive] || version.nil?
|
|
29
|
+
version, source = select_installation_interactive
|
|
30
|
+
else
|
|
31
|
+
source = options[:source]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
installer = InstallerFactory.create(version, source: source)
|
|
35
|
+
|
|
36
|
+
if installer.installed?
|
|
37
|
+
prompt = TTY::Prompt.new
|
|
38
|
+
unless prompt.yes?("Version #{version} (source: #{source}) is already installed. Reinstall?")
|
|
39
|
+
puts 'Installation cancelled.'
|
|
40
|
+
return
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
puts "Installing Metanorma #{version} (source: #{source})..."
|
|
45
|
+
installer.install
|
|
46
|
+
puts "Successfully installed Metanorma #{version} (source: #{source})!"
|
|
47
|
+
rescue Installer::InstallationError => e
|
|
48
|
+
warn "Error: #{e.message}"
|
|
49
|
+
exit 1
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
default_task :install
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def list_available_versions
|
|
57
|
+
current_version, current_source = resolve_current
|
|
58
|
+
current_platform = detect_platform
|
|
59
|
+
|
|
60
|
+
puts "\nAvailable Metanorma versions:"
|
|
61
|
+
puts "(gemfile = source build, binary = prebuilt for specific platforms)\n"
|
|
62
|
+
|
|
63
|
+
# Get all unique versions from both sources
|
|
64
|
+
gemfile_repo = GemfileRepository.new
|
|
65
|
+
binary_repo = BinaryRepository.new
|
|
66
|
+
|
|
67
|
+
gemfile_versions = gemfile_repo.all.sort.reverse
|
|
68
|
+
binary_versions = binary_repo.all
|
|
69
|
+
|
|
70
|
+
# Combine all versions
|
|
71
|
+
all_versions = Hash.new { |h, k| h[k] = { gemfile: false, binary: false } }
|
|
72
|
+
|
|
73
|
+
gemfile_versions.each do |v|
|
|
74
|
+
all_versions[v.version][:gemfile] = true
|
|
75
|
+
all_versions[v.version][:gemfile_obj] = v
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
binary_versions.each do |v|
|
|
79
|
+
all_versions[v.version][:binary] = true
|
|
80
|
+
all_versions[v.version][:binary_obj] = v
|
|
81
|
+
all_versions[v.version][:binary_platforms] = extract_platforms(v.assets)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Check what's installed (from installed directory, not versions data)
|
|
85
|
+
if Dir.exist?(Paths::INSTALLED_DIR)
|
|
86
|
+
Dir.glob("#{Paths::INSTALLED_DIR}/*/").each do |dir|
|
|
87
|
+
version = File.basename(dir)
|
|
88
|
+
source_file = File.join(dir, 'source')
|
|
89
|
+
source = File.exist?(source_file) ? File.read(source_file).strip : nil
|
|
90
|
+
all_versions[version][:"installed_#{source}"] = true if source && all_versions[version]
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Display sorted versions (newest first)
|
|
95
|
+
all_versions.sort.reverse.each do |version, info|
|
|
96
|
+
# Build sources string with platform info for binary
|
|
97
|
+
sources = []
|
|
98
|
+
sources << 'gemfile' if info[:gemfile]
|
|
99
|
+
if info[:binary]
|
|
100
|
+
platforms = info[:binary_platforms] || []
|
|
101
|
+
if platforms.any?
|
|
102
|
+
# Highlight current platform
|
|
103
|
+
platform_display = platforms.map do |p|
|
|
104
|
+
p == current_platform ? "#{p}*" : p
|
|
105
|
+
end.join(', ')
|
|
106
|
+
sources << "binary [#{platform_display}]"
|
|
107
|
+
else
|
|
108
|
+
sources << 'binary'
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Check if current
|
|
113
|
+
is_current = version == current_version && sources.any? { |s| s.include?(current_source.to_s) }
|
|
114
|
+
marker = is_current ? '* ' : ' '
|
|
115
|
+
|
|
116
|
+
# Version display
|
|
117
|
+
version_display = version.ljust(15)
|
|
118
|
+
|
|
119
|
+
# Sources display
|
|
120
|
+
sources_display = sources.join(', ')
|
|
121
|
+
|
|
122
|
+
# Installed status
|
|
123
|
+
installed = []
|
|
124
|
+
installed << 'gemfile' if info[:installed_gemfile]
|
|
125
|
+
installed << 'binary' if info[:installed_binary]
|
|
126
|
+
installed_display = installed.empty? ? '' : " [installed: #{installed.join(', ')}]"
|
|
127
|
+
|
|
128
|
+
puts " #{marker}#{version_display}(#{sources_display})#{installed_display}"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Legend
|
|
132
|
+
puts "\nLegend:"
|
|
133
|
+
puts ' * Current version / platform'
|
|
134
|
+
puts ' [installed: ...] = Already installed locally'
|
|
135
|
+
puts " Detected platform: #{current_platform}"
|
|
136
|
+
puts "\nInstall with: mnenv install VERSION --source SOURCE"
|
|
137
|
+
puts 'Examples:'
|
|
138
|
+
puts ' mnenv install 1.14.4 --source gemfile'
|
|
139
|
+
puts ' mnenv install 1.14.4 --source binary'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def extract_platforms(assets)
|
|
143
|
+
return [] unless assets
|
|
144
|
+
|
|
145
|
+
assets.filter_map do |asset|
|
|
146
|
+
# Match patterns like metanorma-darwin-arm64.tgz or metanorma-linux-x86_64.tgz
|
|
147
|
+
case asset
|
|
148
|
+
when /darwin/ then 'macos'
|
|
149
|
+
when /linux/ then 'linux'
|
|
150
|
+
when /windows/ then 'windows'
|
|
151
|
+
end
|
|
152
|
+
end.uniq.sort
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def detect_platform
|
|
156
|
+
case RbConfig::CONFIG['host_os']
|
|
157
|
+
when /linux/ then 'linux'
|
|
158
|
+
when /darwin/ then 'macos'
|
|
159
|
+
when /mswin|mingw|cygwin/ then 'windows'
|
|
160
|
+
else 'unknown'
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def resolve_current
|
|
165
|
+
# Get current version
|
|
166
|
+
version = ENV['METANORMA_VERSION']
|
|
167
|
+
unless version
|
|
168
|
+
# Check .metanorma-version file
|
|
169
|
+
dir = Dir.pwd
|
|
170
|
+
while dir && dir != '/'
|
|
171
|
+
if File.exist?(File.join(dir, '.metanorma-version'))
|
|
172
|
+
version = File.read(File.join(dir, '.metanorma-version')).strip
|
|
173
|
+
break
|
|
174
|
+
end
|
|
175
|
+
dir = File.dirname(dir)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Check global version
|
|
179
|
+
version ||= (File.read(Paths::VERSION_FILE).strip if File.exist?(Paths::VERSION_FILE))
|
|
180
|
+
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Get current source
|
|
184
|
+
source = ENV['METANORMA_SOURCE']
|
|
185
|
+
unless source
|
|
186
|
+
# Check .metanorma-source file
|
|
187
|
+
dir = Dir.pwd
|
|
188
|
+
while dir && dir != '/'
|
|
189
|
+
if File.exist?(File.join(dir, '.metanorma-source'))
|
|
190
|
+
source = File.read(File.join(dir, '.metanorma-source')).strip
|
|
191
|
+
break
|
|
192
|
+
end
|
|
193
|
+
dir = File.dirname(dir)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Check global source
|
|
197
|
+
source ||= (File.read(Paths::SOURCE_FILE).strip if File.exist?(Paths::SOURCE_FILE))
|
|
198
|
+
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
[version, source]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def select_installation_interactive
|
|
205
|
+
repo = GemfileRepository.new
|
|
206
|
+
prompt = TTY::Prompt.new
|
|
207
|
+
|
|
208
|
+
# First, select source
|
|
209
|
+
source = prompt.select('Select installation source:', [
|
|
210
|
+
{ name: 'Gemfile (faster, on-demand loading, requires dev tools, upgradable)',
|
|
211
|
+
value: 'gemfile' },
|
|
212
|
+
{ name: 'Binary (slower, full-stack memory load, no dev tools, fixed)',
|
|
213
|
+
value: 'binary' }
|
|
214
|
+
])
|
|
215
|
+
|
|
216
|
+
# Then, select version
|
|
217
|
+
choices = repo.all.sort.map do |v|
|
|
218
|
+
version_dir = Paths.version_install_dir(v.version)
|
|
219
|
+
installed = Dir.exist?(version_dir) && File.exist?(File.join(version_dir, 'source'))
|
|
220
|
+
installed_source = if installed
|
|
221
|
+
src = File.read(File.join(version_dir, 'source')).strip
|
|
222
|
+
src.empty? ? '' : "(#{src})"
|
|
223
|
+
else
|
|
224
|
+
''
|
|
225
|
+
end
|
|
226
|
+
{ name: "#{v.display_name} #{installed ? "[installed: #{installed_source}]" : ''}", value: v.version }
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
version = prompt.select('Select a version to install:', choices)
|
|
230
|
+
|
|
231
|
+
[version, source]
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|