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
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mnenv
|
|
4
|
+
# Centralized platform detection for consistent OS/architecture/variant detection
|
|
5
|
+
# across the codebase. Used by binary installer, repository, and CLI.
|
|
6
|
+
class PlatformDetector
|
|
7
|
+
class UnsupportedPlatform < StandardError; end
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# Detect the current operating system
|
|
11
|
+
# @return [String] 'linux', 'darwin', or 'windows'
|
|
12
|
+
# @raise [UnsupportedPlatform] if platform is not supported
|
|
13
|
+
def os
|
|
14
|
+
case RbConfig::CONFIG['host_os']
|
|
15
|
+
when /linux/
|
|
16
|
+
'linux'
|
|
17
|
+
when /darwin/
|
|
18
|
+
'darwin'
|
|
19
|
+
when /mswin|mingw|cygwin/
|
|
20
|
+
'windows'
|
|
21
|
+
else
|
|
22
|
+
raise UnsupportedPlatform, "Unsupported platform: #{RbConfig::CONFIG['host_os']}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Detect the current CPU architecture
|
|
27
|
+
# @return [String] 'arm64' or 'x86_64'
|
|
28
|
+
def arch
|
|
29
|
+
case RbConfig::CONFIG['host_cpu']
|
|
30
|
+
when /arm64|aarch64/
|
|
31
|
+
'arm64'
|
|
32
|
+
when /x86_64|x64/
|
|
33
|
+
'x86_64'
|
|
34
|
+
else
|
|
35
|
+
'x86_64' # Default fallback
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Detect libc variant (for Linux)
|
|
40
|
+
# @return [String, nil] 'musl' for Alpine/musl systems, nil for glibc
|
|
41
|
+
def variant
|
|
42
|
+
return nil unless os == 'linux'
|
|
43
|
+
|
|
44
|
+
'musl' if musl?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Check if running on a musl-based system (Alpine Linux)
|
|
48
|
+
# @return [Boolean]
|
|
49
|
+
def musl?
|
|
50
|
+
File.exist?('/etc/alpine-release') ||
|
|
51
|
+
File.symlink?('/lib/libc.musl-x86_64.so.1')
|
|
52
|
+
rescue StandardError
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Check if running on Windows
|
|
57
|
+
# @return [Boolean]
|
|
58
|
+
def windows?
|
|
59
|
+
os == 'windows'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Check if running on macOS
|
|
63
|
+
# @return [Boolean]
|
|
64
|
+
def macos?
|
|
65
|
+
os == 'darwin'
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Check if running on Linux
|
|
69
|
+
# @return [Boolean]
|
|
70
|
+
def linux?
|
|
71
|
+
os == 'linux'
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Get platform info as a hash
|
|
75
|
+
# @return [Hash] With keys :os, :arch, :variant
|
|
76
|
+
def to_h
|
|
77
|
+
{
|
|
78
|
+
os: os,
|
|
79
|
+
arch: arch,
|
|
80
|
+
variant: variant
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Get a human-readable platform string
|
|
85
|
+
# @return [String] e.g., "linux-x86_64", "darwin-arm64", "linux-musl-x86_64"
|
|
86
|
+
def platform_string
|
|
87
|
+
parts = [os]
|
|
88
|
+
parts << variant if variant
|
|
89
|
+
parts << arch
|
|
90
|
+
parts.join('-')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Get all possible platform strings for binary matching
|
|
94
|
+
# (includes variant-specific and generic versions)
|
|
95
|
+
# @return [Array<String>] List of platform strings in order of preference
|
|
96
|
+
def platform_candidates
|
|
97
|
+
candidates = []
|
|
98
|
+
|
|
99
|
+
# With variant (if applicable)
|
|
100
|
+
candidates << "#{os}-#{variant}-#{arch}" if variant
|
|
101
|
+
|
|
102
|
+
# Without variant
|
|
103
|
+
candidates << "#{os}-#{arch}"
|
|
104
|
+
|
|
105
|
+
candidates
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/mnenv/repository.rb
CHANGED
|
@@ -2,16 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
require 'yaml'
|
|
4
4
|
require 'fileutils'
|
|
5
|
+
require_relative 'versions_manager'
|
|
5
6
|
|
|
6
7
|
module Mnenv
|
|
7
8
|
class Repository
|
|
9
|
+
# Default versions manager (shared across all repositories)
|
|
10
|
+
class << self
|
|
11
|
+
def versions_manager
|
|
12
|
+
@versions_manager ||= VersionsManager.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_writer :versions_manager
|
|
16
|
+
|
|
17
|
+
# Force update the versions data
|
|
18
|
+
def update_versions
|
|
19
|
+
versions_manager.update
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
8
23
|
attr_reader :data_dir, :versions_file_path
|
|
9
24
|
|
|
10
|
-
def initialize(data_dir: nil)
|
|
11
|
-
@data_dir = data_dir || default_data_dir
|
|
25
|
+
def initialize(data_dir: nil, update: false)
|
|
26
|
+
@data_dir = data_dir || cli_data_dir || default_data_dir
|
|
12
27
|
@versions_file_path = File.join(@data_dir, 'versions.yaml')
|
|
13
28
|
@versions_cache = {}
|
|
14
|
-
|
|
29
|
+
@update = update
|
|
30
|
+
load
|
|
15
31
|
end
|
|
16
32
|
|
|
17
33
|
def find(version_number) = @versions_cache[version_number]
|
|
@@ -37,22 +53,29 @@ module Mnenv
|
|
|
37
53
|
protected
|
|
38
54
|
|
|
39
55
|
def load
|
|
40
|
-
data =
|
|
56
|
+
data = fetch_versions_data
|
|
41
57
|
return if data.nil? || data['versions'].nil?
|
|
42
58
|
|
|
43
59
|
data['versions'].each do |version_hash|
|
|
44
60
|
version = version_class.new(version_hash)
|
|
45
|
-
|
|
61
|
+
cache_version(version)
|
|
46
62
|
end
|
|
47
63
|
end
|
|
48
64
|
|
|
65
|
+
# Override in subclasses for custom caching (e.g., SnapRepository uses composite keys)
|
|
66
|
+
def cache_version(version)
|
|
67
|
+
@versions_cache[version.version] = version
|
|
68
|
+
end
|
|
69
|
+
|
|
49
70
|
def persist
|
|
50
|
-
|
|
71
|
+
return unless @data_dir
|
|
72
|
+
|
|
73
|
+
FileUtils.mkdir_p(@data_dir)
|
|
51
74
|
output = {
|
|
52
75
|
'metadata' => metadata,
|
|
53
|
-
'versions' => @versions_cache.values.sort.map
|
|
76
|
+
'versions' => @versions_cache.values.sort.map(&:to_hash)
|
|
54
77
|
}
|
|
55
|
-
File.write(versions_file_path, output.to_yaml)
|
|
78
|
+
File.write(@versions_file_path, output.to_yaml)
|
|
56
79
|
end
|
|
57
80
|
|
|
58
81
|
def metadata
|
|
@@ -68,38 +91,30 @@ module Mnenv
|
|
|
68
91
|
|
|
69
92
|
def source_name = raise NotImplementedError
|
|
70
93
|
|
|
71
|
-
def default_data_dir = File.join(__dir__, '..', '..', 'data', source_name.to_s)
|
|
72
|
-
|
|
73
94
|
private
|
|
74
95
|
|
|
75
|
-
def
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
'published_at' => format_timestamp(version.published_at),
|
|
79
|
-
'parsed_at' => format_timestamp(version.parsed_at)
|
|
80
|
-
}
|
|
96
|
+
def cli_data_dir
|
|
97
|
+
# Check if a data directory was specified via CLI option
|
|
98
|
+
return nil unless defined?(Mnenv::Cli) && Mnenv::Cli.data_dir
|
|
81
99
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
hash['gemfile_path'] = version.gemfile_path
|
|
87
|
-
hash['gemfile_lock_path'] = version.gemfile_lock_path
|
|
88
|
-
when SnapVersion
|
|
89
|
-
hash['revision'] = version.revision
|
|
90
|
-
hash['arch'] = version.arch
|
|
91
|
-
hash['channel'] = version.channel
|
|
92
|
-
when HomebrewVersion
|
|
93
|
-
hash['tag_name'] = version.tag_name
|
|
94
|
-
hash['commit_sha'] = version.commit_sha
|
|
95
|
-
when ChocolateyVersion
|
|
96
|
-
hash['package_name'] = version.package_name
|
|
97
|
-
hash['is_pre_release'] = version.is_pre_release
|
|
98
|
-
end
|
|
100
|
+
source_dir = Mnenv::Cli.data_dir
|
|
101
|
+
# If the CLI data-dir is specified, use it directly with the source name
|
|
102
|
+
File.join(source_dir, source_name.to_s)
|
|
103
|
+
end
|
|
99
104
|
|
|
100
|
-
|
|
105
|
+
def default_data_dir
|
|
106
|
+
# Use the versions manager to ensure data is available
|
|
107
|
+
data_path = self.class.versions_manager.ensure_versions_data(update: @update)
|
|
108
|
+
File.join(data_path, source_name.to_s)
|
|
101
109
|
end
|
|
102
110
|
|
|
103
|
-
def
|
|
111
|
+
def fetch_versions_data
|
|
112
|
+
return unless File.file?(@versions_file_path)
|
|
113
|
+
|
|
114
|
+
YAML.safe_load(File.read(@versions_file_path), permitted_classes: [Time, Symbol, Date])
|
|
115
|
+
rescue StandardError => e
|
|
116
|
+
warn "Warning: Failed to load versions from #{@versions_file_path}: #{e.message}"
|
|
117
|
+
nil
|
|
118
|
+
end
|
|
104
119
|
end
|
|
105
120
|
end
|
data/lib/mnenv/resolver
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Version and source resolver for mnenv shims
|
|
3
|
+
# Usage: ./resolver "version" | ./resolver "source"
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
export MNENV_ROOT="${MNENV_ROOT:-$HOME/.mnenv}"
|
|
8
|
+
|
|
9
|
+
resolve_version() {
|
|
10
|
+
# 1. Check METANORMA_VERSION environment variable
|
|
11
|
+
if [ -n "$METANORMA_VERSION" ]; then
|
|
12
|
+
echo "$METANORMA_VERSION"
|
|
13
|
+
return 0
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# 2. Check .metanorma-version file (walk up directory tree)
|
|
17
|
+
local dir="$PWD"
|
|
18
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
19
|
+
if [ -f "$dir/.metanorma-version" ]; then
|
|
20
|
+
cat "$dir/.metanorma-version"
|
|
21
|
+
return 0
|
|
22
|
+
fi
|
|
23
|
+
dir="${dir%/*}"
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
# 3. Check ~/.mnenv/version (global default)
|
|
27
|
+
if [ -f "$MNENV_ROOT/version" ]; then
|
|
28
|
+
cat "$MNENV_ROOT/version"
|
|
29
|
+
return 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# 4. No version found
|
|
33
|
+
return 1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
resolve_source() {
|
|
37
|
+
# 1. Check METANORMA_SOURCE environment variable
|
|
38
|
+
if [ -n "$METANORMA_SOURCE" ]; then
|
|
39
|
+
echo "$METANORMA_SOURCE"
|
|
40
|
+
return 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# 2. Check .metanorma-source file (walk up directory tree)
|
|
44
|
+
local dir="$PWD"
|
|
45
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
46
|
+
if [ -f "$dir/.metanorma-source" ]; then
|
|
47
|
+
cat "$dir/.metanorma-source"
|
|
48
|
+
return 0
|
|
49
|
+
fi
|
|
50
|
+
dir="${dir%/*}"
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
# 3. Check ~/.mnenv/source (global default)
|
|
54
|
+
if [ -f "$MNENV_ROOT/source" ]; then
|
|
55
|
+
cat "$MNENV_ROOT/source"
|
|
56
|
+
return 0
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# 4. Default to gemfile (faster for devs)
|
|
60
|
+
echo "gemfile"
|
|
61
|
+
return 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Main dispatch
|
|
65
|
+
case "$1" in
|
|
66
|
+
version) resolve_version ;;
|
|
67
|
+
source) resolve_source ;;
|
|
68
|
+
*)
|
|
69
|
+
echo "Usage: $0 {version|source}" >&2
|
|
70
|
+
exit 1
|
|
71
|
+
;;
|
|
72
|
+
esac
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mnenv
|
|
4
|
+
module Shells
|
|
5
|
+
# Base class for shell-specific behavior
|
|
6
|
+
class BaseShell
|
|
7
|
+
def name
|
|
8
|
+
raise NotImplementedError
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def shim_extension
|
|
12
|
+
raise NotImplementedError
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def shim_content(executable_name)
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def use_output(version, source)
|
|
20
|
+
raise NotImplementedError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def config_file
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def windows?
|
|
28
|
+
false
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module Mnenv
|
|
6
|
+
module Shells
|
|
7
|
+
# Bash shell implementation (also works for sh, dash, zsh)
|
|
8
|
+
class BashShell < BaseShell
|
|
9
|
+
def name
|
|
10
|
+
'bash'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def shim_extension
|
|
14
|
+
'' # No extension for bash scripts
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def shim_content(executable_name)
|
|
18
|
+
<<~SHIM
|
|
19
|
+
#!/bin/bash
|
|
20
|
+
set -e
|
|
21
|
+
|
|
22
|
+
export MNENV_ROOT="${MNENV_ROOT:-$HOME/.mnenv}"
|
|
23
|
+
|
|
24
|
+
# Resolve version and source using mnenv resolver
|
|
25
|
+
VERSION="$("$MNENV_ROOT/lib/mnenv/resolver" "version")"
|
|
26
|
+
SOURCE="$("$MNENV_ROOT/lib/mnenv/resolver" "source")"
|
|
27
|
+
|
|
28
|
+
if [ -z "$VERSION" ]; then
|
|
29
|
+
echo "mnenv: version not set or invalid" >&2
|
|
30
|
+
echo "Set a version with: mnenv global <version> or mnenv local <version>" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if [ -z "$SOURCE" ]; then
|
|
35
|
+
echo "mnenv: source not set or invalid" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Determine executable path based on source
|
|
40
|
+
# Installed versions are in $MNENV_ROOT/installed/<version>-<source>/
|
|
41
|
+
if [ "$SOURCE" = "binary" ]; then
|
|
42
|
+
# Binary: single self-contained binary
|
|
43
|
+
EXECUTABLE="$MNENV_ROOT/installed/$VERSION-$SOURCE/metanorma"
|
|
44
|
+
else
|
|
45
|
+
# Gemfile: binstub from bundle install
|
|
46
|
+
EXECUTABLE="$MNENV_ROOT/installed/$VERSION-$SOURCE/bin/#{executable_name}"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [ ! -f "$EXECUTABLE" ]; then
|
|
50
|
+
echo "mnenv: #{executable_name} not installed for version $VERSION (source: $SOURCE)" >&2
|
|
51
|
+
echo "Install it with: mnenv install $VERSION --source $SOURCE" >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
exec "$EXECUTABLE" "$@"
|
|
56
|
+
SHIM
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def use_output(version, source)
|
|
60
|
+
lines = []
|
|
61
|
+
lines << "export METANORMA_VERSION=#{version}"
|
|
62
|
+
lines << "export METANORMA_SOURCE=#{source}" if source
|
|
63
|
+
lines << "# Run this in your shell, or use: eval \"$(mnenv use #{version}#{" --source #{source}" if source})\""
|
|
64
|
+
lines.join("\n")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def config_file
|
|
68
|
+
File.expand_path('~/.bashrc')
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module Mnenv
|
|
6
|
+
module Shells
|
|
7
|
+
# CMD/Batch shell implementation (Windows)
|
|
8
|
+
class CmdShell < BaseShell
|
|
9
|
+
def name
|
|
10
|
+
'cmd'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def shim_extension
|
|
14
|
+
'.bat'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def shim_content(executable_name)
|
|
18
|
+
<<~SHIM
|
|
19
|
+
@echo off
|
|
20
|
+
rem mnenv shim for CMD
|
|
21
|
+
|
|
22
|
+
if defined MNENV_ROOT (
|
|
23
|
+
set "MNENV_ROOT=%MNENV_ROOT%"
|
|
24
|
+
) else (
|
|
25
|
+
set "MNENV_ROOT=%USERPROFILE%\\.mnenv"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
rem Resolve version and source
|
|
29
|
+
set "VERSION="
|
|
30
|
+
set "SOURCE="
|
|
31
|
+
|
|
32
|
+
rem Check environment variables first
|
|
33
|
+
if defined METANORMA_VERSION set "VERSION=%METANORMA_VERSION%"
|
|
34
|
+
if defined METANORMA_SOURCE set "SOURCE=%METANORMA_SOURCE%"
|
|
35
|
+
|
|
36
|
+
rem Check local .metanorma-version file
|
|
37
|
+
if not defined VERSION (
|
|
38
|
+
set "DIR=%CD%"
|
|
39
|
+
:loop
|
|
40
|
+
if exist "%DIR%\\.metanorma-version" (
|
|
41
|
+
set /p VERSION=<"%DIR%\\.metanorma-version"
|
|
42
|
+
goto :found_version
|
|
43
|
+
)
|
|
44
|
+
for %%I in ("%DIR%\\..") do set "PARENT=%%~fI"
|
|
45
|
+
if "%PARENT%"=="%DIR%" goto :check_global
|
|
46
|
+
set "DIR=%PARENT%"
|
|
47
|
+
goto :loop
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
:check_global
|
|
51
|
+
if not defined VERSION (
|
|
52
|
+
if exist "%MNENV_ROOT%\\version" (
|
|
53
|
+
set /p VERSION=<"%MNENV_ROOT%\\version"
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
:found_version
|
|
58
|
+
if not defined SOURCE (
|
|
59
|
+
if exist "%MNENV_ROOT%\\source" (
|
|
60
|
+
set /p SOURCE=<"%MNENV_ROOT%\\source"
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
rem Default source
|
|
65
|
+
if not defined SOURCE set "SOURCE=gemfile"
|
|
66
|
+
|
|
67
|
+
if not defined VERSION (
|
|
68
|
+
echo mnenv: version not set or invalid 1>&2
|
|
69
|
+
echo Set a version with: mnenv global ^<version^> or mnenv local ^<version^> 1>&2
|
|
70
|
+
exit /b 1
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
rem Determine executable path based on source
|
|
74
|
+
rem Installed versions are in %MNENV_ROOT%\\installed\\<version>-<source>\\
|
|
75
|
+
if "%SOURCE%"=="binary" (
|
|
76
|
+
set "EXECUTABLE=%MNENV_ROOT%\\installed\\%VERSION%-%SOURCE%\\metanorma.exe"
|
|
77
|
+
) else (
|
|
78
|
+
set "EXECUTABLE=%MNENV_ROOT%\\installed\\%VERSION%-%SOURCE%\\bin\\#{executable_name}.cmd"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if not exist "%EXECUTABLE%" (
|
|
82
|
+
echo mnenv: #{executable_name} not installed for version %VERSION% ^(source: %SOURCE%^) 1>&2
|
|
83
|
+
echo Install it with: mnenv install %VERSION% --source %SOURCE% 1>&2
|
|
84
|
+
exit /b 1
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
call "%EXECUTABLE%" %*
|
|
88
|
+
SHIM
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def use_output(version, source)
|
|
92
|
+
lines = []
|
|
93
|
+
lines << "set METANORMA_VERSION=#{version}"
|
|
94
|
+
lines << "set METANORMA_SOURCE=#{source}" if source
|
|
95
|
+
lines << 'rem Run this in your CMD session'
|
|
96
|
+
lines.join("\n")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def config_file
|
|
100
|
+
nil # CMD doesn't have a standard config file
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def windows?
|
|
104
|
+
true
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative 'bash'
|
|
5
|
+
require_relative 'power_shell'
|
|
6
|
+
require_relative 'cmd'
|
|
7
|
+
|
|
8
|
+
module Mnenv
|
|
9
|
+
module Shells
|
|
10
|
+
# Factory for detecting and creating shell instances
|
|
11
|
+
class ShellFactory
|
|
12
|
+
SHELLS = {
|
|
13
|
+
'bash' => BashShell,
|
|
14
|
+
'sh' => BashShell,
|
|
15
|
+
'dash' => BashShell,
|
|
16
|
+
'zsh' => BashShell,
|
|
17
|
+
'fish' => BashShell, # Fish can run bash scripts in compatibility mode
|
|
18
|
+
'powershell' => PowerShellShell,
|
|
19
|
+
'pwsh' => PowerShellShell,
|
|
20
|
+
'cmd' => CmdShell
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
# Detect the current shell from environment
|
|
25
|
+
def detect
|
|
26
|
+
shell_env = ENV['SHELL'] || ENV['COMSPEC'] || ''
|
|
27
|
+
|
|
28
|
+
if windows?
|
|
29
|
+
detect_windows_shell(shell_env)
|
|
30
|
+
else
|
|
31
|
+
detect_unix_shell(shell_env)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get shell by name
|
|
36
|
+
def get(shell_name)
|
|
37
|
+
shell_class = SHELLS[shell_name.downcase]
|
|
38
|
+
raise ArgumentError, "Unknown shell: #{shell_name}" unless shell_class
|
|
39
|
+
|
|
40
|
+
shell_class.new
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Get all shells for the current platform
|
|
44
|
+
def platform_shells
|
|
45
|
+
if windows?
|
|
46
|
+
[PowerShellShell.new, CmdShell.new]
|
|
47
|
+
else
|
|
48
|
+
[BashShell.new]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def windows?
|
|
55
|
+
RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def detect_unix_shell(shell_env)
|
|
59
|
+
# Extract shell name from path
|
|
60
|
+
shell_name = File.basename(shell_env) if shell_env
|
|
61
|
+
|
|
62
|
+
# Default to bash if we can't determine
|
|
63
|
+
shell_name ||= 'bash'
|
|
64
|
+
|
|
65
|
+
get(shell_name)
|
|
66
|
+
rescue ArgumentError
|
|
67
|
+
# Default to bash for unknown shells
|
|
68
|
+
BashShell.new
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def detect_windows_shell(comspec)
|
|
72
|
+
if comspec =~ /powershell|pwsh/i
|
|
73
|
+
PowerShellShell.new
|
|
74
|
+
else
|
|
75
|
+
# Default to CMD on Windows, but also create PowerShell shim
|
|
76
|
+
CmdShell.new
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|