diff --git a/.rubocop.yml b/.rubocop.yml index 1b7634b..ebddc05 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -12,8 +12,5 @@ ClassLength: CyclomaticComplexity: Max: 7 -LineLength: - Max: 163 - MethodLength: - Max: 31 + Max: 36 diff --git a/lib/homesick.rb b/lib/homesick.rb index 628ef24..ec14750 100644 --- a/lib/homesick.rb +++ b/lib/homesick.rb @@ -32,14 +32,16 @@ class Homesick < Thor destination = nil if File.exist?(uri) uri = Pathname.new(uri).expand_path - fail "Castle already cloned to #{uri}" if uri.to_s.start_with?(repos_dir.to_s) + fail "Castle already cloned to #{uri}" \ + if uri.to_s.start_with?(repos_dir.to_s) destination = uri.basename ln_s uri, destination elsif uri =~ GITHUB_NAME_REPO_PATTERN destination = Pathname.new(uri).basename - git_clone "https://github.com/#{Regexp.last_match[1]}.git", destination: destination + git_clone "https://github.com/#{Regexp.last_match[1]}.git", + destination: destination elsif uri =~ /%r([^%r]*?)(\.git)?\Z/ || uri =~ /[^:]+:([^:]+)(\.git)?\Z/ destination = Pathname.new(Regexp.last_match[1]) git_clone uri @@ -57,21 +59,28 @@ class Homesick < Thor destination = Pathname.new(name) homesickrc = destination.join('.homesickrc').expand_path if homesickrc.exist? - proceed = shell.yes?("#{name} has a .homesickrc. Proceed with evaling it? (This could be destructive)") + proceed = shell.yes?("#{name} has a .homesickrc. Proceed with "\ + "evaling it? (This could be destructive)") if proceed shell.say_status 'eval', homesickrc inside destination do eval homesickrc.read, binding, homesickrc.expand_path.to_s end else - shell.say_status 'eval skip', "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue + shell.say_status 'eval skip', "not evaling #{homesickrc}, " \ + "#{destination} may need manual " \ + "configuration", :blue end end end end desc 'pull CASTLE', 'Update the specified castle' - method_option :all, type: :boolean, default: false, required: false, desc: 'Update all cloned castles' + method_option :all, + type: :boolean, + default: false, + required: false, + desc: 'Update all cloned castles' def pull(name = DEFAULT_CASTLE_NAME) if options[:all] inside_each_castle do |castle| @@ -111,7 +120,10 @@ class Homesick < Thor end desc 'symlink CASTLE', 'Symlinks all dotfiles from the specified castle' - method_option :force, default: false, desc: 'Overwrite existing conflicting symlinks without prompting.' + method_option :force, + default: false, + desc: 'Overwrite existing conflicting symlinks without ' \ + 'prompting.' def symlink(name = DEFAULT_CASTLE_NAME) check_castle_existance(name, 'symlink') @@ -151,7 +163,11 @@ class Homesick < Thor target.delete mv absolute_path, castle_path else - shell.say_status(:track, "#{target} already exists, and is more recent than #{file}. Run 'homesick SYMLINK CASTLE' to create symlinks.", :blue) unless options[:quiet] + shell.say_status(:track, + "#{target} already exists, and is more recent " \ + "than #{file}. Run 'homesick SYMLINK CASTLE' " \ + "to create symlinks.", + :blue) unless options[:quiet] end else mv absolute_path, castle_path @@ -168,13 +184,16 @@ class Homesick < Thor end # are we tracking something nested? Add the parent dir to the manifest - subdir_add(castle, relative_dir) unless relative_dir.eql?(Pathname.new('.')) + subdir_add(castle, relative_dir) \ + unless relative_dir.eql?(Pathname.new('.')) end desc 'list', 'List cloned castles' def list inside_each_castle do |castle| - say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan + say_status castle.relative_path_from(repos_dir).to_s, + `git config remote.origin.url`.chomp, + :cyan end end @@ -234,22 +253,32 @@ class Homesick < Thor def cd(castle = DEFAULT_CASTLE_NAME) check_castle_existance castle, 'cd' castle_dir = repos_dir.join(castle) - say_status "cd #{castle_dir.realpath}", "Opening a new shell in castle '#{castle}'. To return to the original one exit from the new shell.", :green + say_status "cd #{castle_dir.realpath}", + "Opening a new shell in castle '#{castle}'. To return to the " \ + "original one exit from the new shell.", + :green inside castle_dir do system(ENV['SHELL']) end end - desc 'open CASTLE', 'Open your default editor in the root of the given castle' + desc 'open CASTLE', + 'Open your default editor in the root of the given castle' def open(castle = DEFAULT_CASTLE_NAME) unless ENV['EDITOR'] - say_status :error, 'The $EDITOR environment variable must be set to use this command', :red + say_status :error, + 'The $EDITOR environment variable must be set to use ' \ + 'this command', + :red exit(1) end check_castle_existance castle, 'open' castle_dir = repos_dir.join(castle) - say_status "#{ENV['EDITOR']} #{castle_dir.realpath}", "Opening the root directory of castle '#{castle}' in editor '#{ENV['EDITOR']}'.", :green + say_status "#{ENV['EDITOR']} #{castle_dir.realpath}", + "Opening the root directory of castle '#{castle}' in editor " \ + "'#{ENV['EDITOR']}'.", + :green inside castle_dir do system(ENV['EDITOR']) end @@ -276,7 +305,10 @@ class Homesick < Thor def check_castle_existance(name, action) unless castle_dir(name).exist? - say_status :error, "Could not #{action} #{name}, expected #{castle_dir(name)} exist and contain dotfiles", :red + say_status :error, + "Could not #{action} #{name}, expected " \ + "#{castle_dir(name)} exist and contain dotfiles", + :red exit(1) end @@ -355,7 +387,9 @@ class Homesick < Thor def subdir_remove(castle, path) subdir_filepath = subdir_file(castle) if subdir_filepath.exist? - lines = IO.readlines(subdir_filepath).delete_if { |line| line == "#{path}\n" } + lines = IO.readlines(subdir_filepath).delete_if do |line| + line == "#{path}\n" + end File.open(subdir_filepath, 'w') { |manfile| manfile.puts lines } end @@ -394,7 +428,9 @@ class Homesick < Thor def each_file(castle, basedir, subdirs) absolute_basedir = Pathname.new(basedir).expand_path inside basedir do - files = Pathname.glob('{.*,*}').reject { |a| ['.', '..'].include?(a.to_s) } + files = Pathname.glob('{.*,*}').reject do + |a| ['.', '..'].include?(a.to_s) + end files.each do |path| absolute_path = path.expand_path castle_home = castle_dir(castle) diff --git a/lib/homesick/actions.rb b/lib/homesick/actions.rb index 3bfd4e2..775f932 100644 --- a/lib/homesick/actions.rb +++ b/lib/homesick/actions.rb @@ -7,14 +7,18 @@ class Homesick config ||= {} destination = config[:destination] || File.basename(repo, '.git') - destination = Pathname.new(destination) unless destination.kind_of?(Pathname) + destination = Pathname.new(destination) \ + unless destination.kind_of?(Pathname) FileUtils.mkdir_p destination.dirname if destination.directory? say_status :exist, destination.expand_path, :blue unless options[:quiet] else - say_status 'git clone', "#{repo} to #{destination.expand_path}", :green unless options[:quiet] - system "git clone -q --config push.default=upstream --recursive #{repo} #{destination}" unless options[:pretend] + say_status 'git clone', + "#{repo} to #{destination.expand_path}", + :green unless options[:quiet] + system "git clone -q --config push.default=upstream " \ + "--recursive #{repo} #{destination}" unless options[:pretend] end end @@ -50,7 +54,8 @@ class Homesick def git_submodule_update(config = {}) say_status 'git submodule', 'update', :green unless options[:quiet] - system 'git submodule --quiet update --init --recursive >/dev/null 2>&1' unless options[:pretend] + system 'git submodule --quiet update --init --recursive ' \ + '>/dev/null 2>&1' unless options[:pretend] end def git_pull(config = {}) @@ -94,7 +99,10 @@ class Homesick if destination.exist? say_status :conflict, "#{destination} exists", :red unless options[:quiet] - system "mv '#{source}' '#{destination}'" if (options[:force] || shell.file_collision(destination) { source }) && !options[:pretend] + system "mv '#{source}' '#{destination}'" \ + if (options[:force] || + shell.file_collision(destination) { source }) && + !options[:pretend] else # this needs some sort of message here. system "mv '#{source}' '#{destination}'" unless options[:pretend] @@ -151,9 +159,13 @@ class Homesick if destination.symlink? && destination.readlink == source say_status :identical, destination.expand_path, :blue unless options[:quiet] elsif destination.symlink? - say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red unless options[:quiet] + say_status :conflict, + "#{destination} exists and points to " \ + "#{destination.readlink}", + :red unless options[:quiet] - smart_system "ln -nsf '#{source}' '#{destination}'" if collision_accepted? + smart_system "ln -nsf '#{source}' '#{destination}'" \ + if collision_accepted? elsif destination.exist? say_status :conflict, "#{destination} exists", :red unless options[:quiet] @@ -162,7 +174,9 @@ class Homesick system "ln -sf '#{source}' '#{destination}'" unless options[:pretend] end else - say_status :symlink, "#{source.expand_path} to #{destination.expand_path}", :green unless options[:quiet] + say_status :symlink, + "#{source.expand_path} to #{destination.expand_path}", + :green unless options[:quiet] system "ln -s '#{source}' '#{destination}'" unless options[:pretend] end end diff --git a/spec/homesick_spec.rb b/spec/homesick_spec.rb index 6c68f16..35e8d59 100644 --- a/spec/homesick_spec.rb +++ b/spec/homesick_spec.rb @@ -18,7 +18,9 @@ describe 'homesick' do somewhere = create_construct local_repo = somewhere.directory('some_repo') local_repo.file('.homesickrc') do |file| - file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }" + file << "File.open(Dir.pwd + '/testing', 'w') do + |f| f.print 'testing' + end" end expect($stdout).to receive(:print) @@ -48,7 +50,8 @@ describe 'homesick' do it 'should raise an error' do homesick.should_not_receive(:git_clone) - expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i) + expect { homesick.clone @existing_dir.to_s }.to \ + raise_error(/already cloned/i) end end end @@ -56,33 +59,39 @@ describe 'homesick' do it 'should clone git repo like file:///path/to.git' do bare_repo = File.join(create_construct.to_s, 'dotfiles.git') system "git init --bare #{bare_repo} >/dev/null 2>&1" + # Capture stderr to suppress message about cloning an empty repo. Capture.stderr do homesick.clone "file://#{bare_repo}" end - File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')).should be_true + File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')) + .should be_true end it 'should clone git repo like git://host/path/to.git' do - homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git') + homesick.should_receive(:git_clone) + .with('git://github.com/technicalpickles/pickled-vim.git') homesick.clone 'git://github.com/technicalpickles/pickled-vim.git' end it 'should clone git repo like git@host:path/to.git' do - homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git') + homesick.should_receive(:git_clone) + .with('git@github.com:technicalpickles/pickled-vim.git') homesick.clone 'git@github.com:technicalpickles/pickled-vim.git' end it 'should clone git repo like http://host/path/to.git' do - homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git') + homesick.should_receive(:git_clone) + .with('http://github.com/technicalpickles/pickled-vim.git') homesick.clone 'http://github.com/technicalpickles/pickled-vim.git' end it 'should clone git repo like http://host/path/to' do - homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim') + homesick.should_receive(:git_clone) + .with('http://github.com/technicalpickles/pickled-vim') homesick.clone 'http://github.com/technicalpickles/pickled-vim' end @@ -93,13 +102,16 @@ describe 'homesick' do homesick.clone 'gitolite:pickled-vim.git' end - it 'should throw an exception when trying to clone a malformed uri like malformed' do + it 'should throw an exception when trying to clone a malformed uri like ' \ + 'malformed' do homesick.should_not_receive(:git_clone) expect { homesick.clone 'malformed' }.to raise_error end it 'should clone a github repo' do - homesick.should_receive(:git_clone).with('https://github.com/wfarr/dotfiles.git', destination: Pathname.new('dotfiles')) + homesick.should_receive(:git_clone) + .with('https://github.com/wfarr/dotfiles.git', + destination: Pathname.new('dotfiles')) homesick.clone 'wfarr/dotfiles' end @@ -116,7 +128,9 @@ describe 'homesick' do it 'executes the .homesickrc' do castle.file('.homesickrc') do |file| - file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }" + file << "File.open(Dir.pwd + '/testing', 'w') do + |f| f.print 'testing' + end" end expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval', kind_of(Pathname)) @@ -134,7 +148,9 @@ describe 'homesick' do it 'does not execute the .homesickrc' do castle.file('.homesickrc') do |file| - file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }" + file << "File.open(Dir.pwd + '/testing', 'w') do + |f| f.print 'testing' + end" end expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval skip', /not evaling.+/, :blue) @@ -219,7 +235,9 @@ describe 'homesick' do end context "with '.config' and '.config/someapp' in .homesick_subdir" do - let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) } + let(:castle) do + given_castle('glencairn', ['.config', '.config/someapp']) + end it 'can symlink under both of .config and .config/someapp' do config_dir = castle.directory('.config') config_dotfile = config_dir.file('.some_dotfile') @@ -231,9 +249,11 @@ describe 'homesick' do home_config_dir = home.join('.config') home_someapp_dir = home_config_dir.join('someapp') home_config_dir.symlink?.should be == false - home_config_dir.join('.some_dotfile').readlink.should be == config_dotfile + home_config_dir.join('.some_dotfile').readlink + .should be == config_dotfile home_someapp_dir.symlink?.should be == false - home_someapp_dir.join('.some_appfile').readlink.should == someapp_dotfile + home_someapp_dir.join('.some_appfile').readlink + .should == someapp_dotfile end end @@ -301,7 +321,9 @@ describe 'homesick' do end context "with '.config' and '.config/someapp' in .homesick_subdir" do - let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) } + let(:castle) do + given_castle('glencairn', ['.config', '.config/someapp']) + end it 'can unsymlink under both of .config and .config/someapp' do config_dir = castle.directory('.config') @@ -339,8 +361,14 @@ describe 'homesick' do given_castle('zomg') given_castle('wtf/zomg') - homesick.should_receive(:say_status).with('zomg', 'git://github.com/technicalpickles/zomg.git', :cyan) - homesick.should_receive(:say_status).with('wtf/zomg', 'git://github.com/technicalpickles/zomg.git', :cyan) + homesick.should_receive(:say_status) + .with('zomg', + 'git://github.com/technicalpickles/zomg.git', + :cyan) + homesick.should_receive(:say_status) + .with('wtf/zomg', + 'git://github.com/technicalpickles/zomg.git', + :cyan) homesick.list end @@ -350,7 +378,8 @@ describe 'homesick' do it 'should say "nothing to commit" when there are no changes' do given_castle('castle_repo') text = Capture.stdout { homesick.status('castle_repo') } - text.should =~ /nothing to commit \(create\/copy files and use "git add" to track\)$/ + text.should =~ Regexp.new('nothing to commit \(create\/copy files and ' \ + 'use "git add" to track\)$') end it 'should say "Changes to be committed" when there are changes' do @@ -358,7 +387,8 @@ describe 'homesick' do some_rc_file = home.file '.some_rc_file' homesick.track(some_rc_file.to_s, 'castle_repo') text = Capture.stdout { homesick.status('castle_repo') } - text.should =~ /Changes to be committed:.*new file:\s*home\/.some_rc_file/m + text.should =~ + /Changes to be committed:.*new file:\s*home\/.some_rc_file/m end end @@ -504,11 +534,15 @@ describe 'homesick' do given_castle('castle_repo') some_rc_file = home.file '.a_random_rc_file' homesick.track(some_rc_file.to_s, 'castle_repo') - text = Capture.stdout { homesick.commit('castle_repo', 'Test message') } + text = Capture.stdout do + homesick.commit('castle_repo', 'Test message') + end text.should =~ /^\[master \(root-commit\) \w+\] Test message/ end end + # Note that this is a test for the subdir_file related feature of track, + # not for the subdir_file method itself. describe 'subdir_file' do it 'should add the nested files parent to the subdir_file' do @@ -537,7 +571,8 @@ describe 'homesick' do end end - it 'should remove the parent of a tracked file from the subdir_file if the parent itself is tracked' do + it 'should remove the parent of a tracked file from the subdir_file ' \ + 'if the parent itself is tracked' do castle = given_castle('castle_repo') some_nested_file = home.file('some/nested/file.txt') @@ -555,7 +590,8 @@ describe 'homesick' do describe 'destroy' do it 'removes the symlink files' do - expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y') + expect_any_instance_of(Thor::Shell::Basic).to \ + receive(:yes?).and_return('y') given_castle('stronghold') some_rc_file = home.file '.some_rc_file' homesick.track(some_rc_file.to_s, 'stronghold') @@ -565,7 +601,8 @@ describe 'homesick' do end it 'deletes the cloned repository' do - expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y') + expect_any_instance_of(Thor::Shell::Basic).to \ + receive(:yes?).and_return('y') castle = given_castle('stronghold') some_rc_file = home.file '.some_rc_file' homesick.track(some_rc_file.to_s, 'stronghold') @@ -584,30 +621,47 @@ describe 'homesick' do end it 'returns an error message when the given castle does not exist' do - homesick.should_receive('say_status').once.with(:error, %r{Could not cd castle_repo, expected /tmp/construct_container.* exist and contain dotfiles}, :red) + homesick.should_receive('say_status').once + .with(:error, + Regexp.new('Could not cd castle_repo, expected ' \ + '/tmp/construct_container.* exist and contain dotfiles'), + :red) expect { homesick.cd 'castle_repo' }.to raise_error(SystemExit) end end describe 'open' do it 'opens the system default editor in the root of the given castle' do - ENV.stub(:[]).and_call_original # Make sure calls to ENV use default values for most things... - ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default value for 'EDITOR' just in case none is set + # Make sure calls to ENV use default values for most things... + ENV.stub(:[]).and_call_original + # Set a default value for 'EDITOR' just in case none is set + ENV.stub(:[]).with('EDITOR').and_return('vim') given_castle 'castle_repo' homesick.should_receive('inside').once.with(kind_of(Pathname)).and_yield homesick.should_receive('system').once.with('vim') Capture.stdout { homesick.open 'castle_repo' } end - it 'returns an error message when the $EDITOR environment variable is not set' do - ENV.stub(:[]).with('EDITOR').and_return(nil) # Set the default editor to make sure it fails. - homesick.should_receive('say_status').once.with(:error, 'The $EDITOR environment variable must be set to use this command', :red) + it 'returns an error message when the $EDITOR environment variable is ' \ + 'not set' do + # Set the default editor to make sure it fails. + ENV.stub(:[]).with('EDITOR').and_return(nil) + homesick.should_receive('say_status').once + .with(:error, + 'The $EDITOR environment variable must be set to use '\ + 'this command', + :red) expect { homesick.open 'castle_repo' }.to raise_error(SystemExit) end it 'returns an error message when the given castle does not exist' do - ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default just in case none is set - homesick.should_receive('say_status').once.with(:error, %r{Could not open castle_repo, expected /tmp/construct_container.* exist and contain dotfiles}, :red) + # Set a default just in case none is set + ENV.stub(:[]).with('EDITOR').and_return('vim') + homesick.should_receive('say_status').once + .with(:error, + Regexp.new('Could not open castle_repo, expected ' \ + '/tmp/construct_container.* exist and contain dotfiles'), + :red) expect { homesick.open 'castle_repo' }.to raise_error(SystemExit) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e594897..aed4112 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -24,7 +24,8 @@ RSpec.configure do |config| system 'git init >/dev/null 2>&1' system 'git config user.email "test@test.com"' system 'git config user.name "Test Name"' - system "git remote add origin git://github.com/technicalpickles/#{name}.git >/dev/null 2>&1" + system "git remote add origin " \ + "git://github.com/technicalpickles/#{name}.git >/dev/null 2>&1" if subdirs subdir_file = castle.join(Homesick::SUBDIR_FILENAME) subdirs.each do |subdir|