mnenv 0.1.1 → 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/lib/mnenv/commands/uninstall_command.rb +80 -11
- data/lib/mnenv/commands/version_command.rb +11 -57
- data/lib/mnenv/installer/factory.rb +37 -8
- data/lib/mnenv/platform_detector.rb +109 -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.rb +4 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9bb839d75925723bae3de1d40012914fc768b8f981d4be837247ea0b8de8bf2d
|
|
4
|
+
data.tar.gz: 1335ac68fba15671370c1c42f4d6999707915fd3ec884d33ee47759f3ba95863
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b09af8fc57ec321e46c1b4976ff69e73f00b9443168659b7e343cb8a1f527ef64eaa0ea9dc0265fda6e4d8b678d351bca6fe1adca4b35ded707ddc1e4b895b18
|
|
7
|
+
data.tar.gz: 68a851a68c5a2feafe61cb47b0e68f98dc328d78c7e5459b31440250048c03fd19724cf2fcdf2462e46c6b00c6fdf6e33514d1c24569929d539fdaa8fe7efb69
|
|
@@ -7,36 +7,105 @@ module Mnenv
|
|
|
7
7
|
class UninstallCommand < Thor
|
|
8
8
|
namespace :uninstall
|
|
9
9
|
|
|
10
|
+
class_option :source, type: :string, enum: %w[gemfile binary],
|
|
11
|
+
desc: 'Source type to uninstall (gemfile or binary). If not specified, uninstalls all sources.'
|
|
10
12
|
class_option :force, type: :boolean, aliases: '-f', default: false,
|
|
11
13
|
desc: 'Force uninstallation without confirmation'
|
|
12
14
|
|
|
13
15
|
desc 'VERSION', 'Uninstall a specific Metanorma version'
|
|
16
|
+
method_option :source, type: :string, enum: %w[gemfile binary]
|
|
14
17
|
method_option :force, type: :boolean, aliases: '-f', default: false
|
|
15
18
|
def uninstall(version)
|
|
16
|
-
|
|
19
|
+
source = options[:source]
|
|
20
|
+
|
|
21
|
+
if source
|
|
22
|
+
# Uninstall specific source
|
|
23
|
+
uninstall_source(version, source)
|
|
24
|
+
else
|
|
25
|
+
# Uninstall all sources for this version
|
|
26
|
+
uninstall_all_sources(version)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Regenerate shims after uninstallation
|
|
30
|
+
ShimManager.new.regenerate_all
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
warn "Error: #{e.message}"
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def uninstall_source(version, source)
|
|
39
|
+
version_dir = Paths.version_install_dir(version, source)
|
|
17
40
|
|
|
18
41
|
unless Dir.exist?(version_dir)
|
|
42
|
+
puts "Version #{version} (source: #{source}) is not installed."
|
|
43
|
+
return
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
confirm_and_remove(version, source, version_dir)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def uninstall_all_sources(version)
|
|
50
|
+
# Find all installed sources for this version
|
|
51
|
+
installed_sources = find_installed_sources(version)
|
|
52
|
+
|
|
53
|
+
if installed_sources.empty?
|
|
19
54
|
puts "Version #{version} is not installed."
|
|
20
55
|
return
|
|
21
56
|
end
|
|
22
57
|
|
|
23
|
-
|
|
58
|
+
if installed_sources.length == 1
|
|
59
|
+
# Only one source, uninstall directly
|
|
60
|
+
source = installed_sources.first
|
|
61
|
+
version_dir = Paths.version_install_dir(version, source)
|
|
62
|
+
confirm_and_remove(version, source, version_dir)
|
|
63
|
+
else
|
|
64
|
+
# Multiple sources, ask which to uninstall
|
|
65
|
+
puts "Version #{version} has multiple sources installed:"
|
|
66
|
+
installed_sources.each do |src|
|
|
67
|
+
puts " - #{src}"
|
|
68
|
+
end
|
|
69
|
+
puts ''
|
|
70
|
+
|
|
71
|
+
prompt = TTY::Prompt.new
|
|
72
|
+
choices = installed_sources.map { |s| { name: s, value: s } }
|
|
73
|
+
choices << { name: 'All sources', value: 'all' }
|
|
74
|
+
|
|
75
|
+
selected = prompt.select('Which source(s) to uninstall?', choices)
|
|
76
|
+
|
|
77
|
+
if selected == 'all'
|
|
78
|
+
installed_sources.each do |src|
|
|
79
|
+
version_dir = Paths.version_install_dir(version, src)
|
|
80
|
+
confirm_and_remove(version, src, version_dir, skip_confirm: options[:force])
|
|
81
|
+
end
|
|
82
|
+
else
|
|
83
|
+
version_dir = Paths.version_install_dir(version, selected)
|
|
84
|
+
confirm_and_remove(version, selected, version_dir)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def find_installed_sources(version)
|
|
90
|
+
sources = []
|
|
91
|
+
%w[gemfile binary].each do |source|
|
|
92
|
+
version_dir = Paths.version_install_dir(version, source)
|
|
93
|
+
sources << source if Dir.exist?(version_dir)
|
|
94
|
+
end
|
|
95
|
+
sources
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def confirm_and_remove(version, source, version_dir, skip_confirm: false)
|
|
99
|
+
unless skip_confirm || options[:force]
|
|
24
100
|
prompt = TTY::Prompt.new
|
|
25
|
-
unless prompt.yes?("Uninstall Metanorma #{version}? This cannot be undone.")
|
|
101
|
+
unless prompt.yes?("Uninstall Metanorma #{version} (#{source})? This cannot be undone.")
|
|
26
102
|
puts 'Uninstallation cancelled.'
|
|
27
103
|
return
|
|
28
104
|
end
|
|
29
105
|
end
|
|
30
106
|
|
|
31
107
|
FileUtils.rm_rf(version_dir)
|
|
32
|
-
|
|
33
|
-
# Regenerate shims
|
|
34
|
-
ShimManager.new.regenerate_all
|
|
35
|
-
|
|
36
|
-
puts "Uninstalled Metanorma #{version}"
|
|
37
|
-
rescue StandardError => e
|
|
38
|
-
warn "Error: #{e.message}"
|
|
39
|
-
exit 1
|
|
108
|
+
puts "Uninstalled Metanorma #{version} (source: #{source})"
|
|
40
109
|
end
|
|
41
110
|
end
|
|
42
111
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'tty/prompt'
|
|
4
4
|
require 'json'
|
|
5
5
|
require_relative '../installer'
|
|
6
|
-
require_relative '../
|
|
6
|
+
require_relative '../version_resolver'
|
|
7
7
|
|
|
8
8
|
module Mnenv
|
|
9
9
|
class VersionCommand < Thor
|
|
@@ -68,7 +68,7 @@ module Mnenv
|
|
|
68
68
|
return
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
current_version, current_source =
|
|
71
|
+
current_version, current_source = resolver.resolve
|
|
72
72
|
|
|
73
73
|
case options[:format]
|
|
74
74
|
when 'json'
|
|
@@ -105,6 +105,11 @@ module Mnenv
|
|
|
105
105
|
|
|
106
106
|
private
|
|
107
107
|
|
|
108
|
+
# Get the shared resolver instance
|
|
109
|
+
def resolver
|
|
110
|
+
@resolver ||= VersionResolver.new
|
|
111
|
+
end
|
|
112
|
+
|
|
108
113
|
# List installed versions with their sources
|
|
109
114
|
# Uses Paths::INSTALLED_DIR with new naming convention: <version>-<source>
|
|
110
115
|
def list_installed_versions
|
|
@@ -129,7 +134,7 @@ module Mnenv
|
|
|
129
134
|
|
|
130
135
|
def resolve_version_and_source(version, source, interactive)
|
|
131
136
|
version, source = select_version_interactive if interactive || version.nil?
|
|
132
|
-
source ||=
|
|
137
|
+
source ||= resolver.resolve_source
|
|
133
138
|
[version, source]
|
|
134
139
|
end
|
|
135
140
|
|
|
@@ -140,14 +145,12 @@ module Mnenv
|
|
|
140
145
|
raise 'No versions installed. Run: mnenv install --list' if installed.empty?
|
|
141
146
|
|
|
142
147
|
choices = installed.flat_map do |version, sources|
|
|
143
|
-
sources.map do |
|
|
144
|
-
{ name: "#{version} (#{
|
|
148
|
+
sources.map do |src|
|
|
149
|
+
{ name: "#{version} (#{src})", value: [version, src] }
|
|
145
150
|
end
|
|
146
151
|
end
|
|
147
152
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
[version, source]
|
|
153
|
+
prompt.select('Select a version:', choices)
|
|
151
154
|
end
|
|
152
155
|
|
|
153
156
|
def verify_installed!(version, source)
|
|
@@ -160,54 +163,5 @@ module Mnenv
|
|
|
160
163
|
def installed_versions
|
|
161
164
|
list_installed_versions.keys.sort
|
|
162
165
|
end
|
|
163
|
-
|
|
164
|
-
def default_source
|
|
165
|
-
if File.exist?(Paths::SOURCE_FILE)
|
|
166
|
-
File.read(Paths::SOURCE_FILE).strip
|
|
167
|
-
else
|
|
168
|
-
'gemfile'
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def resolve_version
|
|
173
|
-
return ENV['METANORMA_VERSION'] if ENV['METANORMA_VERSION']
|
|
174
|
-
|
|
175
|
-
dir = Dir.pwd
|
|
176
|
-
loop do
|
|
177
|
-
return File.read(File.join(dir, '.metanorma-version')).strip if File.exist?(File.join(dir,
|
|
178
|
-
'.metanorma-version'))
|
|
179
|
-
|
|
180
|
-
parent = File.dirname(dir)
|
|
181
|
-
break if parent == dir # Reached root
|
|
182
|
-
|
|
183
|
-
dir = parent
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
return File.read(Paths::VERSION_FILE).strip if File.exist?(Paths::VERSION_FILE)
|
|
187
|
-
|
|
188
|
-
nil
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def resolve_source
|
|
192
|
-
return ENV['METANORMA_SOURCE'] if ENV['METANORMA_SOURCE']
|
|
193
|
-
|
|
194
|
-
dir = Dir.pwd
|
|
195
|
-
loop do
|
|
196
|
-
return File.read(File.join(dir, '.metanorma-source')).strip if File.exist?(File.join(dir, '.metanorma-source'))
|
|
197
|
-
|
|
198
|
-
parent = File.dirname(dir)
|
|
199
|
-
break if parent == dir # Reached root
|
|
200
|
-
|
|
201
|
-
dir = parent
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
return File.read(Paths::SOURCE_FILE).strip if File.exist?(Paths::SOURCE_FILE)
|
|
205
|
-
|
|
206
|
-
'gemfile'
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def resolve_current
|
|
210
|
-
[resolve_version, resolve_source]
|
|
211
|
-
end
|
|
212
166
|
end
|
|
213
167
|
end
|
|
@@ -1,17 +1,46 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../source_registry'
|
|
4
|
+
|
|
3
5
|
module Mnenv
|
|
6
|
+
# Factory for creating installer instances based on source type
|
|
7
|
+
# Uses SourceRegistry for extensibility - new sources just need to register
|
|
4
8
|
class InstallerFactory
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
class UnknownSourceError < StandardError; end
|
|
10
|
+
|
|
11
|
+
# Create an installer for the given version and source
|
|
12
|
+
# @param version [String] The version to install
|
|
13
|
+
# @param source [String] The source type (e.g., 'gemfile', 'binary')
|
|
14
|
+
# @param target_dir [String, nil] Optional custom target directory
|
|
15
|
+
# @return [Installer] An installer instance
|
|
16
|
+
# @raise [UnknownSourceError] If source is not registered
|
|
17
|
+
def self.create(version, source:, target_dir: nil)
|
|
18
|
+
installer_class = SourceRegistry.installer(source.to_s)
|
|
19
|
+
|
|
20
|
+
unless installer_class
|
|
21
|
+
available = SourceRegistry.all_names.join(', ')
|
|
12
22
|
raise Installer::InstallationError,
|
|
13
|
-
"Unknown source: #{source}.
|
|
23
|
+
"Unknown source: #{source}. Available sources: #{available}"
|
|
14
24
|
end
|
|
25
|
+
|
|
26
|
+
installer_class.new(version, source: source, target_dir: target_dir)
|
|
27
|
+
rescue SourceRegistry::UnknownSourceError
|
|
28
|
+
available = SourceRegistry.all_names.join(', ')
|
|
29
|
+
raise Installer::InstallationError,
|
|
30
|
+
"Unknown source: #{source}. Available sources: #{available}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Check if a source is supported
|
|
34
|
+
# @param source [String] The source type
|
|
35
|
+
# @return [Boolean]
|
|
36
|
+
def self.supported?(source)
|
|
37
|
+
SourceRegistry.registered?(source.to_s)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get list of supported sources
|
|
41
|
+
# @return [Array<String>]
|
|
42
|
+
def self.supported_sources
|
|
43
|
+
SourceRegistry.all_names
|
|
15
44
|
end
|
|
16
45
|
end
|
|
17
46
|
end
|
|
@@ -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
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'source_registry'
|
|
4
|
+
require_relative 'gemfile_repository'
|
|
5
|
+
require_relative 'binary_repository'
|
|
6
|
+
require_relative 'models/gemfile_version'
|
|
7
|
+
require_relative 'models/binary_version'
|
|
8
|
+
require_relative 'installers/gemfile_installer'
|
|
9
|
+
require_relative 'installers/binary_installer'
|
|
10
|
+
|
|
11
|
+
module Mnenv
|
|
12
|
+
# Auto-registration of built-in sources
|
|
13
|
+
# This enables the plugin architecture - new sources just need to register themselves
|
|
14
|
+
module Sources
|
|
15
|
+
class << self
|
|
16
|
+
# Register all built-in sources
|
|
17
|
+
def setup
|
|
18
|
+
register_gemfile
|
|
19
|
+
register_binary
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def register_gemfile
|
|
25
|
+
SourceRegistry.register(
|
|
26
|
+
name: 'gemfile',
|
|
27
|
+
repository: GemfileRepository,
|
|
28
|
+
model: GemfileVersion,
|
|
29
|
+
installer: Installers::GemfileInstaller
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def register_binary
|
|
34
|
+
SourceRegistry.register(
|
|
35
|
+
name: 'binary',
|
|
36
|
+
repository: BinaryRepository,
|
|
37
|
+
model: BinaryVersion,
|
|
38
|
+
installer: Installers::BinaryInstaller
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Auto-setup on load
|
|
46
|
+
Mnenv::Sources.setup
|
data/lib/mnenv/version.rb
CHANGED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mnenv
|
|
4
|
+
# Centralized version and source resolution with clear precedence:
|
|
5
|
+
# 1. Environment variables (METANORMA_VERSION, METANORMA_SOURCE)
|
|
6
|
+
# 2. Local files (.metanorma-version, .metanorma-source) - walk up tree
|
|
7
|
+
# 3. Global files (~/.mnenv/version, ~/.mnenv/source)
|
|
8
|
+
# 4. Defaults (gemfile for source)
|
|
9
|
+
#
|
|
10
|
+
# This class is the single source of truth for version resolution.
|
|
11
|
+
# The Bash resolver (lib/mnenv/resolver) is kept for shims only.
|
|
12
|
+
class VersionResolver
|
|
13
|
+
# Resolve the current Metanorma version
|
|
14
|
+
# @return [String, nil] The resolved version or nil if not set
|
|
15
|
+
def resolve_version
|
|
16
|
+
from_env('METANORMA_VERSION') ||
|
|
17
|
+
from_local_file('.metanorma-version') ||
|
|
18
|
+
from_global_file(Paths::VERSION_FILE)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Resolve the current Metanorma source
|
|
22
|
+
# @return [String] The resolved source (defaults to 'gemfile')
|
|
23
|
+
def resolve_source
|
|
24
|
+
from_env('METANORMA_SOURCE') ||
|
|
25
|
+
from_local_file('.metanorma-source') ||
|
|
26
|
+
from_global_file(Paths::SOURCE_FILE) ||
|
|
27
|
+
'gemfile'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Resolve both version and source
|
|
31
|
+
# @return [Array<String, String>] Tuple of [version, source]
|
|
32
|
+
def resolve
|
|
33
|
+
[resolve_version, resolve_source]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Check if a version is set anywhere
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
def version_set?
|
|
39
|
+
!resolve_version.nil?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Check if a source is explicitly set (not default)
|
|
43
|
+
# @return [Boolean]
|
|
44
|
+
def source_set?
|
|
45
|
+
from_env('METANORMA_SOURCE') ||
|
|
46
|
+
from_local_file('.metanorma-source') ||
|
|
47
|
+
from_global_file(Paths::SOURCE_FILE)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Get the source of version resolution (for debugging)
|
|
51
|
+
# @return [Symbol] :environment, :local, :global, or :none
|
|
52
|
+
def version_source
|
|
53
|
+
return :environment if from_env('METANORMA_VERSION')
|
|
54
|
+
return :local if from_local_file('.metanorma-version')
|
|
55
|
+
return :global if from_global_file(Paths::VERSION_FILE)
|
|
56
|
+
|
|
57
|
+
:none
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Get the source of source resolution (for debugging)
|
|
61
|
+
# @return [Symbol] :environment, :local, :global, or :default
|
|
62
|
+
def source_source
|
|
63
|
+
return :environment if from_env('METANORMA_SOURCE')
|
|
64
|
+
return :local if from_local_file('.metanorma-source')
|
|
65
|
+
return :global if from_global_file(Paths::SOURCE_FILE)
|
|
66
|
+
|
|
67
|
+
:default
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Read from environment variable
|
|
73
|
+
# @param var [String] Environment variable name
|
|
74
|
+
# @return [String, nil] Value or nil if not set/empty
|
|
75
|
+
def from_env(var)
|
|
76
|
+
value = ENV[var]
|
|
77
|
+
value&.strip&.then { |v| v unless v.empty? }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Read from local file, walking up directory tree
|
|
81
|
+
# @param filename [String] Filename to look for
|
|
82
|
+
# @return [String, nil] File contents or nil if not found
|
|
83
|
+
def from_local_file(filename)
|
|
84
|
+
dir = Dir.pwd
|
|
85
|
+
|
|
86
|
+
loop do
|
|
87
|
+
path = File.join(dir, filename)
|
|
88
|
+
return File.read(path).strip if File.exist?(path)
|
|
89
|
+
|
|
90
|
+
parent = File.dirname(dir)
|
|
91
|
+
break if parent == dir # Reached root
|
|
92
|
+
|
|
93
|
+
dir = parent
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Read from global file
|
|
100
|
+
# @param path [String] Full path to file
|
|
101
|
+
# @return [String, nil] File contents or nil if not found
|
|
102
|
+
def from_global_file(path)
|
|
103
|
+
File.read(path).strip if File.exist?(path)
|
|
104
|
+
rescue StandardError
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
data/lib/mnenv.rb
CHANGED
|
@@ -4,8 +4,11 @@ require 'lutaml/model'
|
|
|
4
4
|
require 'thor'
|
|
5
5
|
|
|
6
6
|
require_relative 'mnenv/paths'
|
|
7
|
+
require_relative 'mnenv/platform_detector'
|
|
8
|
+
require_relative 'mnenv/version_resolver'
|
|
7
9
|
require_relative 'mnenv/models'
|
|
10
|
+
require_relative 'mnenv/source_registry'
|
|
11
|
+
require_relative 'mnenv/sources'
|
|
8
12
|
require_relative 'mnenv/commands'
|
|
9
13
|
require_relative 'mnenv/installer'
|
|
10
|
-
require_relative 'mnenv/source_registry'
|
|
11
14
|
require_relative 'mnenv/cli'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mnenv
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -209,6 +209,7 @@ files:
|
|
|
209
209
|
- lib/mnenv/models/snap_version.rb
|
|
210
210
|
- lib/mnenv/models/version.rb
|
|
211
211
|
- lib/mnenv/paths.rb
|
|
212
|
+
- lib/mnenv/platform_detector.rb
|
|
212
213
|
- lib/mnenv/repository.rb
|
|
213
214
|
- lib/mnenv/resolver
|
|
214
215
|
- lib/mnenv/shells/base.rb
|
|
@@ -221,7 +222,9 @@ files:
|
|
|
221
222
|
- lib/mnenv/snap/fetcher.rb
|
|
222
223
|
- lib/mnenv/snap_repository.rb
|
|
223
224
|
- lib/mnenv/source_registry.rb
|
|
225
|
+
- lib/mnenv/sources.rb
|
|
224
226
|
- lib/mnenv/version.rb
|
|
227
|
+
- lib/mnenv/version_resolver.rb
|
|
225
228
|
- lib/mnenv/versions_manager.rb
|
|
226
229
|
- mnenv.gemspec
|
|
227
230
|
- scripts/cross-source-switching-test.sh
|