Skip to content

Instantly share code, notes, and snippets.

@maxim
Created September 12, 2009 07:25
Show Gist options
  • Save maxim/185746 to your computer and use it in GitHub Desktop.
Save maxim/185746 to your computer and use it in GitHub Desktop.
Rake tasks for managing git plugins with submodules.
# Rake tasks for managing git plugins with submodules.
#
# These tasks aim to make life simpler by automating all the boring work.
# What you get:
# - complete git integration (all you need to know is install, uninstall and update)
# - complete github integration (only use author name + plugin name)
# - rails plugin hooks (install.rb/uninstall.rb) are taken care of
#
# Available commands:
#
# rake git:submodules:init
# You don't have to run this, but someone cloning your repo does
#
# rake git:plugin:install maxim-shmacros
# Install github.com/maxim/shmacros plugin (you can also use / (ie maxim/shmacros))
#
# rake git:plugin:uninstall shmacros
# Uninstall shmacros plugin (no author name this time)
#
# rake git:plugin:update shmacros
# Update shmacros plugin
#
# rake git:plugins:update
# Update all plugins (notice plural plugins, this is to prevent accidents)
#
# rake git:plugins:list
# List all plugins and their commit hashes
namespace :git do
namespace :submodules do
desc "Initialize git submodules"
task :init do
system "git submodule init"
system "git submodule update"
end
end
namespace :plugin do
desc "Install rails plugin as git submodule"
task :install do
arg = ARGV[1].strip
if arg =~ /^git:\/\//
url_parts = arg.scan(/\/([^\/]+)/).flatten
user_nick = url_parts[1]
plugin_name = url_parts[2].split('.').first
else
user_nick, plugin_name = ARGV[1].split(/[\/-]/, 2).map(&:strip)
end
if [user_nick, plugin_name].any?(&:nil?)
puts "Plugin path is invalid."
exit(0)
end
origin = "git://github.com/#{user_nick}/#{plugin_name}.git"
destination = "vendor/plugins/#{plugin_name}"
(puts "Plugin #{plugin_name} is already installed."; exit(0)) if File.exist?(destination)
puts "Installing #{origin} into #{destination}."
system "git submodule add #{origin} #{destination}"
installed = plugin_installed?(plugin_name)
if installed && File.exist?(install_hook = "#{destination}/install.rb")
puts "Running #{install_hook}..."
Rake::Task[:environment].invoke
load install_hook
end
if !installed
puts "Installation failed."
exit(0)
end
Rake::Task['git:submodules:init'].invoke
puts "Plugin #{plugin_name} is successfully installed."
exit(0)
end
desc "Uninstall submodule'd plugin"
task :uninstall do
plugin_name = ARGV[1].strip
(puts "Plugin #{plugin_name} not found."; exit(0)) unless plugin_installed?(plugin_name)
submodule = plugins_list.find{|p| p[:name] == plugin_name}
if File.exist?(uninstall_hook = "#{submodule[:path]}/uninstall.rb")
puts "Running #{uninstall_hook}..."
Rake::Task[:environment].invoke
load uninstall_hook
end
lines = File.readlines(".gitmodules")
lines_count = 0
goner_lines = []
lines.each_slice(3) do |declaration|
if declaration[0].include?(submodule[:path]) &&
declaration[1].include?(submodule[:path]) &&
declaration[2].include?(submodule[:url])
goner_lines += [lines_count, lines_count+1, lines_count+2]
end
lines_count += 3
end
goner_lines.each{|num| lines[num] = nil}
lines.compact!
File.open(".gitmodules", "w") do |gitmodule|
gitmodule.write(lines.join)
end
puts "Removed declaration from .gitmodules."
lines = File.readlines(".git/config")
lines_count = 0
goner_lines = []
lines.each_cons(2) do |pair|
if pair.first.include?(submodule[:path]) && pair.last.include?(submodule[:url])
goner_lines += [lines_count, lines_count+1]
end
lines_count += 1
end
goner_lines.each{|num| lines[num] = nil}
lines.compact!
File.open(".git/config", "w") do |config_file|
config_file.write(lines.join)
end
puts "Removed declaration from .git/config."
system "git rm --cached #{submodule[:path]}"
system "rm -rf #{submodule[:path]}"
system "git add .gitmodules"
puts "Done!"
exit(0)
end
desc "Update a plugin"
task :update => "git:submodules:init" do
plugin_name = ARGV[1].strip
(puts "Plugin #{plugin_name} not found."; exit(0)) unless plugin_installed?(plugin_name)
submodule = plugins_list.find{|p| p[:name] == plugin_name}
puts "Updating #{submodule[:name]}..."
system "cd #{submodule[:path]} && git checkout master && git pull && cd ../.."
puts "Done!"
exit(0)
end
end
namespace :plugins do
desc "List all submodule'd plugins"
task :list do
puts "\n"
plugins_list.each do |plugin|
puts plugin[:name]
plugin.each_pair do |key, value|
puts " #{key}: #{value}" unless key == :name
end
puts "\n"
end
end
desc "Update all plugins"
task :update do
plugins_list.each do |plugin|
system "rake git:plugin:update #{plugin[:name]}"
end
end
end
def plugins_list
gitmodules_file = read_gitmodules_or_fail
lines = gitmodules_file.split("\n")
submodules = []
lines.each_slice(3) do |declaration|
next if declaration[1] =~ /vendor\/rails/
path = declaration[1].split('=')[1].strip
if (head = File.read("#{path}/.git/HEAD")).include?(':')
hash = File.read(path + "/.git/" + head.split(':')[1].strip).strip
else
hash = head
end
submodule = {
:path => path,
:name => path.split('/').last,
:url => declaration[2].split('=')[1].strip,
:hash => hash
}
submodules << submodule
end
submodules
end
def read_gitmodules_or_fail
if !File.exist?('.gitmodules') ||
(gitmodules_file = File.read('.gitmodules').strip).empty? ||
(gitmodules_file.split("\n").size < 6 && gitmodules_file =~ /vendor\/rails/)
puts "No plugins found."
exit(0)
end
gitmodules_file
end
def plugin_installed?(name)
plugins_list.find{|p| p[:name] == name}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment