diff --git a/lib/homesick.rb b/lib/homesick.rb index 623aa49..9af78eb 100644 --- a/lib/homesick.rb +++ b/lib/homesick.rb @@ -91,7 +91,23 @@ class Homesick < Thor desc 'push CASTLE', 'Push the specified castle' def push(name = DEFAULT_CASTLE_NAME) push_castle name + end + desc 'unlink CASTLE', 'Unsymlinks all dotfiles from the specified castle' + def unlink(name = DEFAULT_CASTLE_NAME) + check_castle_existance(name, 'symlink') + + inside castle_dir(name) do + subdirs = subdirs(name) + + # unlink files + unsymlink_each(name, castle_dir(name), subdirs) + + # unlink files in subdirs + subdirs.each do |subdir| + unsymlink_each(name, subdir, subdirs) + end + end end desc 'symlink CASTLE', 'Symlinks all dotfiles from the specified castle' @@ -349,7 +365,7 @@ class Homesick < Thor first_p.mtime > second_p.mtime && !first_p.symlink? end - def symlink_each(castle, basedir, subdirs) + 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) } @@ -378,8 +394,21 @@ class Homesick < Thor relative_dir = absolute_basedir.relative_path_from(castle_home) home_path = home_dir.join(relative_dir).join(path) - ln_s absolute_path, home_path + + yield(absolute_path, home_path) end end end + + def unsymlink_each(castle, basedir, subdirs) + each_file(castle, basedir, subdirs) do |absolute_path, home_path| + rm_link home_path + end + end + + def symlink_each(castle, basedir, subdirs) + each_file(castle, basedir, subdirs) do |absolute_path, home_path| + ln_s absolute_path, home_path + end + end end diff --git a/lib/homesick/actions.rb b/lib/homesick/actions.rb index 03ba481..8ee4cbb 100644 --- a/lib/homesick/actions.rb +++ b/lib/homesick/actions.rb @@ -108,6 +108,17 @@ class Homesick system "rm -rf #{dir}" end + def rm_link(target) + target = Pathname.new(target) + + if target.symlink? + say_status :unlink, "#{target.expand_path}", :green unless options[:quiet] + FileUtils.rm_rf target + else + say_status :conflict, "#{target} is not a symlink", :red unless options[:quiet] + end + end + def ln_s(source, destination, config = {}) source = Pathname.new(source) destination = Pathname.new(destination) diff --git a/spec/homesick_spec.rb b/spec/homesick_spec.rb index fdea672..35932e3 100644 --- a/spec/homesick_spec.rb +++ b/spec/homesick_spec.rb @@ -189,6 +189,94 @@ describe 'homesick' do end end + describe 'unlink' do + let(:castle) { given_castle('glencairn') } + + it 'unlinks dotfiles in the home folder' do + dotfile = castle.file('.some_dotfile') + + homesick.symlink('glencairn') + homesick.unlink('glencairn') + + home.join('.some_dotfile').should_not exist + end + + it 'unlinks non-dotfiles from the home folder' do + dotfile = castle.file('bin') + + homesick.symlink('glencairn') + homesick.unlink('glencairn') + + home.join('bin').should_not exist + end + + context "with '.config' in .homesick_subdir" do + let(:castle) { given_castle('glencairn', ['.config']) } + + it 'can unlink sub directories' do + dotdir = castle.directory('.config') + dotfile = dotdir.file('.some_dotfile') + + homesick.symlink('glencairn') + homesick.unlink('glencairn') + + home_dotdir = home.join('.config') + home_dotdir.should exist + home_dotdir.join('.some_dotfile').should_not exist + end + end + + context "with '.config/appA' in .homesick_subdir" do + let(:castle) { given_castle('glencairn', ['.config/appA']) } + + it 'can unsymlink in nested sub directory' do + dotdir = castle.directory('.config').directory('appA') + dotfile = dotdir.file('.some_dotfile') + + homesick.symlink('glencairn') + homesick.unlink('glencairn') + + home_dotdir = home.join('.config').join('appA') + home_dotdir.should exist + home_dotdir.join('.some_dotfile').should_not exist + end + end + + context "with '.config' and '.config/someapp' in .homesick_subdir" do + let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) } + + it 'can unsymlink under both of .config and .config/someapp' do + config_dir = castle.directory('.config') + config_dotfile = config_dir.file('.some_dotfile') + someapp_dir = config_dir.directory('someapp') + someapp_dotfile = someapp_dir.file('.some_appfile') + + homesick.symlink('glencairn') + homesick.unlink('glencairn') + + home_config_dir = home.join('.config') + home_someapp_dir = home_config_dir.join('someapp') + home_config_dir.should exist + home_config_dir.join('.some_dotfile').should_not exist + home_someapp_dir.should exist + home_someapp_dir.join('.some_appfile').should_not exist + end + end + + context "when call with no castle name" do + let(:castle) { given_castle('dotfiles') } + + it 'using default castle name: "dotfiles"' do + dotfile = castle.file('.some_dotfile') + + homesick.symlink + homesick.unlink + + home.join('.some_dotfile').should_not exist + end + end + end + describe 'list' do it 'should say each castle in the castle directory' do given_castle('zomg')