Parent

Namespace

Class Index [+]

Quicksearch

Echoe

Attributes

author[RW]

user-configurable

changes[RW]

user-configurable

clean_pattern[RW]

user-configurable

description[RW]

user-configurable

email[RW]

user-configurable

runtime_dependencies[RW]

user-configurable

development_dependencies[RW]

user-configurable

need_tgz[RW]

user-configurable

need_tar_gz[RW]

user-configurable

need_gem[RW]

user-configurable

need_zip[RW]

user-configurable

rdoc_pattern[RW]

user-configurable

project[RW]

user-configurable

summary[RW]

user-configurable

test_pattern[RW]

user-configurable

spec_pattern[RW]

user-configurable

url[RW]

user-configurable

version[RW]

user-configurable

docs_host[RW]

user-configurable

rdoc_template[RW]

user-configurable

manifest_name[RW]

user-configurable

install_message[RW]

user-configurable

extension_pattern[RW]

user-configurable

private_key[RW]

user-configurable

certificate_chain[RW]

user-configurable

require_signed[RW]

user-configurable

ruby_version[RW]

user-configurable

platform[RW]

user-configurable

ignore_pattern[RW]

user-configurable

executable_pattern[RW]

user-configurable

require_paths[RW]

user-configurable

changelog[RW]

user-configurable

rcov_options[RW]

user-configurable

gemspec_format[RW]

user-configurable

name[RW]

best left alone

lib_files[RW]

best left alone

test_files[RW]

best left alone

bin_files[RW]

best left alone

spec[RW]

best left alone

rdoc_options[RW]

best left alone

rubyforge_name[RW]

best left alone

has_rdoc[RW]

best left alone

include_gemspec[RW]

best left alone

include_rakefile[RW]

best left alone

gemspec_name[RW]

best left alone

retain_gemspec[RW]

best left alone

rakefile_name[RW]

best left alone

eval[RW]

best left alone

files[RW]

best left alone

changelog_patterns[RW]

best left alone

rubygems_version[RW]

best left alone

use_sudo[RW]

best left alone

gem_bin[RW]

best left alone

extra_deps[RW]

legacy

rdoc_files[RW]

legacy

extensions[RW]

legacy

dependencies[RW]

legacy

Public Class Methods

new(name, _version = nil) click to toggle source
     # 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
silence() click to toggle source
    # 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

Private Instance Methods

apply_pattern(pattern, files = nil) click to toggle source
     # 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
define_tasks() click to toggle source
     # 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
honor_gitignore!() click to toggle source
     # 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.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.