22 Commits

Author SHA1 Message Date
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
8 changed files with 197 additions and 77 deletions

22
ChangeLog.markdown Normal file
View File

@@ -0,0 +1,22 @@
# 3.0.0
* Renamed 'link' to 'symlink'
* Fixed conflict resolution when symlink destination exists and is a normal file
# 2.0.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

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, 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,17 @@ 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 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 +41,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

@@ -12,16 +12,22 @@ 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 mans home (directory) is his castle, so dont 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.3.0"
# 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 'spec/rake/spectask'

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'

64
homesick.gemspec Normal file
View File

@@ -0,0 +1,64 @@
# 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.3.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Joshua Nichols"]
s.date = %q{2010-04-01}
s.default_executable = %q{homesick}
s.description = %q{
A mans home (directory) is his castle, so dont 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",
".gitignore",
"ChangeLog.markdown",
"Gemfile",
"LICENSE",
"README.markdown",
"Rakefile",
"bin/homesick",
"homesick.gemspec",
"lib/homesick.rb",
"lib/homesick/actions.rb",
"lib/homesick/shell.rb",
"spec/homesick/homesick_spec.rb",
"spec/spec.opts",
"spec/spec_helper.rb"
]
s.homepage = %q{http://github.com/technicalpickles/homesick}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubygems_version = %q{1.3.6}
s.summary = %q{A man's home is his castle. Never leave your dotfiles behind.}
s.test_files = [
"spec/homesick/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::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
else
end
else
end
end

View File

@@ -1,65 +1,64 @@
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 empty_directory repos_dir, :verbose => false
inside repos_dir do inside repos_dir do
if uri =~ GIT_URI_PATTERN if uri =~ GITHUB_NAME_REPO_PATTERN
git_clone "git://github.com/#{$1}/#{$2}.git", :destination => "#{$1}_#{$2}"
else
git_clone uri git_clone uri
elsif uri =~ GITHUB_NAME_REPO_PATTERN
git_clone "git://github.com/#{$1}/#{$2}.git", "#{$1}_#{$2}"
end end
end end
end end
desc "link NAME", "Symlinks all dotfiles from the specified castle" desc "symlink NAME", "Symlinks all dotfiles from the specified castle"
def link(home) def symlink(home)
inside castle_dir(home) do unless castle_dir(home).exist?
files = Pathname.glob('.*')[2..-1] # skip . and .., ie the first two say_status :error, "Castle #{home} did not exist in #{repos_dir}", :red
files.each do |path|
absolute_path = path.expand_path
inside user_dir do exit(1)
adjusted_path = (user_dir + path).basename
symlink absolute_path, adjusted_path else
inside castle_dir(home) do
files = Pathname.glob('.*').reject{|a| [".",".."].include?(a.to_s)}
files.each do |path|
absolute_path = path.expand_path
inside user_dir do
adjusted_path = (user_dir + path).basename
ln_s absolute_path, adjusted_path
end
end end
end end
end end
end end
desc "list", "List cloned castles" desc "list", "List cloned castles"
def list def list
inside repos_dir do inside repos_dir do
Pathname.glob('*') do |home| Pathname.glob('*') do |home|
puts home inside home do
say_status home, `git config remote.origin.url`, :cyan
end
end end
end end
end end
@@ -82,43 +81,6 @@ class Homesick < Thor
protected protected
# 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)
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
def symlink(source, destination, config = {})
destination = Pathname.new(destination)
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 def user_dir
self.class.user_dir self.class.user_dir
end end

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

@@ -0,0 +1,46 @@
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)
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 ln_s(source, destination, config = {})
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 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 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