Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
093db8bdac | ||
|
|
04602efd6e | ||
|
|
3265de0c1d | ||
|
|
e4a428e0c5 | ||
|
|
6cc28450a4 | ||
|
|
a0c7fbacb7 | ||
|
|
b750094934 | ||
|
|
d953a964cd | ||
|
|
aa95ffac82 | ||
|
|
9c345828b0 | ||
|
|
59c137c653 | ||
|
|
3d405542af | ||
|
|
88ff4b85ce | ||
|
|
461ac5f226 | ||
|
|
a7d2d0a3f3 | ||
|
|
191ce11d8e | ||
|
|
0d28a3ef9b | ||
|
|
ac34249afe | ||
|
|
d1f87be435 | ||
|
|
cbb6117d69 | ||
|
|
334a1db262 | ||
|
|
e3bee69b27 | ||
|
|
0ff5325e3e | ||
|
|
40efb2f58a | ||
|
|
4b20c7224e | ||
|
|
8e06beced6 | ||
|
|
b043f2a5ed | ||
|
|
3d59bc7a97 | ||
|
|
75dcad8ea4 | ||
|
|
4b38eb848f | ||
|
|
bfce04e63c | ||
|
|
846c5c202b | ||
|
|
600811ff01 | ||
|
|
26ce289e9b | ||
|
|
92dc611bb1 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -45,3 +45,4 @@ pkg
|
||||
*.iml
|
||||
|
||||
Gemfile.lock
|
||||
vendor/
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
# 0.9.4
|
||||
* Use https protocol instead of git protocol
|
||||
* Introduce new commands
|
||||
* `homesick unlink`
|
||||
* `homesick rc`
|
||||
|
||||
# 0.9.3
|
||||
* Add recursive option to `homesick clone`
|
||||
|
||||
# 0.9.2
|
||||
* Set "dotfiles" as default castle name
|
||||
* Introduce new commands
|
||||
|
||||
@@ -31,6 +31,10 @@ If you use the shorthand syntax for GitHub repositories in your clone, please no
|
||||
|
||||
homesick symlink technicalpickles/pickled-vim
|
||||
|
||||
You can remove symlinks anytime when you don't need them anymore
|
||||
|
||||
homesick unlink pickled-vim
|
||||
|
||||
If you're not sure what castles you have around, you can easily list them:
|
||||
|
||||
homesick list
|
||||
|
||||
2
Rakefile
2
Rakefile
@@ -22,7 +22,7 @@ Jeweler::Tasks.new do |gem|
|
||||
gem.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
|
||||
gem.homepage = "http://github.com/technicalpickles/homesick"
|
||||
gem.authors = ["Joshua Nichols", "Yusuke Murata"]
|
||||
gem.version = "0.9.2"
|
||||
gem.version = "0.9.6"
|
||||
gem.license = "MIT"
|
||||
# Have dependencies? Add them to Gemfile
|
||||
|
||||
|
||||
@@ -4,20 +4,15 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{homesick}
|
||||
s.version = "0.9.2"
|
||||
s.name = "homesick"
|
||||
s.version = "0.9.6"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = [%q{Joshua Nichols}, %q{Yusuke Murata}]
|
||||
s.date = %q{2013-06-27}
|
||||
s.description = %q{
|
||||
A man's home (directory) is his castle, so don't leave home with out it.
|
||||
|
||||
Homesick is sorta like rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place with a single command.
|
||||
|
||||
}
|
||||
s.email = [%q{josh@technicalpickles.com}, %q{info@muratayusuke.com}]
|
||||
s.executables = [%q{homesick}]
|
||||
s.authors = ["Joshua Nichols", "Yusuke Murata"]
|
||||
s.date = "2013-10-18"
|
||||
s.description = "\n A man's home (directory) is his castle, so don't leave home with out it.\n\n Homesick is sorta like rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place with a single command. \n\n "
|
||||
s.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
|
||||
s.executables = ["homesick"]
|
||||
s.extra_rdoc_files = [
|
||||
"ChangeLog.markdown",
|
||||
"LICENSE",
|
||||
@@ -41,11 +36,11 @@ Gem::Specification.new do |s|
|
||||
"spec/spec.opts",
|
||||
"spec/spec_helper.rb"
|
||||
]
|
||||
s.homepage = %q{http://github.com/technicalpickles/homesick}
|
||||
s.licenses = [%q{MIT}]
|
||||
s.require_paths = [%q{lib}]
|
||||
s.rubygems_version = %q{1.8.5}
|
||||
s.summary = %q{A man's home is his castle. Never leave your dotfiles behind.}
|
||||
s.homepage = "http://github.com/technicalpickles/homesick"
|
||||
s.licenses = ["MIT"]
|
||||
s.require_paths = ["lib"]
|
||||
s.rubygems_version = "1.8.23"
|
||||
s.summary = "A man's home is his castle. Never leave your dotfiles behind."
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
s.specification_version = 3
|
||||
@@ -58,6 +53,7 @@ Gem::Specification.new do |s|
|
||||
s.add_development_dependency(%q<rcov>, [">= 0"])
|
||||
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
||||
s.add_development_dependency(%q<test-construct>, [">= 0"])
|
||||
s.add_development_dependency(%q<rubocop>, [">= 0"])
|
||||
else
|
||||
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
||||
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
||||
@@ -66,6 +62,7 @@ Gem::Specification.new do |s|
|
||||
s.add_dependency(%q<rcov>, [">= 0"])
|
||||
s.add_dependency(%q<simplecov>, [">= 0"])
|
||||
s.add_dependency(%q<test-construct>, [">= 0"])
|
||||
s.add_dependency(%q<rubocop>, [">= 0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
||||
@@ -75,6 +72,7 @@ Gem::Specification.new do |s|
|
||||
s.add_dependency(%q<rcov>, [">= 0"])
|
||||
s.add_dependency(%q<simplecov>, [">= 0"])
|
||||
s.add_dependency(%q<test-construct>, [">= 0"])
|
||||
s.add_dependency(%q<rubocop>, [">= 0"])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class Homesick < Thor
|
||||
|
||||
add_runtime_options!
|
||||
|
||||
GITHUB_NAME_REPO_PATTERN = /\A([A-Za-z_-]+\/[A-Za-z_-]+)\Z/
|
||||
GITHUB_NAME_REPO_PATTERN = /\A([A-Za-z0-9_-]+\/[A-Za-z0-9_-]+)\Z/
|
||||
SUBDIR_FILENAME = '.homesick_subdir'
|
||||
|
||||
DEFAULT_CASTLE_NAME = 'dotfiles'
|
||||
@@ -33,8 +33,8 @@ class Homesick < Thor
|
||||
|
||||
ln_s uri, destination
|
||||
elsif uri =~ GITHUB_NAME_REPO_PATTERN
|
||||
destination = Pathname.new($1)
|
||||
git_clone "git://github.com/#{$1}.git", :destination => destination
|
||||
destination = Pathname.new(uri).basename
|
||||
git_clone "https://github.com/#{$1}.git", :destination => destination
|
||||
elsif uri =~ /%r([^%r]*?)(\.git)?\Z/
|
||||
destination = Pathname.new($1)
|
||||
git_clone uri
|
||||
@@ -52,13 +52,21 @@ class Homesick < Thor
|
||||
end
|
||||
end
|
||||
|
||||
rc(destination)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'rc CASTLE', 'Run the .homesickrc for the specified castle'
|
||||
def rc(name = DEFAULT_CASTLE_NAME)
|
||||
inside repos_dir do
|
||||
destination = Pathname.new(name)
|
||||
homesickrc = destination.join('.homesickrc').expand_path
|
||||
if homesickrc.exist?
|
||||
proceed = shell.yes?("#{uri} 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
|
||||
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
|
||||
@@ -90,7 +98,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 +355,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 +384,21 @@ class Homesick < Thor
|
||||
|
||||
relative_dir = absolute_basedir.relative_path_from(castle_home)
|
||||
home_path = home_dir.join(relative_dir).join(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
|
||||
end
|
||||
|
||||
@@ -10,7 +10,7 @@ class Homesick
|
||||
|
||||
if ! destination.directory?
|
||||
say_status 'git clone', "#{repo} to #{destination.expand_path}", :green unless options[:quiet]
|
||||
system "git clone -q #{repo} #{destination}" unless options[:pretend]
|
||||
system "git clone -q --recursive #{repo} #{destination}" unless options[:pretend]
|
||||
else
|
||||
say_status :exist, destination.expand_path, :blue unless options[:quiet]
|
||||
end
|
||||
@@ -68,7 +68,7 @@ class Homesick
|
||||
|
||||
def git_add(file, config = {})
|
||||
say_status 'git add file', '', :green unless options[:quiet]
|
||||
system "git add #{file}" unless options[:pretend]
|
||||
system "git add '#{file}'" unless options[:pretend]
|
||||
end
|
||||
|
||||
def git_status(config = {})
|
||||
@@ -89,11 +89,22 @@ class Homesick
|
||||
say_status :conflict, "#{destination} exists", :red unless options[:quiet]
|
||||
|
||||
if options[:force] || shell.file_collision(destination) { source }
|
||||
system "mv #{source} #{destination}" unless options[:pretend]
|
||||
system "mv '#{source}' '#{destination}'" unless options[:pretend]
|
||||
end
|
||||
else
|
||||
# this needs some sort of message here.
|
||||
system "mv #{source} #{destination}" unless options[:pretend]
|
||||
system "mv '#{source}' '#{destination}'" unless options[:pretend]
|
||||
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
|
||||
|
||||
@@ -109,19 +120,19 @@ class Homesick
|
||||
say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red unless options[:quiet]
|
||||
|
||||
if options[:force] || shell.file_collision(destination) { source }
|
||||
system "ln -nsf #{source} #{destination}" unless options[:pretend]
|
||||
system "ln -nsf '#{source}' '#{destination}'" unless options[:pretend]
|
||||
end
|
||||
end
|
||||
elsif destination.exist?
|
||||
say_status :conflict, "#{destination} exists", :red unless options[:quiet]
|
||||
|
||||
if options[:force] || shell.file_collision(destination) { source }
|
||||
system "rm -rf #{destination}" unless options[:pretend]
|
||||
system "ln -sf #{source} #{destination}" unless options[:pretend]
|
||||
system "rm -rf '#{destination}'" unless options[:pretend]
|
||||
system "ln -sf '#{source}' '#{destination}'" unless options[:pretend]
|
||||
end
|
||||
else
|
||||
say_status :symlink, "#{source.expand_path} to #{destination.expand_path}", :green unless options[:quiet]
|
||||
system "ln -s #{source} #{destination}" unless options[:pretend]
|
||||
system "ln -s '#{source}' '#{destination}'" unless options[:pretend]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,9 +8,25 @@ describe 'homesick' do
|
||||
|
||||
let(:homesick) { Homesick.new }
|
||||
|
||||
before { homesick.stub!(:repos_dir).and_return(castles) }
|
||||
before { homesick.stub(:repos_dir).and_return(castles) }
|
||||
|
||||
describe 'clone' do
|
||||
context 'has a .homesickrc' do
|
||||
it 'should run the .homesickrc' 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' }"
|
||||
end
|
||||
|
||||
expect($stdout).to receive(:print)
|
||||
expect($stdin).to receive(:gets).and_return('y')
|
||||
homesick.clone local_repo
|
||||
|
||||
castles.join('some_repo').join('testing').should exist
|
||||
end
|
||||
end
|
||||
|
||||
context 'of a file' do
|
||||
it 'should symlink existing directories' do
|
||||
somewhere = create_construct
|
||||
@@ -78,12 +94,50 @@ describe 'homesick' do
|
||||
end
|
||||
|
||||
it 'should clone a github repo' do
|
||||
homesick.should_receive(:git_clone).with('git://github.com/wfarr/dotfiles.git', :destination => Pathname.new('wfarr/dotfiles'))
|
||||
homesick.should_receive(:git_clone).with('https://github.com/wfarr/dotfiles.git', :destination => Pathname.new('dotfiles'))
|
||||
|
||||
homesick.clone 'wfarr/dotfiles'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'rc' do
|
||||
let(:castle) { given_castle('glencairn') }
|
||||
|
||||
context 'when told to do so' do
|
||||
before do
|
||||
expect($stdout).to receive(:print)
|
||||
expect($stdin).to receive(:gets).and_return('y')
|
||||
end
|
||||
|
||||
it 'executes the .homesickrc' do
|
||||
castle.file('.homesickrc') do |file|
|
||||
file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
|
||||
end
|
||||
|
||||
homesick.rc castle
|
||||
|
||||
castle.join('testing').should exist
|
||||
end
|
||||
end
|
||||
|
||||
context 'when told not to do so' do
|
||||
before do
|
||||
expect($stdout).to receive(:print)
|
||||
expect($stdin).to receive(:gets).and_return('n')
|
||||
end
|
||||
|
||||
it 'does not execute the .homesickrc' do
|
||||
castle.file('.homesickrc') do |file|
|
||||
file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
|
||||
end
|
||||
|
||||
homesick.rc castle
|
||||
|
||||
castle.join('testing').should_not exist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'symlink' do
|
||||
let(:castle) { given_castle('glencairn') }
|
||||
|
||||
@@ -188,6 +242,91 @@ describe 'homesick' do
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unlink' do
|
||||
let(:castle) { given_castle('glencairn') }
|
||||
|
||||
it 'unlinks dotfiles in the home folder' do
|
||||
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
|
||||
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
|
||||
castle.directory('.config').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
|
||||
castle.directory('.config').directory('appA').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_dir.file('.some_dotfile')
|
||||
config_dir.directory('someapp').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
|
||||
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')
|
||||
@@ -258,6 +397,19 @@ describe 'homesick' do
|
||||
some_rc_file.readlink.should == tracked_file
|
||||
end
|
||||
|
||||
it 'should handle files with parens' do
|
||||
castle = given_castle('castle_repo')
|
||||
|
||||
some_rc_file = home.file 'Default (Linux).sublime-keymap'
|
||||
|
||||
homesick.track(some_rc_file.to_s, 'castle_repo')
|
||||
|
||||
tracked_file = castle.join('Default (Linux).sublime-keymap')
|
||||
tracked_file.should exist
|
||||
|
||||
some_rc_file.readlink.should == tracked_file
|
||||
end
|
||||
|
||||
it 'should track a file in nested folder structure' do
|
||||
castle = given_castle('castle_repo')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user