# File lib/echoe.rb, line 165 165: def initialize(name, _version = nil) 166: # Defaults 167: 168: self.name = name 169: self.project = name.downcase 170: self.changelog = "CHANGELOG" 171: self.url = "" 172: self.author = "" 173: self.email = "" 174: self.clean_pattern = ["pkg", "doc", 'build/*', '**/coverage', '**/*.o', '**/*.so', '**/*.a', '**/*.log', "{ext,lib}/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/Makefile", "{ext,lib}/**/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/**/Makefile", "pkg", "*.gem", ".config"] 175: self.test_pattern = File.exist?("test/test_all.rb") ? "test/test_all.rb" : ['test/**/test_*.rb', 'test/**/*_test.rb'] 176: self.spec_pattern = "spec/**/*_spec.rb" 177: 178: self.ignore_pattern = /^(pkg|doc)|\.svn|CVS|\.bzr|\.DS|\.git/ 179: 180: self.changelog_patterns = { 181: :version => [ 182: /^\s*v([\d\w\.]+)(\.|\s|$)/, 183: /\s*\*\s*([\d\w\.]+)\s*\*\s*$/ 184: ], 185: :changes => [ 186: /^\s*v([\d\.]+\. .*)/, 187: /\*\s*[\d\.]+\s*\*\s*(.*)\*\s*[\d\.]+\s*\*$/ 188: ] 189: } 190: 191: self.description = "" 192: self.summary = "" 193: self.install_message = nil 194: self.executable_pattern = /^bin\// 195: self.require_paths = nil 196: self.has_rdoc = true 197: self.use_sudo = !(Platform.windows? or ENV['GEM_HOME'].to_s.include?(ENV['USER'].to_s)) 198: self.gem_bin = "gem#{Platform.suffix}" 199: self.rcov_options = [] 200: self.rdoc_pattern = /^(lib|bin|tasks|ext)|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/ 201: 202: self.gemspec_format = :ruby 203: 204: title = (name.downcase == name ? name.capitalize : name) 205: self.rdoc_options = ['--line-numbers', '--inline-source', '--title', title] 206: 207: readme = Dir['*'].detect { |filename| filename =~ /^readme/ } 208: self.rdoc_options += ['--main', readme] if readme 209: 210: self.runtime_dependencies = [] 211: self.development_dependencies = [] # These appear to not work at all 212: self.manifest_name = "Manifest" 213: self.extension_pattern = ["ext/**/extconf.rb", "ext/extconf.rb"] 214: self.private_key = ENV['GEM_PRIVATE_KEY'] 215: self.require_signed = false 216: self.certificate_chain = ENV['GEM_CERTIFICATE_CHAIN'].to_s.split(/\,\s*/).compact 217: 218: self.need_gem = true 219: self.need_tar_gz = true 220: self.need_tgz = false 221: self.need_zip = false 222: self.platform = $platform 223: 224: self.include_rakefile = true 225: self.include_gemspec = true 226: self.gemspec_name = "#{name}.gemspec" 227: self.retain_gemspec = false 228: self.rakefile_name = "Rakefile" 229: self.rubygems_version = ">= 1.2" 230: 231: yield self if block_given? 232: 233: # legacy compatibility 234: self.runtime_dependencies = dependencies if dependencies and runtime_dependencies.empty? 235: self.runtime_dependencies = extra_deps if extra_deps and runtime_dependencies.empty? 236: self.project = rubyforge_name if rubyforge_name 237: self.rdoc_pattern = rdoc_files if rdoc_files 238: self.extension_pattern = extensions if extensions 239: 240: # read manifest 241: begin 242: self.files = File.readlines(manifest_name).map { |x| x.strip } + 243: [(gemspec_name if include_gemspec)] + 244: [(rakefile_name if include_rakefile)] 245: self.files = files.compact.uniq 246: rescue Errno::ENOENT 247: unless ARGV.include? "manifest" 248: puts "Missing manifest. You can build one with 'rake manifest'." 249: exit 1 250: else 251: self.files = [] 252: end 253: end 254: 255: # snag version and changeset 256: self.version ||= _version 257: unless version 258: if File.exist? changelog 259: parsed = Array(changelog_patterns[:version]).map do |pattern| 260: open(changelog) do |log| 261: log.read[pattern, 1] 262: end 263: end.compact.first 264: raise "Could not parse version from #{changelog}" unless parsed 265: self.version = parsed.chomp(".").strip 266: else 267: raise "No #{changelog} found, and no version supplied in Rakefile." 268: end 269: end 270: 271: unless self.changes 272: self.changes = if File.exist? changelog 273: Array(changelog_patterns[:changes]).map do |pattern| 274: open(changelog) do |log| 275: log.read[pattern, 1] 276: end 277: end.compact.first or "" 278: else 279: "" 280: end 281: end 282: 283: # set some post-defaults 284: self.certificate_chain = Array(certificate_chain).map {|file| File.expand_path(file)} 285: self.private_key = File.expand_path(private_key) if private_key 286: self.description = summary if description.empty? 287: self.summary = description if summary.empty? 288: self.clean_pattern = apply_pattern(clean_pattern) 289: self.extension_pattern = apply_pattern(extension_pattern, files) 290: 291: self.ignore_pattern = apply_pattern(ignore_pattern) 292: honor_gitignore! if File.exist?(".git") 293: 294: self.rdoc_pattern = apply_pattern(rdoc_pattern, files) - [manifest_name] 295: self.executable_pattern = apply_pattern(executable_pattern, files) 296: self.test_pattern = apply_pattern(test_pattern) 297: self.spec_pattern = apply_pattern(spec_pattern) 298: 299: define_tasks 300: end
# File lib/echoe/extensions.rb, line 14 14: def self.silence 15: if !ENV['VERBOSE'] 16: stdout, stderr = $stdout.clone, $stderr.clone 17: $stdout.reopen(File.new("#{Dir.tmpdir}/stdout.echoe", 'w')) 18: $stderr.reopen(File.new("#{Dir.tmpdir}/stderr.echoe", 'w')) 19: begin 20: yield 21: ensure 22: $stdout.reopen(stdout) 23: $stderr.reopen(stderr) 24: end 25: else 26: yield 27: end 28: end
# File lib/echoe.rb, line 317 317: def apply_pattern(pattern, files = nil) 318: files ||= Dir['**/**'] 319: case pattern 320: when String, Array 321: files & (Array(pattern).map do |p| 322: Dir.glob(p) 323: end.flatten) 324: when Regexp 325: files.select do |file| 326: file =~ pattern 327: end 328: when FileList 329: pattern.each do |ignorefile| 330: ignorefiles = File.open(ignorefile).to_a.map(&:chomp) 331: files = files.select do |file| 332: ignorefiles.map { |i| File.fnmatch(i, file) }.include?(true) 333: end 334: end 335: files 336: else 337: [] 338: end 339: end
# File lib/echoe.rb, line 341 341: def define_tasks 342: 343: ### Packaging and Installing 344: 345: self.spec = Gem::Specification.new do |s| 346: s.name = name 347: s.version = version 348: # s.specification_version = 3 349: s.summary = summary 350: s.author = Array(author).join(", ") 351: s.email = email 352: s.homepage = url 353: s.rubyforge_project = project 354: s.post_install_message = install_message if install_message 355: s.description = description 356: s.required_ruby_version = ruby_version 357: s.required_rubygems_version = rubygems_version if rubygems_version 358: s.platform = platform 359: s.rdoc_options = rdoc_options 360: s.extra_rdoc_files = rdoc_pattern 361: 362: if private_key and File.exist? private_key 363: s.signing_key = private_key 364: s.cert_chain = certificate_chain 365: end 366: 367: runtime_dependencies.each do |dep| 368: dep = dep.split(" ") if dep.is_a? String 369: s.add_runtime_dependency(*dep) 370: end 371: 372: development_dependencies.each do |dep| 373: dep = dep.split(" ") if dep.is_a? String 374: s.add_development_dependency(*dep) 375: end 376: 377: s.files = files 378: 379: s.bindir = if executable_pattern.any? 380: executable_pattern[0].split("/")[0] 381: else 382: "bin" 383: end 384: 385: s.executables = executable_pattern.map do |file| 386: file[(s.bindir.length + 1)..1] 387: end 388: 389: dirs = Dir['{lib,ext}'] 390: s.extensions = extension_pattern if extension_pattern.any? 391: if require_paths 392: s.require_paths = require_paths 393: else 394: s.require_paths = dirs unless dirs.empty? 395: end 396: s.has_rdoc = has_rdoc 397: 398: if File.exist? "test/test_all.rb" 399: s.test_file = "test/test_all.rb" 400: else 401: s.test_files = test_pattern 402: end 403: 404: if eval 405: s.instance_eval &eval 406: end 407: 408: end 409: 410: self.lib_files = spec.files.grep(/^lib/) 411: self.bin_files = spec.files.grep(/^bin/) 412: self.test_files = spec.files.grep(/^test/) 413: 414: Rake::GemPackageTask.new(spec) do |pkg| 415: pkg.need_tar = @need_tgz 416: pkg.need_tar_gz = @need_tar_gz 417: pkg.need_zip = @need_zip 418: end 419: 420: desc "Display Echoe's knowledge of your system" 421: task :details do 422: (self.instance_variables.sort - ['@spec']).each do |var| 423: puts "#{var}: #{instance_variable_get(var).inspect}" 424: end 425: end 426: 427: desc "Builds the .gemspec" 428: task :build_gemspec do 429: # Construct the gemspec file, if needed. 430: if include_gemspec 431: File.open(gemspec_name, 'w') do |f| 432: case gemspec_format 433: when :yaml 434: spec.to_yaml.split("\n").each do |line| 435: # Don't publish any information about the private key or certificate chain 436: f.puts line unless line =~ /signing_key|cert_chain|\.pem/ 437: end 438: when :ruby 439: f.puts spec.to_ruby 440: else 441: raise "Unknown gemspec format #{gemspec_format.inspect}. Supported formats: :ruby and :yaml" 442: end 443: end 444: end 445: puts "Gemspec generated" 446: end 447: 448: # Chain it to the gemspec task prerequisite 449: task gemspec_name.to_sym => [:build_gemspec] 450: 451: desc "Generates manifest & gemspec in one go" 452: task :build => [:manifest, :build_gemspec] 453: 454: task :package do 455: # Chain some cleanup tasks to the default :package task. 456: # Remove the gemfile if it wasn't actually requested. 457: unless @need_gem 458: puts " Gem file not requested. Removed." 459: system "rm pkg/*.gem" 460: end 461: # Remove the generated gemspec once the packaging is done, to discourage people from modifying it by hand. 462: if include_gemspec and File.exist? gemspec_name and not retain_gemspec 463: File.delete gemspec_name 464: end 465: 466: # Test signing status 467: if private_key and File.exist? private_key 468: puts "Signing gem." 469: else 470: raise "Key required, but not found. Maybe you forget to set ENV['GEM_PRIVATE_KEY']?" if require_signed 471: puts "Private key not found; gem will not be signed." 472: end 473: puts "Targeting \"#{platform}\" platform." 474: end 475: 476: desc 'Install the gem' 477: task :install => [:clean, :package, :uninstall] do 478: system "#{'sudo' if use_sudo} #{gem_bin} install pkg/*.gem --no-update-sources #{'-P MediumSecurity' if private_key and File.exist?(private_key)}" 479: end 480: 481: namespace :install do 482: desc 'Install the gem including development dependencies' 483: task :development => [:clean, :package, :uninstall] do 484: system "#{'sudo' if use_sudo} #{gem_bin} install pkg/*.gem -P MediumSecurity --no-update-sources --development" 485: end 486: end 487: 488: desc 'Uninstall the gem' 489: task :uninstall do 490: system "#{'sudo' if use_sudo} #{gem_bin} uninstall #{name} -a -I -x" 491: end 492: 493: desc 'Package and upload the release to Gemcutter' 494: task :release => [:clean, :package] do |t| 495: pkg = "pkg/#{name}-#{version}" 496: pkg_gem = pkg + ".gem" 497: pkg_tar = pkg + ".tgz" 498: pkg_tar_gz = pkg + ".tar.gz" 499: pkg_zip = pkg + ".zip" 500: 501: puts "Releasing #{name} v. #{version} to Gemcutter." 502: system("gem push #{pkg_gem.inspect}") 503: end 504: 505: ### Extension building 506: 507: task :lib do 508: directory "lib" 509: end 510: 511: if extension_pattern.any? 512: 513: desc "Compile the binary extension module" 514: task :compile => [:lib] do 515: extension_pattern.each do |extension| 516: ext_dir = File.dirname(extension) 517: lib_target = nil 518: Dir.chdir(ext_dir) do 519: ruby File.basename(extension) 520: system(RUBY_PLATFORM =~ /win32/ ? 'nmake' : 'make') 521: lib_target = open('Makefile').readlines.grep(/target_prefix = /).first.split('=').last.chomp("\n").strip 522: end 523: Dir["#{ext_dir}/*.#{Config::CONFIG['DLEXT']}"].each do |file| 524: dir = "lib/#{lib_target}/".gsub('//', '/') 525: mkdir_p dir 526: cp file, dir 527: end 528: end 529: end 530: 531: task :test => [:compile] if test_pattern.any? 532: task :spec => :compile if spec_pattern.any? 533: 534: end 535: 536: ### Cross-platform targets 537: 538: Gem::Specification::PLATFORM_CROSS_TARGETS.each do |target| 539: task target do 540: reset_target target 541: end 542: end 543: 544: ### Documentation 545: 546: Rake::RDocTask.new(:docs) do |rd| 547: # rd.main = Dir['*'].detect {|f| f =~ /^readme/i} 548: rd.options += Array(rdoc_options) 549: 550: rd.rdoc_dir = 'doc' 551: rd.rdoc_files.push(*rdoc_pattern) 552: 553: if rdoc_template 554: rd.template = rdoc_template 555: elsif ENV['RDOC_TEMPLATE'] 556: rd.template = ENV['RDOC_TEMPLATE'] 557: end 558: end 559: 560: task :doc => [:redocs] 561: 562: desc "Publish documentation to #{docs_host ? "'#{docs_host}'" : "rubyforge"}" 563: task :publish_docs => [:clean, :docs] do 564: 565: local_dir = 'doc' 566: remote_dir_name = project 567: remote_dir_name += "/#{name}" if project != name 568: 569: unless docs_host 570: config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml"))) 571: pub = Rake::SshDirPublisher.new "#{config["username"]}@rubyforge.org", 572: "/var/www/gforge-projects/#{remote_dir_name}", 573: local_dir 574: if project != name then 575: def pub.upload 576: begin 577: super 578: rescue 579: # project directory probably doesn't exist, transfer as a whole 580: cmd = "scp -qr #{local_dir} #{host}:#{remote_dir}" 581: puts "Uploading: #{cmd}" 582: system(cmd) 583: end 584: end 585: end 586: pub.upload 587: else 588: # you may need ssh keys configured for this to work 589: host, dir = docs_host.split(":") 590: dir.chomp!("/") 591: 592: # XXX too dangerous? 593: cmd = "ssh #{host} 'rm -rf #{dir}/#{remote_dir_name}'" 594: puts "Deleting existing docs: #{cmd}" 595: system(cmd) 596: 597: cmd = "scp -qr #{local_dir} #{host}:#{dir}/#{remote_dir_name}" 598: puts "Uploading: #{cmd}" 599: system(cmd) 600: end 601: end 602: 603: desc 'Generate a release announcement, edit it, and post it to Rubyforge.' 604: task :announce do 605: 606: filename = "#{Dir.tmpdir}/#{name}_#{version}_announcement.txt" 607: 608: if File.exist?(filename) 609: puts "Announcement file already exists. Please delete #{filename.inspect} first." 610: exit(1) 611: end 612: 613: File.open(filename, 'w') do |f| 614: f.write "Subject: #{name.capitalize} #{version}\n\n" 615: f.write "#{name.capitalize} has been updated to #{version}. #{name.capitalize} is #{summary.uncapitalize}\n\n" 616: unless changes.empty? 617: f.write "Changes in this version: " 618: if changes.include?("\n") 619: f.write(changes) 620: else 621: f.write(changes.sub(/^\s*[\w\d\.]+\s+/, '').uncapitalize) 622: end 623: f.write("\n\n") 624: end 625: f.write "More information is available at #{url} .\n\n" unless url.empty? 626: end 627: 628: editor = ENV['EDITOR'] || 'nano' 629: system("#{editor} #{filename}") or raise "Editor '#{editor}' failed to start" 630: puts File.open(filename).read 631: 632: File.open(filename).readlines.detect { |line| line =~ /Subject: (.*)/ } 633: subject = $1 or raise "Subject line seems to have disappeared" 634: 635: body = File.open(filename).readlines.reject { |line| line =~ /Subject: / }.join.gsub("\n\n\n", "\n\n") 636: 637: rf = RubyForge.new.configure 638: rf.login 639: rf.post_news(project, subject, body) 640: puts "Published announcement to Rubyforge." 641: File.delete filename 642: end 643: 644: ### Clean 645: 646: desc 'Clean up auto-generated files' 647: task :clean do 648: puts "Cleaning" 649: clean_pattern.each do |file| 650: if File.exist?(file) 651: puts "- #{file}" 652: rm_rf file 653: end 654: end 655: end 656: 657: ### Manifest 658: 659: desc "Build a Manifest list" 660: task :manifest => [:clean] do 661: puts "Building Manifest" 662: old_files = files 663: files = [] 664: Dir['**/**'].sort.each do |file| 665: next unless file 666: next if ignore_pattern.include?(file) 667: next if File.directory?(file) 668: next if !include_rakefile and file == rakefile_name 669: files << file 670: end 671: 672: files << rakefile_name if include_rakefile 673: files << manifest_name 674: files.uniq! 675: 676: File.open(manifest_name, 'w').puts(files) 677: 678: (files | old_files).sort.each do |file| 679: next if file == gemspec_name 680: sign = " " 681: if old_files.include?(file) and !files.include?(file) 682: sign = "-" 683: elsif files.include?(file) and !old_files.include?(file) 684: sign = "+" 685: end 686: puts "#{sign} #{file}" 687: end 688: end 689: 690: task :build_manifest => :manifest 691: 692: ### Testing 693: 694: if test_pattern.any? 695: 696: Rake::TestTask.new(:test_inner) do |t| 697: t.libs = ['lib', 'ext', 'bin', 'test'] 698: t.test_files = test_pattern 699: t.verbose = true 700: end 701: 702: desc "Run the test suite" 703: task :test do 704: if File.exist? 'test/setup.rb' 705: Echoe.silence do 706: puts "Setting up test environment" 707: system("ruby test/setup.rb") 708: end 709: end 710: begin 711: test = Rake::Task[:test_inner] 712: if test.respond_to? :already_invoked= 713: # Method provided by MultiRails 714: test.already_invoked = false 715: end 716: test.invoke 717: ensure 718: if File.exist? 'test/teardown.rb' 719: Echoe.silence do 720: puts "Tearing down test environment" 721: system("ruby test/teardown.rb") 722: end 723: end 724: end 725: end 726: 727: task :default => :test 728: end 729: 730: if defined? Spec and spec_pattern.any? 731: desc "Run the spec suite" 732: Spec::Rake::SpecTask.new('spec') do |t| 733: t.spec_files = spec_pattern 734: end 735: 736: task :default => :spec 737: end 738: 739: if defined? Rcov 740: Rcov::RcovTask.new(:coverage) do |t| 741: t.test_files = test_pattern 742: t.rcov_opts << rcov_options if rcov_options 743: t.verbose = true 744: end 745: task :rcov => :coverage 746: end 747: end
# File lib/echoe.rb, line 303 303: def honor_gitignore! 304: self.ignore_pattern += Dir["**/.gitignore"].inject([]) do |pattern,gitignore| 305: pattern.concat File.readlines(gitignore). 306: map { |line| line.strip }. 307: reject { |line| "" == line }. 308: map { |glob| 309: d = File.dirname(gitignore) 310: d == "." ? glob : File.join(d, glob) 311: } 312: end.flatten.uniq 313: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.