74 Commits

Author SHA1 Message Date
Joshua Nichols
944988cb63 Regenerate gemspec for version 0.6.1 2010-11-13 14:05:24 -06:00
Joshua Nichols
6cd51597a3 Version bump to 0.6.1. 2010-11-13 13:59:34 -06:00
Joshua Nichols
6209080e0c Remove debug code. 2010-11-13 13:57:55 -06:00
Joshua Nichols
4a7e369c36 Add license. 2010-11-13 13:51:22 -06:00
Joshua Nichols
984da79210 Update to rspec 2.1.0. 2010-11-13 13:49:21 -06:00
Joshua Nichols
d0097eb5b6 Regenerated gemspec for version 0.6.0 2010-10-27 10:42:16 -04:00
Joshua Nichols
71303376ee Version bump to 0.6.0 2010-10-27 10:41:57 -04:00
Joshua Nichols
8dbd5a9b21 Spiked homesickrc support. Create a .homesickrc in a castle, and you will be prompted to eval it at clone. Runs in castle directory, and runs in the context of a Homesick instance 2010-10-27 10:09:24 -04:00
Joshua Nichols
f82dc905a2 Tweaks to track. Don't add & commit newly tracked file. Also fix tests to not be spitting out to stdout. 2010-10-27 08:38:30 -04:00
Joshua Nichols
bfbabc05d5 Removing copy-pasta 2010-10-27 08:38:30 -04:00
j.c.sackett
58767454b3 Added track command.
* Moves a specified file into the specified castle.
* Symlinks it into its original position.

Signed-off-by: Joshua Nichols <josh@technicalpickles.com>
2010-10-27 08:37:56 -04:00
Jon Sackett
4776651b27 Updated dependencies to use a version of jeweler that's available in rubygems. 2010-09-30 19:59:45 -04:00
Joshua Nichols
832eade857 Regenerated gemspec for version 0.5.4 2010-09-03 18:50:17 -04:00
Joshua Nichols
44ff9a8b4b Version bump to 0.5.4. 2010-09-03 18:50:05 -04:00
Joshua Nichols
3f26a74c71 Use || instead of or 2010-09-03 18:49:49 -04:00
Mathieu Sauve-Frankel
1041cb5160 make homesick symlink respect the force option
Signed-off-by: Joshua Nichols <josh@technicalpickles.com>
2010-09-03 18:49:25 -04:00
Joshua Nichols
04e7df1283 Regenerated gemspec for version 0.5.3 2010-08-19 02:31:06 -04:00
Joshua Nichols
fd5d92eb12 Added Gemfile.lock. 2010-08-19 02:31:00 -04:00
Joshua Nichols
46d2c72776 Get rid of bad multibyte characters. 2010-08-19 02:30:02 -04:00
Joshua Nichols
03f8765279 Version bump to 0.5.3. 2010-08-18 21:15:03 -04:00
Joshua Nichols
9f027ad164 Updates for latest bundler/jeweler. 2010-08-18 21:14:04 -04:00
Joshua Nichols
68bd47126a Merge remote branch 'jacobat/bundler-src' 2010-08-18 20:06:44 -04:00
Jacob Atzen
f9c351f941 Handle cloning of uri's based on ssh aliases like host:repos 2010-08-17 10:14:19 +02:00
Jacob Atzen
0440cd672d Don't try to clone uri's without a corresponding destination
The code throws the exception

  undefined method `join' for nil:NilClass

if destionation doesn't exist - so it's better to not call git_clone if
destination is not present.
2010-08-17 10:12:59 +02:00
Jacob Atzen
cb5a71213f Add source to Gemfile so bundler works 2010-08-17 09:56:50 +02:00
Joshua Nichols
546f078f99 Regenerated gemspec for version 0.5.2 2010-07-22 16:28:01 -04:00
Joshua Nichols
b71d75266c Version bump to 0.5.2. 2010-07-22 16:27:19 -04:00
Joshua Nichols
4a08ce4118 Added minimal thor version. 2010-07-22 16:27:05 -04:00
Joshua Nichols
c99039da0a Regenerated gemspec for version 0.5.1 2010-05-18 21:07:43 -04:00
Joshua Nichols
2dc948d933 Actually bump. 2010-05-18 21:07:25 -04:00
Joshua Nichols
18e44b663c Regenerated gemspec for version 0.4.1 2010-05-18 21:06:28 -04:00
Joshua Nichols
7f3fa403aa Version bump to 0.5.0. 2010-05-18 21:05:20 -04:00
Joshua Nichols
55d47ea4f5 Added link to rip in readme. 2010-05-18 20:57:56 -04:00
Joshua Nichols
3efee55f03 Fix listing of github-style cloned repos. 2010-05-18 20:42:45 -04:00
Joshua Nichols
f0c67f9653 Merge remote branch 'Sutto/master' 2010-05-18 20:25:53 -04:00
Darcy Laycock
53ed5697b8 Add note to readme re. github and symlink 2010-05-17 02:10:29 +08:00
Jorge Dias
94975b49e7 Changed update to pull to match git commands 2010-05-02 19:14:16 +02:00
Jorge Dias
95d22951b3 Implemented update action for castle 2010-04-09 19:02:43 +02:00
Joshua Nichols
c9399064e0 First pass at castle generator task. 2010-04-08 01:05:34 -04:00
Joshua Nichols
e1901b3a83 Regenerated gemspec for version 0.4.1 2010-04-02 00:54:20 -04:00
Joshua Nichols
cc39d30f09 Version bump to 0.4.1. 2010-04-02 00:54:04 -04:00
Joshua Nichols
a798f3c562 Add a better error message when a repo's home doesn't exist. 2010-04-02 00:53:17 -04:00
Joshua Nichols
02c3fda939 Regenerated gemspec for version 0.4.0 2010-04-01 22:02:40 -04:00
Joshua Nichols
958ab3e09e Version bump to 0.4.0 2010-04-01 22:02:21 -04:00
Joshua Nichols
c0797dd607 Cloning will now try to init and update git submodules, if they exist. 2010-04-01 21:59:15 -04:00
Joshua Nichols
00b6f9b390 Regenerated gemspec. 2010-04-01 21:23:07 -04:00
Joshua Nichols
9a22513ba4 Allow symlinking existing directories into repos, instead of cloning. 2010-04-01 21:19:25 -04:00
Joshua Nichols
5ac2a0739a Clone github repos into username/repo instead of username_repo, for more consistent use with symlink. 2010-04-01 21:08:36 -04:00
Joshua Nichols
923c634377 Misc cleanup 2010-04-01 21:04:06 -04:00
Joshua Nichols
0579f94430 Moving towards testing list more. 2010-04-01 20:59:24 -04:00
Joshua Nichols
c50464e366 Added more clone specs. 2010-04-01 20:17:47 -04:00
Joshua Nichols
c5f8563f71 Shuffled specs around. 2010-04-01 20:14:29 -04:00
Joshua Nichols
34ef4a4659 Regenerated gemspec for version 0.3.0 2010-04-01 00:15:54 -04:00
Joshua Nichols
4ccbd927fa Bumped to 0.3.0 2010-04-01 00:15:14 -04:00
Joshua Nichols
595c53370e Converted README to markdown. 2010-04-01 00:13:06 -04:00
Joshua Nichols
43facf1ec0 Renamed 'link' command to 'symlink' 2010-03-31 23:59:05 -04:00
Joshua Nichols
46b2cbfa3f Renamed symlink action to ln_s. 2010-03-31 23:57:18 -04:00
Joshua Nichols
cde7989e85 Fix conflict resolution when destination is a plain file (not a symlink). 2010-03-31 23:18:38 -04:00
Joshua Nichols
5db3048e71 Fix header in changelog 2010-03-19 00:35:10 -04:00
Joshua Nichols
3b3a8f8533 Regenerated gemspec for version 0.2.0 2010-03-19 00:34:21 -04:00
Joshua Nichols
412558f9ad Version bump 2010-03-19 00:34:08 -04:00
Joshua Nichols
73d890652e Fix quiet support 2010-03-19 00:33:59 -04:00
Joshua Nichols
ba84df0137 Cyan list instead of green. 2010-03-19 00:28:08 -04:00
Joshua Nichols
8be582a4cb Fixed cloning from github. 2010-03-18 23:45:34 -04:00
Joshua Nichols
b80b132a7a Adding in pretend options. 2010-03-18 23:38:45 -04:00
Joshua Nichols
bf66d91b1f Shuffled some stuff out of main homesick.rb 2010-03-18 23:30:18 -04:00
Joshua Nichols
ce0d9b9d02 Hai, pretty output. 2010-03-18 23:22:29 -04:00
Jacob Atzen
78e952c2e4 Fixed github name regex so specs run 2010-03-18 23:17:10 -04:00
Jacob Atzen
de0b14bbd6 Don't try to recognize git uri's
There's a bunch of different way to specify git uri's. Instead of trying
to recognize uri's let's just accept that the user knows, what he's doing.
2010-03-18 23:17:01 -04:00
Joshua Nichols
39c5142ee7 Regenerated gemspec for version 0.1.1 2010-03-17 11:46:09 -04:00
Joshua Nichols
a7d2dfebb3 Version bump to 0.1.1, and added ChangeLog. 2010-03-17 11:45:50 -04:00
Joshua Nichols
8add88a1dc Make sure castle dir exists before trying to link from it, preventing empty dirs from being created. 2010-03-17 11:38:03 -04:00
Martinos
c6a517e100 Correcting listing of dotfiles in home directory 2010-03-13 12:42:50 -05:00
Joshua Nichols
863567382a Fixed summary + description. 2010-03-10 15:23:08 -05:00
14 changed files with 543 additions and 126 deletions

1
.rspec Normal file
View File

@@ -0,0 +1 @@
--color

39
ChangeLog.markdown Normal file
View File

@@ -0,0 +1,39 @@
# 0.5.0
* Fixed listing of castles cloned using `homesick clone <github-user>/<github-repo>` (issue 3)
* Added `homesick pull <CASTLE>` for updating castles (thanks Jorge Dias!)
* Added a very basic `homesick generate <CASTLE>`
# 0.4.1
* Improved error message when a castle's home dir doesn't exist
# 0.4.0
* `homesick clone` can now take a path to a directory on the filesystem, which will be symlinked into place
* `homesick clone` now tries to `git submodule init` and `git submodule update` if git submodules are defined for a cloned repo
* Fixed missing dependency on thor and others
* Use HOME environment variable for where to store files, instead of assuming ~
# 0.3.0
* Renamed 'link' to 'symlink'
* Fixed conflict resolution when symlink destination exists and is a normal file
# 0.2.0
* Better support for recognizing git urls (thanks jacobat!)
* if it looks like a github user/repo, do that
* otherwise hand off to git clone
* Listing now displays in color, and show git remote
* Support pretend, force, and quiet modes
# 0.1.1
* Fixed trying to link against castles that don't exist
* Fixed linking, which tries to exclude . and .. from the list of files to
link (thanks Martinos!)
# 0.1.0
* Initial release

15
Gemfile
View File

@@ -1,16 +1,15 @@
source :gemcutter
# Add dependencies required to use your gem here. # Add dependencies required to use your gem here.
group :runtime do gem "thor", ">= 0.14.0"
#gem 'bundler', '>= 0.9.5'
gem "thor"
end
# Add dependencies to develop your gem here. # Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc. # Include everything needed to run rake, tests, features, etc.
group :development do group :development do
gem "rake" gem "rake"
gem "rspec", ">= 1.2.9" gem "rspec", "~> 2.1.0"
gem "bundler", ">= 0.9.5" gem "bundler", "~> 1.0.0"
gem "jeweler", ">= 1.4.0" gem "jeweler", ">= 1.5.0.pre6"
gem "rcov", ">= 0" gem "rcov", ">= 0"
gem "devver-construct" gem "test-construct"
end end

33
Gemfile.lock Normal file
View File

@@ -0,0 +1,33 @@
GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.2)
git (1.2.5)
jeweler (1.5.0.pre6)
bundler (~> 1.0.0)
git (>= 1.2.5)
rake
rake (0.8.7)
rcov (0.9.8)
rspec (2.1.0)
rspec-core (~> 2.1.0)
rspec-expectations (~> 2.1.0)
rspec-mocks (~> 2.1.0)
rspec-core (2.1.0)
rspec-expectations (2.1.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.1.0)
test-construct (1.2.0)
thor (0.14.0)
PLATFORMS
ruby
DEPENDENCIES
bundler (~> 1.0.0)
jeweler (>= 1.5.0.pre6)
rake
rcov
rspec (~> 2.1.0)
test-construct
thor (>= 0.14.0)

View File

@@ -1,14 +1,13 @@
= homesick # homesick
A man's home (directory) is his castle, so don't leave home with out it. 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. Homesick is sorta like [rip](http://github.com/defunkt/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.
We call a repository that is compatible with homesick to be a 'castle'. To act as a castle, a repository must be organized like so: We call a repository that is compatible with homesick to be a 'castle'. To act as a castle, a repository must be organized like so:
* Contains a 'home' directory * Contains a 'home' directory
* 'home' contains any number of files and directories that begin with '.' * 'home' contains any number of files and directories that begin with '.'
* Optionally has a README file
To get started, install homesick first: To get started, install homesick first:
@@ -24,13 +23,21 @@ Alternatively, if it's on github, there's a slightly shorter way:
With the castle cloned, you can now link its contents into your home dir: With the castle cloned, you can now link its contents into your home dir:
homesick link pickled-vim homesick symlink pickled-vim
If uou use the shorthand syntax for GitHub repositories in your clone, please note you will instead need to run:
homesick symlink technicalpickles/pickled-vim
If you're not sure what castles you have around, you can easily list them: If you're not sure what castles you have around, you can easily list them:
homesick list homesick list
== Note on Patches/Pull Requests Not sure what else homesick has up its sleeve? There's always the built in help:
homesick help
## Note on Patches/Pull Requests
* Fork the project. * Fork the project.
* Make your feature addition or bug fix. * Make your feature addition or bug fix.
@@ -38,6 +45,6 @@ If you're not sure what castles you have around, you can easily list them:
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
* Send me a pull request. Bonus points for topic branches. * Send me a pull request. Bonus points for topic branches.
== Copyright ## Copyright
Copyright (c) 2010 Joshua Nichols. See LICENSE for details. Copyright (c) 2010 Joshua Nichols. See LICENSE for details.

View File

@@ -1,7 +1,7 @@
require 'rubygems' require 'rubygems'
require 'bundler' require 'bundler'
begin begin
Bundler.setup(:runtime, :development) Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e rescue Bundler::BundlerError => e
$stderr.puts e.message $stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems" $stderr.puts "Run `bundle install` to install missing gems"
@@ -12,30 +12,36 @@ require 'rake'
require 'jeweler' require 'jeweler'
Jeweler::Tasks.new do |gem| Jeweler::Tasks.new do |gem|
gem.name = "homesick" gem.name = "homesick"
gem.summary = %Q{TODO: one-line summary of your gem} gem.summary = %Q{A man's home is his castle. Never leave your dotfiles behind.}
gem.description = %Q{TODO: longer description of your gem} gem.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.
}
gem.email = "josh@technicalpickles.com" gem.email = "josh@technicalpickles.com"
gem.homepage = "http://github.com/technicalpickles/homesick" gem.homepage = "http://github.com/technicalpickles/homesick"
gem.authors = ["Joshua Nichols"] gem.authors = ["Joshua Nichols"]
gem.version = "0.1.0" gem.version = "0.6.1"
gem.license = "MIT"
# Have dependencies? Add them to Gemfile # Have dependencies? Add them to Gemfile
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
end end
Jeweler::GemcutterTasks.new
require 'spec/rake/spectask' require 'rspec/core/rake_task'
Spec::Rake::SpecTask.new(:spec) do |spec| RSpec::Core::RakeTask.new(:spec) do |spec|
spec.libs << 'lib' << 'spec' spec.pattern = FileList['spec/**/*_spec.rb']
spec.spec_files = FileList['spec/**/*_spec.rb']
end end
Spec::Rake::SpecTask.new(:rcov) do |spec| RSpec::Core::RakeTask.new(:rcov) do |spec|
spec.libs << 'lib' << 'spec'
spec.pattern = 'spec/**/*_spec.rb' spec.pattern = 'spec/**/*_spec.rb'
spec.rcov = true spec.rcov = true
end end
task :default => :spec task :default => :spec
require 'rake/rdoctask' require 'rake/rdoctask'

View File

@@ -2,7 +2,7 @@
require 'pathname' require 'pathname'
lib = Pathname.new(__FILE__).dirname.join('..', 'lib').expand_path lib = Pathname.new(__FILE__).dirname.join('..', 'lib').expand_path
$LOAD_PATH.unshift.unshift lib.to_s unless $LOAD_PATH.include?(lib.to_s) $LOAD_PATH.unshift lib.to_s
require 'homesick' require 'homesick'

86
homesick.gemspec Normal file
View File

@@ -0,0 +1,86 @@
# Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{homesick}
s.version = "0.6.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Joshua Nichols"]
s.date = %q{2010-11-13}
s.default_executable = %q{homesick}
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}
s.executables = ["homesick"]
s.extra_rdoc_files = [
"ChangeLog.markdown",
"LICENSE",
"README.markdown"
]
s.files = [
".document",
".rspec",
"ChangeLog.markdown",
"Gemfile",
"Gemfile.lock",
"LICENSE",
"README.markdown",
"Rakefile",
"bin/homesick",
"homesick.gemspec",
"lib/homesick.rb",
"lib/homesick/actions.rb",
"lib/homesick/shell.rb",
"spec/homesick_spec.rb",
"spec/spec.opts",
"spec/spec_helper.rb"
]
s.homepage = %q{http://github.com/technicalpickles/homesick}
s.licenses = ["MIT"]
s.require_paths = ["lib"]
s.rubygems_version = %q{1.3.7}
s.summary = %q{A man's home is his castle. Never leave your dotfiles behind.}
s.test_files = [
"spec/homesick_spec.rb",
"spec/spec_helper.rb"
]
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<thor>, [">= 0.14.0"])
s.add_development_dependency(%q<rake>, [">= 0"])
s.add_development_dependency(%q<rspec>, ["~> 2.1.0"])
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
s.add_development_dependency(%q<jeweler>, [">= 1.5.0.pre6"])
s.add_development_dependency(%q<rcov>, [">= 0"])
s.add_development_dependency(%q<test-construct>, [">= 0"])
else
s.add_dependency(%q<thor>, [">= 0.14.0"])
s.add_dependency(%q<rake>, [">= 0"])
s.add_dependency(%q<rspec>, ["~> 2.1.0"])
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
s.add_dependency(%q<jeweler>, [">= 1.5.0.pre6"])
s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<test-construct>, [">= 0"])
end
else
s.add_dependency(%q<thor>, [">= 0.14.0"])
s.add_dependency(%q<rake>, [">= 0"])
s.add_dependency(%q<rspec>, ["~> 2.1.0"])
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
s.add_dependency(%q<jeweler>, [">= 1.5.0.pre6"])
s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<test-construct>, [">= 0"])
end
end

View File

@@ -1,130 +1,161 @@
require 'thor' require 'thor'
class Homesick < Thor class Homesick < Thor
autoload :Shell, 'homesick/shell'
autoload :Actions, 'homesick/actions'
include Thor::Actions include Thor::Actions
include Homesick::Actions
# Hack in support for diffing symlinks add_runtime_options!
class Shell < Thor::Shell::Color
def show_diff(destination, content) GITHUB_NAME_REPO_PATTERN = /\A([A-Za-z_-]+\/[A-Za-z_-]+)\Z/
destination = Pathname.new(destination)
if destination.symlink?
say "- #{destination.readlink}", :red, true
say "+ #{content.expand_path}", :green, true
else
super
end
end
end
def initialize(args=[], options={}, config={}) def initialize(args=[], options={}, config={})
super super
self.shell = Homesick::Shell.new self.shell = Homesick::Shell.new
end end
GIT_URI_PATTERN = /^git:\/\//
GITHUB_NAME_REPO_PATTERN = /([A-Za-z_-]+)\/([A-Za-z_-]+)/
desc "clone URI", "Clone +uri+ as a castle for homesick" desc "clone URI", "Clone +uri+ as a castle for homesick"
def clone(uri) def clone(uri)
empty_directory repos_dir, :verbose => false
inside repos_dir do inside repos_dir do
if uri =~ GIT_URI_PATTERN destination = nil
git_clone uri if File.exist?(uri)
destination = Pathname.new(uri).basename
ln_s uri, destination
elsif uri =~ GITHUB_NAME_REPO_PATTERN elsif uri =~ GITHUB_NAME_REPO_PATTERN
git_clone "git://github.com/#{$1}/#{$2}.git", "#{$1}_#{$2}" destination = Pathname.new($1)
git_clone "git://github.com/#{$1}.git", :destination => destination
elsif uri =~ /\/([^\/]*)(\.git)?\Z/
destination = Pathname.new($1)
git_clone uri
elsif uri =~ /[^:]+:([^:]+)(\.git)?\Z/
destination = Pathname.new($1)
git_clone uri
else
raise "Unknown URI format: #{uri}"
end
if destination.join('.gitmodules').exist?
inside destination do
git_submodule_init
git_submodule_update
end
end
homesickrc = destination.join('.homesickrc').expand_path
if homesickrc.exist?
proceed = shell.yes?("#{uri} 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
end
else
shell.say_status "eval skip", "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue
end
end end
end end
end end
desc "link NAME", "Symlinks all dotfiles from the specified castle" desc "pull NAME", "Update the specified castle"
def link(home) def pull(name)
inside castle_dir(home) do check_castle_existance(name, "pull")
files = Pathname.glob('.*')[2..-1] # skip . and .., ie the first two
inside repos_dir.join(name) do
git_pull
git_submodule_init
git_submodule_update
end
end
desc "symlink NAME", "Symlinks all dotfiles from the specified castle"
def symlink(name)
check_castle_existance(name, "symlink")
inside castle_dir(name) do
files = Pathname.glob('.*').reject{|a| [".",".."].include?(a.to_s)}
files.each do |path| files.each do |path|
absolute_path = path.expand_path absolute_path = path.expand_path
inside user_dir do inside home_dir do
adjusted_path = (user_dir + path).basename adjusted_path = (home_dir + path).basename
symlink absolute_path, adjusted_path ln_s absolute_path, adjusted_path
end end
end end
end end
end end
desc "track FILE CASTLE", "add a file to a castle"
def track(file, castle)
castle = Pathname.new(castle)
file = Pathname.new(file)
check_castle_existance(castle, 'track')
absolute_path = file.expand_path
castle_path = castle_dir(castle)
mv absolute_path, castle_path
inside home_dir do
absolute_path = castle_dir(castle) + file.basename
home_path = home_dir + file
ln_s absolute_path, home_path
end
end
desc "list", "List cloned castles" desc "list", "List cloned castles"
def list def list
inside repos_dir do Pathname.glob("#{repos_dir}/**/*/.git") do |git_dir|
Pathname.glob('*') do |home| castle = git_dir.dirname
puts home Dir.chdir castle do # so we can call git config from the right contxt
say_status castle.relative_path_from(repos_dir), `git config remote.origin.url`.chomp, :cyan
end end
end end
end end
desc "generate PATH", "generate a homesick-ready git repo at PATH"
def generate(castle)
castle = Pathname.new(castle).expand_path
no_tasks do github_user = `git config github.user`.chomp
# class method, so it's convenient to stub out during tests github_user = nil if github_user == ""
def self.user_dir github_repo = castle.basename
@user_dir ||= Pathname.new('~').expand_path
end
def self.repos_dir empty_directory castle
@repos_dir ||= Pathname.new('~/.homesick/repos').expand_path inside castle do
end git_init
if github_user
url = "git@github.com:#{github_user}/#{github_repo}.git"
git_remote_add 'origin', url
end
def repos_dir empty_directory "home"
self.class.repos_dir
end end
end end
protected protected
# TODO move this to be more like thor's template, empty_directory, etc def home_dir
def git_clone(repo, config = {}) @home_dir ||= Pathname.new(ENV['HOME'] || '~').expand_path
config ||= {}
destination = config[:destination] || begin
repo =~ /([^\/]+)\.git$/
$1
end
destination = Pathname.new(destination) unless destination.kind_of?(Pathname)
if ! destination.directory?
say_status 'git clone', "#{repo} to #{destination.expand_path}", :green if config.fetch(:verbose, true)
system "git clone #{repo} #{destination}" unless options[:pretend]
else
say_status :exist, destination.expand_path, :blue
end
end end
def symlink(source, destination, config = {}) def repos_dir
destination = Pathname.new(destination) @repos_dir ||= home_dir.join('.homesick', 'repos').expand_path
if destination.symlink?
if destination.readlink == source
say_status :identical, destination.expand_path, :blue
else
say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red
if shell.file_collision(destination) { source }
system "ln -sf #{source} #{destination}"
end
end
else
say_status :symlink, "#{source.expand_path} to #{destination.expand_path}", :green
system "ln -s #{source} #{destination}"
end
end
def user_dir
self.class.user_dir
end end
def castle_dir(name) def castle_dir(name)
repos_dir.join(name, 'home') repos_dir.join(name, 'home')
end end
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
exit(1)
end
end
end end

104
lib/homesick/actions.rb Normal file
View File

@@ -0,0 +1,104 @@
class Homesick
module Actions
# TODO move this to be more like thor's template, empty_directory, etc
def git_clone(repo, config = {})
config ||= {}
destination = config[:destination] || begin
repo =~ /([^\/]+)\.git$/
$1
end
destination = Pathname.new(destination) unless destination.kind_of?(Pathname)
FileUtils.mkdir_p destination.dirname
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]
else
say_status :exist, destination.expand_path, :blue unless options[:quiet]
end
end
def git_init(path = ".")
path = Pathname.new(path)
inside path do
unless path.join('.git').exist?
say_status 'git init', '' unless options[:quiet]
system "git init >/dev/null" unless options[:pretend]
else
say_status 'git init', 'already initialized', :blue unless options[:quiet]
end
end
end
def git_remote_add(name, url)
existing_remote = `git config remote.#{name}.url`.chomp
existing_remote = nil if existing_remote == ''
unless existing_remote
say_status 'git remote', "add #{name} #{url}" unless options[:quiet]
system "git remote add #{name} #{url}" unless options[:pretend]
else
say_status 'git remote', "#{name} already exists", :blue unless options[:quiet]
end
end
def git_submodule_init(config = {})
say_status 'git submodule', 'init', :green unless options[:quiet]
system "git submodule --quiet init" unless options[:pretend]
end
def git_submodule_update(config = {})
say_status 'git submodule', 'update', :green unless options[:quiet]
system "git submodule --quiet update >/dev/null 2>&1" unless options[:pretend]
end
def git_pull(config = {})
say_status 'git pull', '', :green unless options[:quiet]
system "git pull --quiet" unless options[:pretend]
end
def mv(source, destination, config = {})
source = Pathname.new(source)
destination = Pathname.new(destination + source.basename)
if destination.exist?
say_status :conflict, "#{destination} exists", :red unless options[:quiet]
if options[:force] || shell.file_collision(destination) { source }
system "mv #{source} #{destination}" unless options[:pretend]
end
else
# this needs some sort of message here.
system "mv #{source} #{destination}" unless options[:pretend]
end
end
def ln_s(source, destination, config = {})
source = Pathname.new(source)
destination = Pathname.new(destination)
if destination.symlink?
if destination.readlink == source
say_status :identical, destination.expand_path, :blue unless options[:quiet]
else
say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red unless options[:quiet]
if options[:force] || shell.file_collision(destination) { source }
system "ln -sf #{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 "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]
end
end
end
end

17
lib/homesick/shell.rb Normal file
View File

@@ -0,0 +1,17 @@
class Homesick
# Hack in support for diffing symlinks
class Shell < Thor::Shell::Color
def show_diff(destination, content)
destination = Pathname.new(destination)
if destination.symlink?
say "- #{destination.readlink}", :red, true
say "+ #{content.expand_path}", :green, true
else
super
end
end
end
end

View File

@@ -1,19 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "Homesick" do
before do
@homesick = Homesick.new
end
it "should clone any git repo" do
@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 a github repo" do
@homesick.should_receive(:git_clone).with('git://github.com/wfarr/dotfiles.git', 'wfarr_dotfiles')
@homesick.clone "wfarr/dotfiles"
end
end

113
spec/homesick_spec.rb Normal file
View File

@@ -0,0 +1,113 @@
require 'spec_helper'
describe Homesick do
before do
@homesick = Homesick.new
end
describe "clone" do
it "should symlink existing directories" do
somewhere = create_construct
somewhere.directory('wtf')
wtf = somewhere + 'wtf'
@homesick.should_receive(:ln_s).with(wtf.to_s, wtf.basename)
@homesick.clone wtf.to_s
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.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.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.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.clone 'http://github.com/technicalpickles/pickled-vim'
end
it "should clone git repo like host-alias:repos.git" do
@homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git')
@homesick.clone 'gitolite:pickled-vim.git'
end
it "should not try to clone a malformed uri like malformed" do
@homesick.should_not_receive(:git_clone)
@homesick.clone 'malformed' rescue nil
end
it "should throw an exception when trying to clone a malformed uri like malformed" do
lambda {
@homesick.clone 'malformed'
}.should raise_error
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.clone "wfarr/dotfiles"
end
end
describe "list" do
# FIXME only passes in isolation. need to setup data a bit better
xit "should say each castle in the castle directory" do
@user_dir.directory '.homesick/repos' do |repos_dir|
repos_dir.directory 'zomg' do |zomg|
Dir.chdir do
system "git init >/dev/null 2>&1"
system "git remote add origin git://github.com/technicalpickles/zomg.git >/dev/null 2>&1"
end
end
repos_dir.directory 'wtf/zomg' do |zomg|
Dir.chdir do
system "git init >/dev/null 2>&1"
system "git remote add origin git://github.com/technicalpickles/zomg.git >/dev/null 2>&1"
end
end
end
@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
end
describe "track" do
it "should move the tracked file into the castle" do
some_rc_file = @user_dir.file '.some_rc_file'
homesickrepo = @user_dir.directory('.homesick').directory('repos').directory('castle_repo')
castle_path = homesickrepo.directory 'home'
# There is some hideous thing going on with construct; rming the file I'm moving works on this test.
# Otherwise when track ln_s's it back out, it sees a conflict. Its as if file operations don't
# actually effect this thing, or something.
system "rm #{some_rc_file.to_s}"
Dir.chdir homesickrepo do
system "git init >/dev/null 2>&1"
end
@homesick.should_receive(:mv).with(some_rc_file, castle_path)
@homesick.should_receive(:ln_s).with(castle_path + some_rc_file.basename, some_rc_file)
@homesick.track(some_rc_file.to_s, 'castle_repo')
end
end
end

View File

@@ -1,16 +1,16 @@
$LOAD_PATH.unshift(File.dirname(__FILE__)) $LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'homesick' require 'homesick'
require 'spec' require 'rspec'
require 'spec/autorun' require 'rspec/autorun'
require 'construct' require 'construct'
Spec::Runner.configure do |config| Rspec.configure do |config|
config.include Construct::Helpers config.include Construct::Helpers
config.before do config.before do
@user_dir = create_construct @user_dir = create_construct
Homesick.stub!(:user_dir).and_return(@user_dir) ENV['HOME'] = @user_dir.to_s
end end
config.after do config.after do