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.
138 lines
3.3 KiB
Ruby
138 lines
3.3 KiB
Ruby
require 'thor'
|
|
|
|
class Homesick < Thor
|
|
include Thor::Actions
|
|
|
|
# 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
|
|
|
|
def initialize(args=[], options={}, config={})
|
|
super
|
|
self.shell = Homesick::Shell.new
|
|
end
|
|
|
|
GITHUB_NAME_REPO_PATTERN = /([A-Za-z_-]+)\/([A-Za-z_-]+)/
|
|
|
|
desc "clone URI", "Clone +uri+ as a castle for homesick"
|
|
def clone(uri)
|
|
empty_directory repos_dir, :verbose => false
|
|
inside repos_dir do
|
|
if uri =~ GITHUB_NAME_REPO_PATTERN
|
|
git_clone "git://github.com/#{$1}/#{$2}.git", "#{$1}_#{$2}"
|
|
else
|
|
git_clone uri
|
|
end
|
|
end
|
|
end
|
|
|
|
desc "link NAME", "Symlinks all dotfiles from the specified castle"
|
|
def link(home)
|
|
unless castle_dir(home).exist?
|
|
say_status :error, "Castle #{home} did not exist in #{repos_dir}", :red
|
|
|
|
exit(1)
|
|
|
|
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
|
|
|
|
symlink absolute_path, adjusted_path
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
desc "list", "List cloned castles"
|
|
def list
|
|
inside repos_dir do
|
|
Pathname.glob('*') do |home|
|
|
puts home
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
no_tasks do
|
|
# class method, so it's convenient to stub out during tests
|
|
def self.user_dir
|
|
@user_dir ||= Pathname.new('~').expand_path
|
|
end
|
|
|
|
def self.repos_dir
|
|
@repos_dir ||= Pathname.new('~/.homesick/repos').expand_path
|
|
end
|
|
|
|
def repos_dir
|
|
self.class.repos_dir
|
|
end
|
|
end
|
|
|
|
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
|
|
self.class.user_dir
|
|
end
|
|
|
|
def castle_dir(name)
|
|
repos_dir.join(name, 'home')
|
|
end
|
|
|
|
end
|