Module: PWN::Setup
- Defined in:
- lib/pwn/setup.rb
Overview
PWN::Setup — post-install "doctor" and capability provisioner.
PWN ships as a single gem whose runtime is 100 % autoloaded
(lib/pwn.rb) — a plugin whose native gem or OS binary is missing
costs nothing until you touch that constant. PWN::Setup is the
piece that grows a bare gem install pwn into a fully-armed host
after the gem is installed, instead of before via a chain
of bash scripts that assume /opt/pwn, rvmsudo, screen, and
MacPorts.
It is the Ruby-native, versioned-with-the-gem replacement for the
case $os blocks previously buried in install.sh and
packer/provisioners/pwn.sh.
pwn setup # doctor (read-only)
pwn setup --check # same
pwn setup --deps # install OS headers for EVERY native gem
pwn setup --profile web # install just what TransparentBrowser/Burp need
pwn setup --profile sdr --yes # non-interactive
pwn setup --list-profiles
Also exposed as pwn_setup (driver) and pwn --setup[=PROFILE].
Constant Summary collapse
- NATIVE_GEMS =
Native-extension Ruby gems → OS headers/libs required to compile them,
- per package manager, plus the PWN
constants they unlock.
{ 'pg' => { apt: %w[postgresql-server-dev-all], dnf: %w[postgresql-devel], pacman: %w[postgresql-libs], brew: %w[postgresql], port: %w[postgresql16-server], plugins: %w[PWN::Plugins::DAOPostgres] }, 'sqlite3' => { apt: %w[libsqlite3-dev], dnf: %w[sqlite-devel], pacman: %w[sqlite], brew: %w[sqlite], port: %w[sqlite3], plugins: %w[PWN::Plugins::DAOSqlite3] }, 'pcaprub' => { apt: %w[libpcap-dev], dnf: %w[libpcap-devel], pacman: %w[libpcap], brew: %w[libpcap], port: %w[libpcap], plugins: %w[PWN::Plugins::Packet extro_packet] }, 'rmagick' => { apt: %w[imagemagick libmagickwand-dev], dnf: %w[ImageMagick-devel], pacman: %w[imagemagick], brew: %w[imagemagick], port: %w[imagemagick], plugins: %w[PWN::Plugins::OCR PWN::Reports] }, 'rtesseract' => { apt: %w[tesseract-ocr tesseract-ocr-all], dnf: %w[tesseract], pacman: %w[tesseract tesseract-data-eng], brew: %w[tesseract], port: %w[tesseract], plugins: %w[PWN::Plugins::OCR extro_vision] }, 'ruby-audio' => { apt: %w[libsndfile1-dev], dnf: %w[libsndfile-devel], pacman: %w[libsndfile], brew: %w[libsndfile], port: %w[libsndfile], plugins: %w[PWN::Plugins::Voice PWN::SDR extro_voice] }, 'curses' => { apt: %w[libncurses-dev], dnf: %w[ncurses-devel], pacman: %w[ncurses], brew: %w[ncurses], port: %w[ncurses], plugins: %w[PWN::Plugins::REPL] }, 'libusb' => { apt: %w[libusb-1.0-0-dev], dnf: %w[libusbx-devel], pacman: %w[libusb], brew: %w[libusb], port: %w[libusb], plugins: %w[PWN::SDR PWN::Plugins::BusPirate] }, 'ffi' => { apt: %w[libffi-dev], dnf: %w[libffi-devel], pacman: %w[libffi], brew: %w[libffi], port: %w[libffi], plugins: %w[PWN::FFI] }, 'nokogiri' => { apt: %w[libxml2-dev libxslt1-dev], dnf: %w[libxml2-devel libxslt-devel], pacman: %w[libxml2 libxslt], brew: %w[libxml2], port: %w[libxml2 libxslt], plugins: %w[PWN::Plugins::TransparentBrowser PWN::WWW] }, 'oily_png' => { apt: %w[build-essential], dnf: %w[gcc make], pacman: %w[base-devel], brew: %w[gcc], port: %w[gcc12], plugins: %w[PWN::Plugins::ScannableCodes] }, 'eventmachine' => { apt: %w[libssl-dev], dnf: %w[openssl-devel], pacman: %w[openssl], brew: %w[openssl], port: %w[openssl], plugins: %w[PWN::Plugins::Sock PWN::Plugins::IRC] }, 'gruff' => { apt: %w[imagemagick libmagickwand-dev], dnf: %w[ImageMagick-devel], pacman: %w[imagemagick], brew: %w[imagemagick], port: %w[imagemagick], plugins: %w[PWN::Reports] }, # Not a native extension, but gated by required_ruby_version >= 4.0 on # rubygems.org — so it cannot be a hard runtime dependency of pwn while # pwn.gemspec advertises `>= 3.3`. Managed here instead so # `gem install pwn` succeeds on distro rubies (3.3/3.4) and `pwn setup` # installs it post-hoc where possible. See install-matrix.yml. 'meshtastic' => { apt: %w[], dnf: %w[], pacman: %w[], brew: %w[], port: %w[], min_ruby: '4.0.0', plugins: %w[PWN::Plugins::REPL#pwn-mesh] } }.freeze
- TOOLCHAIN =
External binaries PWN wraps → OS packages that provide them. (Extrospection.probe_toolchain already knows how to detect these; this table knows how to install them.)
{ 'nmap' => { apt: %w[nmap], dnf: %w[nmap], pacman: %w[nmap], brew: %w[nmap], port: %w[nmap], plugins: %w[PWN::Plugins::NmapIt] }, 'chromium' => { apt: %w[chromium], dnf: %w[chromium], pacman: %w[chromium], brew: %w[chromium], port: %w[chromium], plugins: %w[PWN::Plugins::TransparentBrowser extro_verify extro_watch] }, 'geckodriver' => { apt: %w[firefox-esr], dnf: %w[firefox], pacman: %w[geckodriver], brew: %w[geckodriver], port: %w[geckodriver], plugins: %w[PWN::Plugins::TransparentBrowser] }, 'msfconsole' => { apt: %w[metasploit-framework], dnf: %w[metasploit-framework], pacman: %w[metasploit], brew: %w[metasploit], port: %w[], plugins: %w[PWN::Plugins::Metasploit] }, 'burpsuite' => { apt: %w[burpsuite], dnf: %w[], pacman: %w[burpsuite], brew: %w[burp-suite], port: %w[], plugins: %w[PWN::Plugins::BurpSuite] }, 'zaproxy' => { apt: %w[zaproxy], dnf: %w[], pacman: %w[zaproxy], brew: %w[zap], port: %w[], plugins: %w[PWN::Plugins::Zaproxy] }, 'sqlmap' => { apt: %w[sqlmap], dnf: %w[sqlmap], pacman: %w[sqlmap], brew: %w[sqlmap], port: %w[], plugins: %w[PWN::Plugins::Fuzz] }, 'tor' => { apt: %w[tor], dnf: %w[tor], pacman: %w[tor], brew: %w[tor], port: %w[tor], plugins: %w[PWN::Plugins::Tor] }, 'tshark' => { apt: %w[tshark], dnf: %w[wireshark-cli], pacman: %w[wireshark-cli], brew: %w[wireshark], port: %w[wireshark], plugins: %w[PWN::Plugins::Packet extro_packet] }, 'tcpdump' => { apt: %w[tcpdump], dnf: %w[tcpdump], pacman: %w[tcpdump], brew: %w[tcpdump], port: %w[tcpdump], plugins: %w[PWN::Plugins::Packet extro_packet] }, 'tesseract' => { apt: %w[tesseract-ocr], dnf: %w[tesseract], pacman: %w[tesseract], brew: %w[tesseract], port: %w[tesseract], plugins: %w[PWN::Plugins::OCR extro_vision] }, 'zbarimg' => { apt: %w[zbar-tools], dnf: %w[zbar], pacman: %w[zbar], brew: %w[zbar], port: %w[zbar], plugins: %w[PWN::Plugins::ScannableCodes extro_vision] }, 'espeak-ng' => { apt: %w[espeak-ng], dnf: %w[espeak-ng], pacman: %w[espeak-ng], brew: %w[espeak-ng], port: %w[espeak-ng], plugins: %w[PWN::Plugins::Voice extro_voice] }, 'sox' => { apt: %w[sox], dnf: %w[sox], pacman: %w[sox], brew: %w[sox], port: %w[sox], plugins: %w[PWN::Plugins::Voice PWN::SDR] }, 'gqrx' => { apt: %w[gqrx-sdr], dnf: %w[gqrx], pacman: %w[gqrx], brew: %w[gqrx], port: %w[gqrx], plugins: %w[PWN::SDR extro_rf_tune] }, 'rtl_sdr' => { apt: %w[rtl-sdr], dnf: %w[rtl-sdr], pacman: %w[rtl-sdr], brew: %w[librtlsdr], port: %w[rtl-sdr], plugins: %w[PWN::SDR PWN::FFI::RTLSdr] }, 'hackrf_info' => { apt: %w[hackrf], dnf: %w[hackrf], pacman: %w[hackrf], brew: %w[hackrf], port: %w[hackrf], plugins: %w[PWN::SDR PWN::FFI::HackRF] }, 'SoapySDRUtil' => { apt: %w[soapysdr-tools], dnf: %w[SoapySDR], pacman: %w[soapysdr], brew: %w[soapysdr], port: %w[SoapySDR], plugins: %w[PWN::SDR PWN::FFI::SoapySDR] }, 'multimon-ng' => { apt: %w[multimon-ng], dnf: %w[multimon-ng], pacman: %w[multimon-ng], brew: %w[multimon-ng], port: %w[], plugins: %w[PWN::SDR::Decoder] }, 'dot' => { apt: %w[graphviz], dnf: %w[graphviz], pacman: %w[graphviz], brew: %w[graphviz], port: %w[graphviz], plugins: %w[documentation/diagrams] }, 'adb' => { apt: %w[adb], dnf: %w[android-tools], pacman: %w[android-tools], brew: %w[android-platform-tools], port: %w[], plugins: %w[PWN::Plugins::Android] }, 'baresip' => { apt: %w[baresip], dnf: %w[baresip], pacman: %w[baresip], brew: %w[baresip], port: %w[], plugins: %w[PWN::Plugins::BareSIP extro_telecomm] }, 'whois' => { apt: %w[whois], dnf: %w[whois], pacman: %w[whois], brew: %w[whois], port: %w[whois], plugins: %w[extro_osint] }, 'jq' => { apt: %w[jq], dnf: %w[jq], pacman: %w[jq], brew: %w[jq], port: %w[jq], plugins: %w[extro_osint] } }.freeze
- PROFILES =
Capability profiles — how you get the ergonomics of
pwn-fullwithout shipping a second gem.pwn setup --profile <name>. { core: { desc: '~/.pwn bootstrap + vault + REPL (always runs on bare `pwn setup --deps`)', gems: %w[ffi nokogiri curses eventmachine], bins: %w[] }, ai: { desc: 'verify at least one AI engine key/oauth in ~/.pwn/pwn.yaml', gems: %w[], bins: %w[jq] }, web: { desc: 'TransparentBrowser · BurpSuite · Zaproxy · extro_verify · extro_watch', gems: %w[nokogiri eventmachine], bins: %w[chromium geckodriver burpsuite zaproxy sqlmap tor] }, net: { desc: 'NmapIt · Packet · extro_packet · extro_osint', gems: %w[pcaprub], bins: %w[nmap tshark tcpdump whois jq] }, db: { desc: 'DAOPostgres · DAOSqlite3 · DAOMongo', gems: %w[pg sqlite3], bins: %w[] }, sdr: { desc: 'PWN::SDR · GQRX · FFI DSP backends · extro_rf_tune', gems: %w[ruby-audio libusb ffi], bins: %w[gqrx rtl_sdr hackrf_info SoapySDRUtil multimon-ng sox] }, vision: { desc: 'OCR · ScannableCodes · Reports · extro_vision', gems: %w[rmagick rtesseract oily_png gruff], bins: %w[tesseract zbarimg dot] }, voice: { desc: 'PWN::Plugins::Voice · extro_voice', gems: %w[ruby-audio], bins: %w[espeak-ng sox] }, exploit: { desc: 'Metasploit · sqlmap', gems: %w[], bins: %w[msfconsole sqlmap] }, hardware: { desc: 'Serial · BusPirate · Android · BareSIP · extro_serial · extro_telecomm', gems: %w[libusb], bins: %w[adb baresip] }, full: { desc: 'everything above', gems: NATIVE_GEMS.keys, bins: TOOLCHAIN.keys } }.freeze
- OK =
"\e[32mok\e[0m"- MISS =
"\e[31mMISSING\e[0m"
Class Method Summary collapse
-
.authors ⇒ Object
- Author(s)
0day Inc.
-
.check(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.check( io: 'optional - IO to write the report to (default $stdout)' ).
-
.deps(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.deps( profile: 'optional - one of PROFILES.keys (default :full)', yes: 'optional - non-interactive; assume yes to prompts (default false)', dry_run: 'optional - print commands only, do not execute (default false)', io: 'optional - IO to write to (default $stdout)' ).
-
.help ⇒ Object
Display Usage for this Module.
-
.list_profiles(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.list_profiles( io: 'optional - IO to write to (default $stdout)' ).
-
.migrate(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.migrate( fix: 'optional - also autofix incompatible ~/.pwn files (default false)', dry_run: 'optional - print what WOULD happen (default false)', yes: 'optional - alias for fix:true (CI-friendly)', io: 'optional - IO to write to (default $stdout)' ).
-
.pkg_manager ⇒ Object
- Supported Method Parameters
PWN::Setup.pkg_manager.
Class Method Details
.authors ⇒ Object
- Author(s)
0day Inc. support@0dayinc.com
578 579 580 581 582 |
# File 'lib/pwn/setup.rb', line 578 public_class_method def self. "AUTHOR(S): 0day Inc. <support@0dayinc.com> " end |
.check(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.check( io: 'optional - IO to write the report to (default $stdout)' )
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/pwn/setup.rb', line 323 public_class_method def self.check(opts = {}) io = opts[:io] || $stdout pm = pkg_manager os = detect_os_attr(attr: :type, fallback: RbConfig::CONFIG['host_os']) arch = detect_os_attr(attr: :arch, fallback: RbConfig::CONFIG['host_cpu']) io.puts "PWN v#{PWN::VERSION} · ruby #{RUBY_VERSION} · #{os} #{arch} · pkg-manager: #{pm[:key]}" io.puts # ~/.pwn ----------------------------------------------------------- pwn_root = File.join(Dir.home, '.pwn') pwn_yaml = File.join(pwn_root, 'pwn.yaml') pwn_dec = File.join(pwn_root, 'pwn.yaml.decryptor') root_ok = File.directory?(pwn_root) root_note = root_ok ? "(#{Dir.children(pwn_root).length} entries)" : '(will be created on first `pwn` launch)' io.puts "#{'~/.pwn/'.ljust(26)} #{root_ok ? OK : MISS} #{root_note}" yaml_ok = File.file?(pwn_yaml) dec_state = File.file?(pwn_dec) ? 'present' : 'MISSING' yaml_note = yaml_ok ? "(encrypted, decryptor #{dec_state})" : '(run `pwn` once, then `pwn-vault` to configure)' io.puts "#{'~/.pwn/pwn.yaml'.ljust(26)} #{yaml_ok ? OK : MISS} #{yaml_note}" engine = ai_active_engine key_ok = ai_key_configured?(engine: engine) engine_note = if engine "#{engine} #{key_ok ? '(key set)' : '(no key — set via `pwn-vault`)'}" else '(no ai.active in pwn.yaml)' end io.puts "#{'AI engine'.ljust(26)} #{key_ok ? OK : MISS} #{engine_note}" io.puts # Native gems ------------------------------------------------------ io.puts 'Ruby extensions' gem_missing = [] NATIVE_GEMS.each do |gem_name, | ok = gem_loadable?(name: gem_name) gem_missing << gem_name unless ok need = ok ? '' : "(needs: #{Array([pm[:key]]).join(' ')})" io.puts " #{gem_name.to_s.ljust(14)} #{ok ? OK : MISS} #{need.ljust(42)} → #{Array([:plugins]).join(', ')}" end io.puts # Toolchain -------------------------------------------------------- io.puts "#{'External toolchain'.ljust(46)} used by" bin_missing = [] TOOLCHAIN.each do |bin, | path = which(name: bin) bin_missing << bin if path.empty? shown_path = path.empty? ? '' : path[0, 24] io.puts " #{bin.to_s.ljust(16)} #{path.empty? ? MISS : OK} #{shown_path.ljust(24)} #{Array([:plugins]).join(', ')}" end io.puts # ~/.pwn state ---------------------------------------------------- migrate = nil if defined?(PWN::Migrate) migrate = PWN::Migrate.check(io: io) io.puts end total = NATIVE_GEMS.size + TOOLCHAIN.size missing = gem_missing.size + bin_missing.size io.puts "#{total - missing} / #{total} capabilities usable · #{missing} degraded" io.puts unless missing.zero? io.puts 'Run `pwn setup --deps` to install missing OS headers/tools, or' io.puts ' `pwn setup --profile <name>` for a subset. See `pwn setup --list-profiles`.' end { ok: missing.zero? && Array(migrate && migrate[:incompatible]).empty?, native_gems_missing: gem_missing, toolchain_missing: bin_missing, state: migrate, pkg_manager: pm[:key], os: os, arch: arch } rescue StandardError => e raise e end |
.deps(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.deps( profile: 'optional - one of PROFILES.keys (default :full)', yes: 'optional - non-interactive; assume yes to prompts (default false)', dry_run: 'optional - print commands only, do not execute (default false)', io: 'optional - IO to write to (default $stdout)' )
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'lib/pwn/setup.rb', line 406 public_class_method def self.deps(opts = {}) profile = (opts[:profile] || :full).to_sym yes = opts[:yes] ? true : false dry_run = opts[:dry_run] ? true : false io = opts[:io] || $stdout raise "Unknown profile '#{profile}'. Known: #{PROFILES.keys.join(', ')}" unless PROFILES.key?(profile) pm = pkg_manager raise 'No supported package manager found (apt / dnf / pacman / brew / port).' if pm[:key] == :unknown prof = PROFILES[profile] gems = Array(prof[:gems]) # Drop setup-managed gems whose upstream required_ruby_version excludes # THIS ruby (e.g. meshtastic >= 4.0 on a distro ruby 3.3) — otherwise # `gem install` in the loop below fails and takes the whole profile with it. gems = gems.reject do |g| floor = NATIVE_GEMS.dig(g, :min_ruby) skip = floor && Gem::Version.new(RUBY_VERSION) < Gem::Version.new(floor) io.puts " \e[33mskip\e[0m #{g} — requires ruby >= #{floor} (running #{RUBY_VERSION})" if skip skip end bins = Array(prof[:bins]) os_pkgs = [] gems.each { |g| os_pkgs.concat(Array(NATIVE_GEMS.dig(g, pm[:key]))) } bins.each { |b| os_pkgs.concat(Array(TOOLCHAIN.dig(b, pm[:key]))) } os_pkgs = os_pkgs.reject(&:empty?).uniq io.puts "Profile : #{profile} — #{prof[:desc]}" io.puts "Pkg mgr : #{pm[:key]}" io.puts "OS pkgs : #{os_pkgs.empty? ? '(none)' : os_pkgs.join(' ')}" io.puts "Ruby exts : #{gems.empty? ? '(none)' : gems.join(' ')}" io.puts cmds = [] cmds << "#{pm[:install]} #{os_pkgs.map { |p| Shellwords.escape(p) }.join(' ')}" unless os_pkgs.empty? unless gems.empty? broken = gems.reject { |g| gem_loadable?(name: g) } cmds << "gem pristine #{broken.map { |g| Shellwords.escape(g) }.join(' ')}" unless broken.empty? cmds << "gem install #{broken.map { |g| Shellwords.escape(g) }.join(' ')}" unless broken.empty? end if cmds.empty? io.puts "Nothing to do — profile '#{profile}' is already satisfied." return { profile: profile, ran: [], skipped: true } end io.puts 'Will run:' cmds.each { |c| io.puts " $ #{c}" } io.puts unless yes || dry_run io.print 'Proceed? [y/N] ' ans = $stdin.gets.to_s.strip.downcase return { profile: profile, ran: [], aborted: true } unless %w[y yes].include?(ans) end ran = [] cmds.each do |c| io.puts "→ #{c}" if dry_run ran << { cmd: c, exit: 0, dry_run: true } else ok = system(c) ran << { cmd: c, exit: $CHILD_STATUS && $CHILD_STATUS.exitstatus, ok: ok } io.puts " (exit #{ran.last[:exit]})" unless ok end end io.puts io.puts 'Re-checking…' io.puts result = check(io: io) { profile: profile, ran: ran, check: result } rescue StandardError => e raise e end |
.help ⇒ Object
Display Usage for this Module
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
# File 'lib/pwn/setup.rb', line 586 public_class_method def self.help puts "USAGE: # Read-only doctor — which PWN capabilities are usable on this host? #{self}.check # Install OS headers + rebuild native gems for a capability profile. # profile ∈ #{PROFILES.keys.inspect} #{self}.deps( profile: 'optional - capability profile (default :full)', yes: 'optional - assume yes (non-interactive)', dry_run: 'optional - print commands only' ) # List capability profiles. #{self}.list_profiles # Detected package manager (:apt / :dnf / :pacman / :brew / :port). #{self}.pkg_manager # Data tables — versioned with the gem: #{self}::NATIVE_GEMS # native ext → OS headers → PWN:: constants #{self}::TOOLCHAIN # external bin → OS package → PWN:: constants #{self}::PROFILES # capability profile → gems + bins # From the shell: pwn setup # == check pwn setup --check pwn setup --deps # profile :full pwn setup --profile web pwn setup --profile sdr --yes pwn setup --list-profiles pwn setup --dry-run --profile net pwn setup --migrate # verify + upgrade ~/.pwn schema pwn setup --migrate --fix # also autofix incompatible files #{self}.authors " end |
.list_profiles(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.list_profiles( io: 'optional - IO to write to (default $stdout)' )
489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/pwn/setup.rb', line 489 public_class_method def self.list_profiles(opts = {}) io = opts[:io] || $stdout io.puts 'Available capability profiles (`pwn setup --profile <name>`):' io.puts PROFILES.each do |name, | io.puts " #{name.to_s.ljust(10)} #{[:desc]}" io.puts " #{''.ljust(10)} gems: #{[:gems].join(' ')}" unless [:gems].empty? io.puts " #{''.ljust(10)} bins: #{[:bins].join(' ')}" unless [:bins].empty? io.puts end PROFILES.keys rescue StandardError => e raise e end |
.migrate(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::Setup.migrate( fix: 'optional - also autofix incompatible ~/.pwn files (default false)', dry_run: 'optional - print what WOULD happen (default false)', yes: 'optional - alias for fix:true (CI-friendly)', io: 'optional - IO to write to (default $stdout)' )
Delegate to PWN::Migrate.run — verify every ~/.pwn state file is
compatible with THIS pwn release and (optionally) autofix it. A
timestamped backup of ~/.pwn is taken first. See PWN::Migrate.help.
516 517 518 519 520 521 522 523 524 |
# File 'lib/pwn/setup.rb', line 516 public_class_method def self.migrate(opts = {}) PWN::Migrate.run( fix: opts[:fix] || opts[:yes], dry_run: opts[:dry_run], io: opts[:io] || $stdout ) rescue StandardError => e raise e end |
.pkg_manager ⇒ Object
- Supported Method Parameters
PWN::Setup.pkg_manager
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/pwn/setup.rb', line 294 public_class_method def self.pkg_manager return @pkg_manager if defined?(@pkg_manager) && @pkg_manager # Drop the `sudo` prefix when we are already root (Docker / CI # containers, `sudo -i`, root shells) or when `sudo` is not # installed — otherwise `pwn setup --profile x --yes` dies with # `sh: sudo: not found` on stock debian:* / fedora:* images. root = begin Process.uid.zero? rescue StandardError false end sudo = root || !bin?(name: 'sudo') ? '' : 'sudo ' @pkg_manager = if bin?(name: 'apt-get') then { key: :apt, install: "#{sudo}apt-get install -y", sudo: !sudo.empty? } elsif bin?(name: 'dnf') then { key: :dnf, install: "#{sudo}dnf install -y", sudo: !sudo.empty? } elsif bin?(name: 'pacman') then { key: :pacman, install: "#{sudo}pacman -S --noconfirm", sudo: !sudo.empty? } elsif bin?(name: 'brew') then { key: :brew, install: 'brew install', sudo: false } elsif bin?(name: 'port') then { key: :port, install: "#{sudo}port -N install", sudo: !sudo.empty? } else { key: :unknown, install: nil, sudo: false } end end |