From cb916792d52c1ac2d90162aa3b76e46863ede665 Mon Sep 17 00:00:00 2001 From: Danny Ben Shitrit Date: Sun, 14 Sep 2025 08:17:12 +0000 Subject: [PATCH] - Refactor installer with new io / string builders --- .envrc.example | 3 ++ lib/completely.rb | 1 + lib/completely/commands/install.rb | 13 ++++---- lib/completely/installer.rb | 38 ++++++++++++++++++------ spec/completely/commands/install_spec.rb | 16 ++-------- spec/completely/installer_spec.rb | 20 ++++++++----- 6 files changed, 56 insertions(+), 35 deletions(-) diff --git a/.envrc.example b/.envrc.example index 6ccf214..3ba46bb 100644 --- a/.envrc.example +++ b/.envrc.example @@ -1,3 +1,6 @@ # for git-changelog (https://github.com/dannyben/git-changelog) export CHANGELOG_COMMIT_URL=https://github.com/bashly-framework/completely/commit/%h export CHANGELOG_COMPARE_URL=https://github.com/bashly-framework/completely/compare/%s + +# include the debug gem +export COMPLETELY_DEV=1 diff --git a/lib/completely.rb b/lib/completely.rb index 439cf34..54a3d95 100644 --- a/lib/completely.rb +++ b/lib/completely.rb @@ -4,3 +4,4 @@ require 'completely/completions' require 'completely/tester' require 'completely/installer' +require 'debug' if ENV['COMPLETELY_DEV'] diff --git a/lib/completely/commands/install.rb b/lib/completely/commands/install.rb index e8522d4..ae73e82 100644 --- a/lib/completely/commands/install.rb +++ b/lib/completely/commands/install.rb @@ -1,4 +1,3 @@ -require 'tempfile' require 'completely/commands/base' module Completely @@ -37,14 +36,18 @@ def run end def installer - @installer ||= Installer.new(program: args['PROGRAM'], script_path: script_path) + @installer ||= if stdin? + Installer.from_io program: + else + Installer.new program:, script_path: input_script_path + end end private - def script_path - @script_path ||= args['SCRIPT_PATH'] || 'completely.bash' - end + def program = args['PROGRAM'] + def stdin? = input_script_path == '-' + def input_script_path = args['SCRIPT_PATH'] || 'completely.bash' end end end diff --git a/lib/completely/installer.rb b/lib/completely/installer.rb index bcea0c6..ae80323 100644 --- a/lib/completely/installer.rb +++ b/lib/completely/installer.rb @@ -1,15 +1,39 @@ module Completely class Installer - attr_reader :program, :script_path + class << self + def from_io(program:, io: nil) + io ||= $stdin - def initialize(program:, script_path: nil) - if script_path == '-' - raise InstallError, 'Nothing is piped on stdin' if $stdin.tty? + raise InstallError, "io must respond to #read" unless io.respond_to?(:read) + raise InstallError, "io is closed" if io.respond_to?(:closed?) && io.closed? + + from_string program:, string: io.read + end + def from_string(program:, string:) + tempfile = create_tempfile script_path = tempfile.path - File.write script_path, $stdin.read + begin + File.write script_path, string + ensure + tempfile.close + end + + new program:, script_path: + end + + def create_tempfile + tempfile = Tempfile.new ["completely-", '.bash'] + tempfiles.push tempfile + tempfile end + def tempfiles = @tempfiles ||= [] + end + + attr_reader :program, :script_path + + def initialize(program:, script_path: nil) @program = program @script_path = script_path end @@ -67,10 +91,6 @@ def uninstall private - def tempfile - @tempfile ||= Tempfile.new('stdin-completely-') - end - def target_exist? File.exist? target_path end diff --git a/spec/completely/commands/install_spec.rb b/spec/completely/commands/install_spec.rb index 85ea371..014b476 100644 --- a/spec/completely/commands/install_spec.rb +++ b/spec/completely/commands/install_spec.rb @@ -37,7 +37,7 @@ context 'with PROGRAM - (stdin)' do it 'invokes the Installer using a temp file' do allow(subject).to receive(:installer).and_return(mock_installer) - allow($stdin).to receive_messages(tty?: false, read: 'dummy data') + allow($stdin).to receive_messages(read: 'dummy data') expect(mock_installer).to receive(:install) @@ -57,23 +57,13 @@ context 'with PROGRAM - --dry (stdin)' do it 'shows the command and does not install anything' do - allow($stdin).to receive_messages(tty?: false, read: 'dummy data') + allow($stdin).to receive_messages(read: 'dummy data') expect(mock_installer).not_to receive(:install) expect { subject.execute %w[install completely-test - --dry] } .to output_approval('cli/install/stdin-dry') - .except(/[^\s]*stdin-completely-[^\s]*/, '') - end - - context 'when stdin is empty' do - it 'raises InstallError' do - allow($stdin).to receive_messages(tty?: true, read: nil) - expect(mock_installer).not_to receive(:install) - - expect { subject.execute %w[install completely-test - --dry] } - .to raise_error(InstallError, 'Nothing is piped on stdin') - end + .except(/cp [^\s]*completely-[^\s]*/, 'cp ') end end diff --git a/spec/completely/installer_spec.rb b/spec/completely/installer_spec.rb index 7053656..9c78caf 100644 --- a/spec/completely/installer_spec.rb +++ b/spec/completely/installer_spec.rb @@ -13,17 +13,21 @@ %w[sudo rm -f] + targets end - describe '#initialize' do - context 'when script_path == "-"' do - let(:script_path) { '-' } + describe '::from_io' do + let(:io) { StringIO.new 'dummy data' } + subject { described_class.from_io program:, io: } - it 'reads the script from stdin and writes it to a temp file' do - allow($stdin).to receive_messages(tty?: false, read: 'dummy data') + it 'reads the script from io and writes it to a temp file' do + expect(File.read subject.script_path).to eq 'dummy data' + end + end - subject + describe '::from_string' do + let(:string) { 'dummy data' } + subject { described_class.from_string program:, string: } - expect(File.read subject.script_path).to eq 'dummy data' - end + it 'reads the script from io and writes it to a temp file' do + expect(File.read subject.script_path).to eq 'dummy data' end end