Class: Vcdeps::CLI
- Inherits:
-
Object
- Object
- Vcdeps::CLI
- Defined in:
- lib/vcdeps/cli.rb
Overview
Command-line interface for the vcdeps executable. Mirrors the vcvars CLI:
run returns an Integer exit status (never calls exit), dispatch is a plain
case, flags are hand-parsed (no optparse), and one rescue turns every known
error into a clean one-liner with no backtrace.
Class Method Summary collapse
Instance Method Summary collapse
- #cmd_baseline(argv) ⇒ Object
- #cmd_bootstrap(_argv) ⇒ Object
- #cmd_doctor(argv) ⇒ Object
- #cmd_install(argv) ⇒ Object
- #cmd_vendor(argv) ⇒ Object
-
#cmd_version ⇒ Object
--- commands ------------------------------------------------------------.
- #cmd_where(_argv) ⇒ Object
-
#extract_opt(argv, name) ⇒ Object
Pulls "--opt value" or "--opt=value" out of argv (mutating it).
- #print_help ⇒ Object
-
#resolve_manifest(explicit) ⇒ Object
Manifest default: cwd; if cwd has no vcpkg.json and exactly one ext/*/vcpkg.json exists, use that one (gem-layout DX).
-
#run(argv) ⇒ Object
Returns a process exit status (Integer).
Class Method Details
.start(argv) ⇒ Object
12 13 14 |
# File 'lib/vcdeps/cli.rb', line 12 def self.start(argv) new.run(argv) end |
Instance Method Details
#cmd_baseline(argv) ⇒ Object
129 130 131 132 133 134 |
# File 'lib/vcdeps/cli.rb', line 129 def cmd_baseline(argv) manifest = extract_opt(argv, "--manifest") sha = Vcdeps.baseline!(manifest: resolve_manifest(manifest), out: $stderr) puts sha 0 end |
#cmd_bootstrap(_argv) ⇒ Object
136 137 138 139 140 |
# File 'lib/vcdeps/cli.rb', line 136 def cmd_bootstrap(_argv) tool = Vcdeps.bootstrap!(out: $stderr) puts "Bootstrapped: #{tool}" 0 end |
#cmd_doctor(argv) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/vcdeps/cli.rb', line 52 def cmd_doctor(argv) require "vcdeps/doctor" manifest = extract_opt(argv, "--manifest") deep = !argv.include?("--quick") checks = Doctor.run(manifest: manifest, deep: deep) checks.each do |c| puts "#{c.icon} #{c.label}" next unless c.detail && !c.detail.to_s.empty? c.detail.to_s.each_line { |line| puts " #{line.chomp}" } end fails = checks.count { |c| c.status == :fail } warns = checks.count { |c| c.status == :warn } puts if fails.zero? extra = warns.positive? ? " (#{warns} warning#{'s' if warns > 1})" : "" puts "Summary: no blocking problems#{extra}." 0 else puts "Summary: #{fails} problem#{'s' if fails > 1} found — see remedies above." 1 end end |
#cmd_install(argv) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/vcdeps/cli.rb', line 92 def cmd_install(argv) manifest = extract_opt(argv, "--manifest") triplet = extract_opt(argv, "--triplet") force = argv.delete("--force") ? true : false manifest_dir = resolve_manifest(manifest) inst = Vcdeps.install!(manifest: manifest_dir, triplet: triplet, force: force, out: $stderr) puts inst.prefix 0 end |
#cmd_vendor(argv) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/vcdeps/cli.rb', line 104 def cmd_vendor(argv) into = extract_opt(argv, "--into") manifest = extract_opt(argv, "--manifest") triplet = extract_opt(argv, "--triplet") licenses = !argv.delete("--no-licenses") shim = !argv.delete("--no-shim") if into.nil? || into.empty? warn "vcdeps vendor: --into DIR is required." warn "Example: vcdeps vendor --into lib/foo/vendor" return 1 end inst = Vcdeps.install!(manifest: resolve_manifest(manifest), triplet: triplet, out: $stderr) written = Vcdeps.vendor!(inst, into: into, licenses: licenses, shim: shim, out: $stderr) if written.empty? puts "(nothing to vendor — static-md or header-only build)" else written.each { |f| puts f } end 0 end |
#cmd_version ⇒ Object
--- commands ------------------------------------------------------------
47 48 49 50 |
# File 'lib/vcdeps/cli.rb', line 47 def cmd_version puts "vcdeps #{Vcdeps::VERSION}" 0 end |
#cmd_where(_argv) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/vcdeps/cli.rb', line 78 def cmd_where(_argv) tool = Vcdeps.tool if tool puts tool.to_s puts "exe: #{tool.exe}" puts "version: #{tool.version}" puts "source: #{tool.source}" 0 else Vcdeps.tool! # raises ToolNotFound with the three remedies -> rescued as a one-liner 0 end end |
#extract_opt(argv, name) ⇒ Object
Pulls "--opt value" or "--opt=value" out of argv (mutating it). Returns the value or nil; raises on a dangling flag.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/vcdeps/cli.rb', line 158 def extract_opt(argv, name) if (i = argv.index(name)) value = argv[i + 1] if value.nil? argv.slice!(i, 1) raise Error, "#{name} requires a value." end argv.slice!(i, 2) return value end prefix = "#{name}=" if (i = argv.index { |a| a.to_s.start_with?(prefix) }) value = argv[i][prefix.length..] argv.slice!(i, 1) return value end nil end |
#print_help ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/vcdeps/cli.rb', line 177 def print_help puts <<~HELP vcdeps #{Vcdeps::VERSION} — vcpkg-powered native dependencies for Ruby C extensions on Windows (MSVC). Usage: vcdeps doctor [--manifest DIR] [--quick] Diagnose vcpkg acquisition + mkmf wiring vcdeps where Show the resolved vcpkg (path, version, source) vcdeps install [--manifest DIR] [--triplet T] [--force] Pre-build the manifest's ports (CI / warm cache) vcdeps vendor --into DIR [--manifest DIR] [--triplet T] [--no-licenses] [--no-shim] install! then vendor DLLs + licenses + preload shim vcdeps baseline [--manifest DIR] Add/refresh "builtin-baseline" in vcpkg.json vcdeps bootstrap Create a private vcpkg under %LOCALAPPDATA%\\vcdeps vcdeps version vcdeps help Examples: vcdeps doctor --manifest ext/foo vcdeps install --manifest ext/foo --triplet x64-windows-static-md vcdeps vendor --into lib/foo/vendor --manifest ext/foo vcdeps baseline --manifest ext/foo In extconf.rb, `require "vcdeps/mkmf"; Vcdeps.mkmf!(vendor: ...)` does the install + wiring + vendoring automatically — no CLI step is needed to build. HELP end |
#resolve_manifest(explicit) ⇒ Object
Manifest default: cwd; if cwd has no vcpkg.json and exactly one ext/*/vcpkg.json exists, use that one (gem-layout DX).
146 147 148 149 150 151 152 153 154 |
# File 'lib/vcdeps/cli.rb', line 146 def resolve_manifest(explicit) return explicit if explicit && !explicit.empty? return Dir.pwd if File.exist?(File.join(Dir.pwd, "vcpkg.json")) ext_manifests = Dir[File.join(Dir.pwd, "ext", "*", "vcpkg.json")] return File.dirname(ext_manifests.first) if ext_manifests.size == 1 Dir.pwd end |
#run(argv) ⇒ Object
Returns a process exit status (Integer).
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/vcdeps/cli.rb', line 17 def run(argv) argv = argv.dup command = argv.shift case command when "doctor" then cmd_doctor(argv) when "where" then cmd_where(argv) when "install" then cmd_install(argv) when "vendor" then cmd_vendor(argv) when "baseline" then cmd_baseline(argv) when "bootstrap" then cmd_bootstrap(argv) when "version", "-v", "--version" then cmd_version when nil, "help", "-h", "--help" then print_help; 0 else warn "vcdeps: unknown command #{command.inspect}\n\n" print_help 1 end rescue Vcdeps::Error, Vcvars::Error, ArgumentError => e # Library messages already carry the "vcdeps: " prefix (§2.1); don't double # it when we re-emit them through the CLI. msg = e..to_s.sub(/\Avcdeps:\s*/, "") warn "vcdeps: #{msg}" 1 rescue Interrupt 130 end |