diff --git a/.gitignore b/.gitignore index e16687e..6fccad9 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,5 @@ pkg .idea/ *.iml -Gemfile.lock \ No newline at end of file +Gemfile.lock +vendor/ diff --git a/lib/homesick.rb b/lib/homesick.rb index 81b9a05..10f8e31 100644 --- a/lib/homesick.rb +++ b/lib/homesick.rb @@ -90,7 +90,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' @@ -331,7 +347,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) } @@ -360,8 +376,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 87918d7..e037e9e 100644 --- a/lib/homesick/actions.rb +++ b/lib/homesick/actions.rb @@ -97,6 +97,17 @@ class Homesick end 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 173897c..b5738a9 100644 --- a/spec/homesick_spec.rb +++ b/spec/homesick_spec.rb @@ -188,6 +188,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')