task/gemgem.rb in dm-is-reflective-1.3.1 vs task/gemgem.rb in dm-is-reflective-1.3.2
- old
+ new
@@ -1,109 +1,152 @@
-require 'pathname'
-
module Gemgem
class << self
- attr_accessor :dir, :spec
+ attr_accessor :dir, :spec, :submodules, :spec_create
end
module_function
+ def gem_tag ; "#{spec.name}-#{spec.version}" ; end
+ def gem_path ; "#{pkg_dir}/#{gem_tag}.gem" ; end
+ def spec_path ; "#{dir}/#{spec.name}.gemspec" ; end
+ def pkg_dir ; "#{dir}/pkg" ; end
+ def escaped_dir; @escaped_dir ||= Regexp.escape(dir); end
+
+ def init dir, options={}, &block
+ self.dir = dir
+ ENV['RUBYLIB'] = "#{dir}/lib:#{ENV['RUBYLIB']}"
+ ENV['PATH'] = "#{dir}/bin:#{ENV['PATH']}"
+ self.submodules = options[:submodules] || []
+ self.spec_create = block
+
+ $LOAD_PATH.unshift("#{dir}/lib", *submodules_libs)
+ end
+
def create
- yield(spec = Gem::Specification.new{ |s|
+ spec = Gem::Specification.new do |s|
s.authors = ['Lin Jen-Shin (godfat)']
s.email = ['godfat (XD) godfat.org']
s.description = description.join
s.summary = description.first
- s.license = readme['LICENSE'].sub(/.+\n\n/, '').lines.first.strip
+ s.license = license
- s.rubygems_version = Gem::VERSION
- s.date = Time.now.strftime('%Y-%m-%d')
- s.files = gem_files
- s.test_files = gem_files.grep(%r{^test/(.+?/)*test_.+?\.rb$})
- s.executables = Dir['bin/*'].map{ |f| File.basename(f) }
- s.require_paths = %w[lib]
- })
+ s.date = Time.now.strftime('%Y-%m-%d')
+ s.files = gem_files
+ s.test_files = test_files
+ s.executables = bin_files
+ end
+ spec_create.call(spec)
spec.homepage ||= "https://github.com/godfat/#{spec.name}"
- spec
+ self.spec = spec
end
- def readme
- path = %w[README.md README].find{ |name|
- File.exist?("#{Gemgem.dir}/#{name}")
- }
- @readme ||=
- if path
- ps = "##{File.read(path)}".
- scan(/((#+)[^\n]+\n\n.+?(?=(\n\n\2[^#\n]+\n)|\Z))/m).map(&:first)
- ps.inject('HEADER' => ps.first){ |r, s, i|
- r[s[/\w+/]] = s
- r
- }
- else
- {}
- end
+ def gem_install
+ require 'rubygems/commands/install_command'
+ # read ~/.gemrc
+ Gem.use_paths(Gem.configuration[:gemhome], Gem.configuration[:gempath])
+ Gem::Command.extra_args = Gem.configuration[:gem]
+
+ # setup install options
+ cmd = Gem::Commands::InstallCommand.new
+ cmd.handle_options([])
+
+ # install
+ install = Gem::Installer.new(gem_path, cmd.options)
+ install.install
+ puts "\e[35mGem installed: \e[33m#{strip_path(install.gem_dir)}\e[0m"
end
- def description
- @description ||= (readme['DESCRIPTION']||'').sub(/.+\n\n/, '').lines
+ def gem_spec
+ create
+ write
end
- def changes
- path = %w[CHANGES.md CHANGES].find{ |name|
- File.exist?("#{Gemgem.dir}/#{name}")
- }
- @changes ||=
- if path
- date = '\d+{4}\-\d+{2}\-\d{2}'
- File.read(path).match(
- /([^\n]+#{date}\n\n(.+?))(?=\n\n[^\n]+#{date}\n|\Z)/m)[1]
- else
- ''
- end
+ def gem_build
+ require 'fileutils'
+ require 'rubygems/package'
+ gem = nil
+ Dir.chdir(dir) do
+ gem = Gem::Package.build(Gem::Specification.load(spec_path))
+ FileUtils.mkdir_p(pkg_dir)
+ FileUtils.mv(gem, pkg_dir) # gem is relative path, but might be ok
+ end
+ puts "\e[35mGem built: \e[33m#{strip_path("#{pkg_dir}/#{gem}")}\e[0m"
end
- def ann_md
- "#{readme['HEADER'].sub(/([\w\-]+)/, "[\\1](#{spec.homepage})")}\n\n" \
- "##{readme['DESCRIPTION'][/[^\n]+\n\n[^\n]+/]}\n\n" \
- "### CHANGES:\n\n" \
- "###{changes}\n\n" \
- "##{readme['INSTALLATION']}\n\n" +
- if readme['SYNOPSIS'] then "##{readme['SYNOPSIS'][/[^\n]+\n\n[^\n]+/]}"
- else '' end
+ def gem_release
+ sh_git('tag', gem_tag)
+ sh_git('push')
+ sh_git('push', '--tags')
+ sh_gem('push', gem_path)
end
- def ann_html
- gem 'nokogiri'
- gem 'kramdown'
+ def gem_check
+ unless git('status', '--porcelain').empty?
+ puts("\e[35mWorking copy is not clean.\e[0m")
+ exit(3)
+ end
- IO.popen('kramdown', 'r+') do |md|
- md.puts Gemgem.ann_md
- md.close_write
- require 'nokogiri'
- html = Nokogiri::XML.parse("<gemgem>#{md.read}</gemgem>")
- html.css('*').each{ |n| n.delete('id') }
- html.root.children.to_html
+ ver = spec.version.to_s
+
+ if ENV['VERSION'].nil?
+ puts("\e[35mExpected " \
+ "\e[33mVERSION\e[35m=\e[33m#{ver}\e[0m")
+ exit(1)
+
+ elsif ENV['VERSION'] != ver
+ puts("\e[35mExpected \e[33mVERSION\e[35m=\e[33m#{ver} " \
+ "\e[35mbut got\n " \
+ "\e[33mVERSION\e[35m=\e[33m#{ENV['VERSION']}\e[0m")
+ exit(2)
end
end
- def ann_email
- "#{readme['HEADER'].sub(/([\w\-]+)/, "\\1 <#{spec.homepage}>")}\n\n" \
- "#{readme['DESCRIPTION']}\n\n" \
- "#{readme['INSTALLATION']}\n\n" +
- if readme['SYNOPSIS'] then "##{readme['SYNOPSIS']}\n\n" else '' end +
- "## CHANGES:\n\n" \
- "##{changes}\n\n"
+ def test
+ return if test_files.empty?
+
+ if ENV['COV'] || ENV['CI']
+ require 'simplecov'
+ if ENV['CI']
+ begin
+ require 'coveralls'
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
+ rescue LoadError => e
+ puts "Cannot load coveralls, skip: #{e}"
+ end
+ end
+ SimpleCov.start do
+ add_filter('test/')
+ add_filter('test.rb')
+ submodules_libs.each(&method(:add_filter))
+ end
+ end
+
+ test_files.each{ |file| require "#{dir}/#{file[0..-4]}" }
end
- def gem_tag
- "#{spec.name}-#{spec.version}"
+ def clean
+ return if ignored_files.empty?
+
+ require 'fileutils'
+ trash = File.expand_path("~/.Trash/#{spec.name}")
+ puts "Move the following files into: \e[35m#{strip_path(trash)}\e[33m"
+
+ ignored_files.each do |file|
+ from = "#{dir}/#{file}"
+ to = "#{trash}/#{File.dirname(file)}"
+ puts strip_path(from)
+
+ FileUtils.mkdir_p(to)
+ FileUtils.mv(from, to)
+ end
+
+ print "\e[0m"
end
def write
- File.open("#{dir}/#{spec.name}.gemspec", 'w'){ |f|
- f << split_lines(spec.to_ruby) }
+ File.open(spec_path, 'w'){ |f| f << split_lines(spec.to_ruby) }
end
def split_lines ruby
ruby.gsub(/(.+?)\s*=\s*\[(.+?)\]/){ |s|
if $2.index(',')
@@ -112,157 +155,184 @@
s
end
}
end
+ def strip_path path
+ strip_home_path(strip_cwd_path(path))
+ end
+
+ def strip_home_path path
+ path.sub(/\A#{Regexp.escape(ENV['HOME'])}\//, '~/')
+ end
+
+ def strip_cwd_path path
+ path.sub(/\A#{Regexp.escape(Dir.pwd)}\//, '')
+ end
+
+ def submodules_libs
+ submodules.map{ |path| "#{dir}/#{path}/lib" }
+ end
+
+ def git *args
+ `git --git-dir=#{dir}/.git #{args.join(' ')}`
+ end
+
+ def sh_git *args
+ Rake.sh('git', "--git-dir=#{dir}/.git", *args)
+ end
+
+ def sh_gem *args
+ Rake.sh(Gem.ruby, '-S', 'gem', *args)
+ end
+
+ def glob path=dir
+ Dir.glob("#{path}/**/*", File::FNM_DOTMATCH)
+ end
+
+ def readme
+ @readme ||=
+ if (path = "#{Gemgem.dir}/README.md") && File.exist?(path)
+ ps = "##{File.read(path)}".
+ scan(/((#+)[^\n]+\n\n.+?(?=(\n\n\2[^#\n]+\n)|\Z))/m).map(&:first)
+ ps.inject('HEADER' => ps.first){ |r, s, i|
+ r[s[/\w+/]] = s
+ r
+ }
+ else
+ {}
+ end
+ end
+
+ def description
+ # JRuby String#lines is returning an enumerator
+ @description ||= (readme['DESCRIPTION']||'').sub(/.+\n\n/, '').lines.to_a
+ end
+
+ def license
+ readme['LICENSE'].sub(/.+\n\n/, '').lines.first.
+ split(/[()]/).map(&:strip).reject(&:empty?).last
+ end
+
def all_files
- @all_files ||= find_files(Pathname.new(dir)).map{ |file|
- if file.to_s =~ %r{\.git/|\.git$}
- nil
+ @all_files ||= fold_files(glob).sort
+ end
+
+ def fold_files files
+ files.inject([]){ |r, path|
+ if File.file?(path) && path !~ %r{/\.git(/|$)} &&
+ (rpath = path[%r{^#{escaped_dir}/(.*$)}, 1])
+ r << rpath
+ elsif File.symlink?(path) # walk into symlinks...
+ r.concat(fold_files(glob(File.expand_path(path,
+ File.readlink(path)))))
else
- file.to_s
+ r
end
- }.compact.sort
+ }
end
def gem_files
- @gem_files ||= all_files - ignored_files
+ @gem_files ||= all_files.reject{ |f|
+ f =~ submodules_pattern ||
+ (f =~ ignored_pattern && !git_files.include?(f))
+ }
end
- def ignored_files
- @ignored_file ||= all_files.select{ |path| ignore_patterns.find{ |ignore|
- path =~ ignore && !git_files.include?(path)}}
+ def test_files
+ @test_files ||= gem_files.grep(%r{^test/(.+?/)*test_.+?\.rb$})
end
+ def bin_files
+ @bin_files ||= gem_files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ end
+
def git_files
@git_files ||= if File.exist?("#{dir}/.git")
- `git ls-files`.split("\n")
+ git('ls-files').split("\n")
else
[]
end
end
- # protected
- def find_files path
- path.children.select(&:file?).map{|file| file.to_s[(dir.size+1)..-1]} +
- path.children.select(&:directory?).map{|dir| find_files(dir)}.flatten
+ def ignored_files
+ @ignored_files ||= all_files.grep(ignored_pattern)
end
- def ignore_patterns
- @ignore_files ||= expand_patterns(
- gitignore.split("\n").reject{ |pattern|
- pattern.strip == ''
- }).map{ |pattern| %r{^([^/]+/)*?#{Regexp.escape(pattern)}(/[^/]+)*?$} }
+ def ignored_pattern
+ @ignored_pattern ||= if gitignore.empty?
+ /^$/
+ else
+ Regexp.new(expand_patterns(gitignore).join('|'))
+ end
end
+ def submodules_pattern
+ @submodules_pattern ||= if submodules.empty?
+ /^$/
+ else
+ Regexp.new(submodules.map{ |path|
+ "^#{Regexp.escape(path)}/" }.join('|'))
+ end
+ end
+
def expand_patterns pathes
- pathes.map{ |path|
- if path !~ /\*/
- path
- else
- expand_patterns(
- Dir[path] +
- Pathname.new(File.dirname(path)).children.select(&:directory?).
- map{ |prefix| "#{prefix}/#{File.basename(path)}" })
- end
- }.flatten
+ # http://git-scm.com/docs/gitignore
+ pathes.flat_map{ |path|
+ # we didn't implement negative pattern for now
+ Regexp.escape(path).sub(%r{^/}, '^').gsub(/\\\*/, '[^/]*')
+ }
end
def gitignore
- if File.exist?(path = "#{dir}/.gitignore")
- File.read(path)
- else
- ''
- end
+ @gitignore ||= if File.exist?(path = "#{dir}/.gitignore")
+ File.read(path).lines.
+ reject{ |l| l == /^\s*(#|\s+$)/ }.map(&:strip)
+ else
+ []
+ end
end
end
namespace :gem do
desc 'Install gem'
task :install => [:build] do
- sh("#{Gem.ruby} -S gem install pkg/#{Gemgem.gem_tag}.gem")
+ Gemgem.gem_install
end
desc 'Build gem'
task :build => [:spec] do
- sh("#{Gem.ruby} -S gem build #{Gemgem.spec.name}.gemspec")
- sh("mkdir -p pkg")
- sh("mv #{Gemgem.gem_tag}.gem pkg/")
+ Gemgem.gem_build
end
+desc 'Generate gemspec'
+task :spec do
+ Gemgem.gem_spec
+end
+
desc 'Release gem'
task :release => [:spec, :check, :build] do
- sh("git tag #{Gemgem.gem_tag}")
- sh("git push")
- sh("git push --tags")
- sh("#{Gem.ruby} -S gem push pkg/#{Gemgem.gem_tag}.gem")
+ Gemgem.gem_release
end
task :check do
- ver = Gemgem.spec.version.to_s
-
- if ENV['VERSION'].nil?
- puts("\e[35mExpected " \
- "\e[33mVERSION\e[35m=\e[33m#{ver}\e[0m")
- exit(1)
-
- elsif ENV['VERSION'] != ver
- puts("\e[35mExpected \e[33mVERSION\e[35m=\e[33m#{ver} " \
- "\e[35mbut got\n " \
- "\e[33mVERSION\e[35m=\e[33m#{ENV['VERSION']}\e[0m")
- exit(2)
- end
+ Gemgem.gem_check
end
end # of gem namespace
-desc 'Run tests in memory'
+desc 'Run tests'
task :test do
- require 'bacon'
- Bacon.extend(Bacon::TestUnitOutput)
- Bacon.summary_on_exit
- $LOAD_PATH.unshift('lib')
- Dir['./test/**/test_*.rb'].each{ |file| require file[0..-4] }
+ Gemgem.test
end
-desc 'Run tests with shell'
-task 'test:shell', :RUBY_OPTS do |t, args|
- files = Dir['test/**/test_*.rb'].join(' ')
-
- cmd = [Gem.ruby, args[:RUBY_OPTS],
- '-I', 'lib', '-S', 'bacon', '--quiet', files]
-
- sh(cmd.compact.join(' '))
-end
-
-desc 'Generate ann markdown'
-task 'ann:md' => ['gem:spec'] do
- puts Gemgem.ann_md
-end
-
-desc 'Generate ann html'
-task 'ann:html' => ['gem:spec'] do
- puts Gemgem.ann_html
-end
-
-desc 'Generate ann email'
-task 'ann:email' => ['gem:spec'] do
- puts Gemgem.ann_email
-end
-
-desc 'Generate rdoc'
-task :doc => ['gem:spec'] do
- sh("yardoc -o rdoc --main README.md" \
- " --files #{Gemgem.spec.extra_rdoc_files.join(',')}")
-end
-
-desc 'Remove ignored files'
+desc 'Trash ignored files'
task :clean => ['gem:spec'] do
- trash = "~/.Trash/#{Gemgem.spec.name}/"
- sh "mkdir -p #{trash}" unless File.exist?(File.expand_path(trash))
- Gemgem.ignored_files.each{ |file| sh "mv #{file} #{trash}" }
+ Gemgem.clean
end
task :default do
- puts `#{Gem.ruby} -S #{$PROGRAM_NAME} -T`
+ # Is there a reliable way to do this in the current process?
+ # It failed miserably before between Rake versions...
+ exec "#{Gem.ruby} -S #{$PROGRAM_NAME} -f #{Rake.application.rakefile} -T"
end