Class: Echoe

Inherits:
Object
  • Object
show all
Includes:
Rake::DSL
Defined in:
lib/echoe.rb,
lib/echoe/extensions.rb

Overview

Echoe includes some optional accessors for more advanced gem configuration.

For example, a simple Rakefile might look like this:

require 'echoe'

Echoe.new("uncapitalizer") do |p|
  p.author = "Evan Weaver"
  p.summary = "A library that uncapitalizes strings."
  p.runtime_dependencies = ["string_tools >=1.4.0"]
end

See below for the full list.

Signing gems

Echoe supports signing gems. First, create yourself a public and private key:

gem cert --build [email protected]

Move them somewhere secret, and add the following environment variables in your .bash_profile or similar:

export GEM_PRIVATE_KEY='/secret/path/to/gem-private_key.pem'
export GEM_CERTIFICATE_CHAIN='/secret/path/to/gem-public_cert.pem'

Make sure your environment is up-to-date:

source ~/.bash_profile

Upload your public_cert.pem file to your website or Rubyforge project, and tell your users to add that certificate to their system via:

gem cert --add /path/to/public_cert.pem

Finally, package and release your project as normal. Now users can install your gem via:

sudo gem install gemname -P HighSecurity

Note that you can also set the key and certificate locations in the Rakefile itself. Finally, you can add p.require_signed = true to your Rakefile so that you don’t accidentally release an unsigned gem if your key is missing.

Metadependencies

Echoe does not force packages to depend on Echoe itself. Instead, it generates a gemspec from your Rakefile and includes that. Downstream repackagers can use the gemspec as-is to build new versions of your gem even without Echoe.

Cross-packaging

Echoe supports platform Rake targets to allow you to cross-package your gems. Just write the spec assuming RUBY_PLATFORM will be what you need it to be for each architecture, and then invoke Rake with the platform name when you’re cross-packaging.

For example, on JRuby, rake package will build a generic -ruby type gem. But if you want to include a Java-specific extension, you can do one of two things. You can package from within JRuby by checking if RUBY_PLATFORM =~ /java/ and setting p.platform = jruby, or you can run rake java package, which will set RUBY_PLATFORM and p.platform for you.

This way you can run rake java package, rake aix install, or whatever task you need and Echoe will behave just like you’re packaging from within the target platform.

Test environment setup and teardown

For some applications, you may need to setup and teardown environment state for the entire test suite. This is especially common for integration tests that may need to spawn an external daemon. To support this, you can add a file tests/setup.rb and it will be silently executed before the entire suite runs. Add a similar file tests/teardown.rb in your app to be executed at the end of the entire run.

Note; these files will only get executed if you run the tests via rake. Also, you can set the environment variable VERBOSE=1 to not hide the setup/teardown output.

Accessor options

Descriptive options:

  • author - Your name.

  • email - Your email address.

  • description - A more detailed description of the library.

  • summary - A shorter description of the library.

  • url - A url for the library. Defaults to generated RDoc on GitHub pages for the project.f

  • install_message - A message to display after the gem is installed.

Versioning options:

  • version - A string for the version number. Parsed from CHANGELOG otherwise.

  • changes - A string describing the most recent changes. Parsed from CHANGELOG otherwise.

Common packaging options:

  • runtime_dependencies - An array of runtime dependencies for this gem. For example, ['mongrel', 'activesupport >= 2.0.2'].

  • development_dependencies - An array of development dependencies for this gem. For example, ['rake >=0.7.1'].

  • extension_pattern - A filename array, glob array, or regex for extension files that need to be run at install time. Defaults to "ext/**/extconf.rb".

Testing options:

  • clean_pattern - A filename array, glob array, or regex for files that should be removed when rake clean is run.

  • test_pattern - A filename array, glob array, or regex for test runners. Overridden by "test/test_all.rb", if it exists.

  • spec_pattern - A filename array, glob array, or regex for test runners.

  • rcov_options - Any extra flags to pass to RCov when coverage reports are run.

Uncommon packaging options:

  • platform - What platform this gem is for.

  • manifest_name - The name of the manifest file. Defaults to Manifest.

  • need_gem - Whether to generate a gem package. Defaults to true.

  • need_tar_gz - Whether to generate a .tar.gz package. Defaults to true.

  • need_tgz - Whether to generate a .tgz package. Defaults to false.

  • need_zip - Whether to generate a .zip package. Defaults to false.

  • include_rakefile - Include the Rakefile directly within the package. Defaults to true.

  • include_gemspec - Include the generated gemspec file within the package. Defaults to true.

  • ruby_version - Version string for which Ruby to require (for example, '>= 1.8.4'.

  • eval - Accepts a proc to be evaluated in the context of the Gem::Specification object. This allows you to set more unusual gemspec options.

  • ignore_pattern - A filename array, glob array, or regex for pathnames that should be ignored when building the manifest.

  • require_paths - Non-standard requirement paths to add to the gem definition.

  • executable_pattern - A filename array, glob array, or regex for files that should be installed as wrapped executables.

Security options:

  • private_key - The path to your gem private key. Defaults to ENV, if available. This accessor is not published in the resulting gemspec.

  • certificate_chain - An array representing your certificate authorization chain. If no one else has signed your certificate, just set it to your own cert. Defaults to ENV, if available. This accessor is not published in the resulting gemspec.

  • require_signed - Force Echoe to refuse to package your gem if it’s not properly signed. Default false.

Publishing options:

  • project - The name of the Rubyforge project. Defaults to the name of the gem.

  • docs_host - A host and filesystem path to publish the documentation to. Defaults to GitHub pages for the project. SSH upload to an accessible static file host also works.

Documentation options:

  • rdoc_pattern - A filename array, glob array, or regex for filenames that should be passed to RDoc.

  • rdoc_template - A path to an RDoc template. Defaults to the generic template.

Defined Under Namespace

Modules: Platform

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, _version = nil) {|_self| ... } ⇒ Echoe

Returns a new instance of Echoe.

Yields:

  • (_self)

Yield Parameters:

  • _self (Echoe)

    the object that the method was called on



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/echoe.rb', line 164

def initialize(name, _version = nil)
  # Defaults

  self.name = name
  self.project = name.downcase
  self.changelog = "CHANGELOG"
  self.author = ""
  self.email = ""
  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"]
  self.test_pattern = File.exist?("test/test_all.rb") ? "test/test_all.rb" : ['test/**/test_*.rb', 'test/**/*_test.rb']
  self.spec_pattern = "spec/**/*_spec.rb"

  self.ignore_pattern = /^(pkg|doc)|(\.svn|CVS|\.bzr|\.DS|\.git)$/

  self.changelog_patterns = {
      :version => [
          /^\s*v([\d\w\.]+)(\.|\s|$)/,
          /\s*\*\s*([\d\w\.]+)\s*\*\s*$/
        ],
      :changes => [
        /^\s*v([\d\.]+\. .*)/,
        /\*\s*[\d\.]+\s*\*\s*(.*)\*\s*[\d\.]+\s*\*$/m
      ]
    }

  self.description = ""
  self.summary = ""
  self.install_message = nil
  self.executable_pattern = /^bin\//
  self.require_paths = nil
  self.use_sudo = !(Platform.windows? or ENV['GEM_HOME'].to_s.include?(ENV['USER'].to_s))
  self.gem_bin = "gem#{Platform.suffix}"
  self.rcov_options = []
  self.rdoc_pattern = /^(lib|bin|tasks|ext)|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/

  self.gemspec_format = :ruby

  title = (name.downcase == name ? name.capitalize : name)
  self.rdoc_options = ['--line-numbers', '--inline-source', '--title', title]

  readme = Dir['*'].detect { |filename| filename =~ /^readme/i }
  self.rdoc_options += ['--main', readme] if readme

  self.runtime_dependencies = []
  self.development_dependencies = [] # These appear to not work at all
  self.manifest_name = "Manifest"
  self.extension_pattern = ["ext/**/extconf.rb", "ext/extconf.rb"]
  self.private_key = ENV['GEM_PRIVATE_KEY']
  self.require_signed = false
  self.certificate_chain = ENV['GEM_CERTIFICATE_CHAIN'].to_s.split(/\,\s*/).compact

  self.need_gem = true
  self.need_tar_gz = true
  self.need_tgz = false
  self.need_zip = false
  self.platform = $platform

  self.include_rakefile = true
  self.include_gemspec = true
  self.gemspec_name = "#{name}.gemspec"
  self.retain_gemspec = false
  self.rakefile_name = "Rakefile"
  self.rubygems_version = ">= 1.2"

  yield self if block_given?

  self.docs_host ||= "[email protected]:#{self.project}/#{self.project}.github.com"
  if self.docs_host =~ /[email protected]/
    self.url ||= "http://#{self.project}.github.com/#{self.project}/#{(self.name + '/') if project != name}"
  end

  # legacy compatibility
  self.runtime_dependencies = dependencies if dependencies and runtime_dependencies.empty?
  self.runtime_dependencies = extra_deps if extra_deps and runtime_dependencies.empty?
  self.rdoc_pattern = rdoc_files if rdoc_files
  self.extension_pattern = extensions if extensions

  # read manifest
  begin
    self.files = File.readlines(manifest_name).map { |x| x.strip } +
      [(gemspec_name if include_gemspec)] +
      [(rakefile_name if include_rakefile)]
    self.files = files.compact.uniq
  rescue Errno::ENOENT
    unless ARGV.include? "manifest"
      puts "Missing manifest. You can build one with 'rake manifest'."
      exit 1
    else
      self.files = []
    end
  end

  # snag version and changeset
  self.version ||= _version
  unless version
    if File.exist? changelog
      parsed = Array(changelog_patterns[:version]).map do |pattern|
        open(changelog) do |log|
          log.read[pattern, 1]
        end
      end.compact.first
      raise "Could not parse version from #{changelog}" unless parsed
      self.version = parsed.chomp(".").strip
    else
      raise "No #{changelog} found, and no version supplied in Rakefile."
    end
  end

  unless self.changes
    self.changes = if File.exist? changelog
      Array(changelog_patterns[:changes]).map do |pattern|
        open(changelog) do |log|
          log.read[pattern, 1]
        end
      end.compact.first or ""
    else
      ""
    end
  end

  # set some post-defaults
  self.certificate_chain = Array(certificate_chain).map {|file| File.expand_path(file)}
  self.private_key = File.expand_path(private_key) if private_key
  self.description = summary if description.empty?
  self.summary = description if summary.empty?
  self.clean_pattern = apply_pattern(clean_pattern)
  self.extension_pattern = apply_pattern(extension_pattern, files)

  self.ignore_pattern = apply_pattern(ignore_pattern)
  honor_gitignore! if File.exist?(".git")

  self.rdoc_pattern = apply_pattern(rdoc_pattern, files) - [manifest_name]
  self.executable_pattern = apply_pattern(executable_pattern, files)
  self.test_pattern = apply_pattern(test_pattern)
  self.spec_pattern = apply_pattern(spec_pattern)

  define_tasks
end

Instance Attribute Details

#authorObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def author
  @author
end

#bin_filesObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def bin_files
  @bin_files
end

#certificate_chainObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def certificate_chain
  @certificate_chain
end

#changelogObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def changelog
  @changelog
end

#changelog_patternsObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def changelog_patterns
  @changelog_patterns
end

#changesObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def changes
  @changes
end

#clean_patternObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def clean_pattern
  @clean_pattern
end

#dependenciesObject

legacy



162
163
164
# File 'lib/echoe.rb', line 162

def dependencies
  @dependencies
end

#descriptionObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def description
  @description
end

#development_dependenciesObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def development_dependencies
  @development_dependencies
end

#docs_hostObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def docs_host
  @docs_host
end

#emailObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def email
  @email
end

#evalObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def eval
  @eval
end

#executable_patternObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def executable_pattern
  @executable_pattern
end

#extension_patternObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def extension_pattern
  @extension_pattern
end

#extensionsObject

legacy



162
163
164
# File 'lib/echoe.rb', line 162

def extensions
  @extensions
end

#extra_depsObject

legacy



162
163
164
# File 'lib/echoe.rb', line 162

def extra_deps
  @extra_deps
end

#filesObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def files
  @files
end

#gem_binObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def gem_bin
  @gem_bin
end

#gemspec_formatObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def gemspec_format
  @gemspec_format
end

#gemspec_nameObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def gemspec_name
  @gemspec_name
end

#ignore_patternObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def ignore_pattern
  @ignore_pattern
end

#include_gemspecObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def include_gemspec
  @include_gemspec
end

#include_rakefileObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def include_rakefile
  @include_rakefile
end

#install_messageObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def install_message
  @install_message
end

#lib_filesObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def lib_files
  @lib_files
end

#manifest_nameObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def manifest_name
  @manifest_name
end

#nameObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def name
  @name
end

#need_gemObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def need_gem
  @need_gem
end

#need_tar_gzObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def need_tar_gz
  @need_tar_gz
end

#need_tgzObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def need_tgz
  @need_tgz
end

#need_zipObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def need_zip
  @need_zip
end

#platformObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def platform
  @platform
end

#private_keyObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def private_key
  @private_key
end

#projectObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def project
  @project
end

#rakefile_nameObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def rakefile_name
  @rakefile_name
end

#rcov_optionsObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def rcov_options
  @rcov_options
end

#rdoc_filesObject

legacy



162
163
164
# File 'lib/echoe.rb', line 162

def rdoc_files
  @rdoc_files
end

#rdoc_optionsObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def rdoc_options
  @rdoc_options
end

#rdoc_patternObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def rdoc_pattern
  @rdoc_pattern
end

#rdoc_templateObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def rdoc_template
  @rdoc_template
end

#require_pathsObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def require_paths
  @require_paths
end

#require_signedObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def require_signed
  @require_signed
end

#retain_gemspecObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def retain_gemspec
  @retain_gemspec
end

#ruby_versionObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def ruby_version
  @ruby_version
end

#rubygems_versionObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def rubygems_version
  @rubygems_version
end

#runtime_dependenciesObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def runtime_dependencies
  @runtime_dependencies
end

#specObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def spec
  @spec
end

#spec_patternObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def spec_pattern
  @spec_pattern
end

#summaryObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def summary
  @summary
end

#test_filesObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def test_files
  @test_files
end

#test_patternObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def test_pattern
  @test_pattern
end

#urlObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def url
  @url
end

#use_sudoObject

best left alone



159
160
161
# File 'lib/echoe.rb', line 159

def use_sudo
  @use_sudo
end

#versionObject

user-configurable



156
157
158
# File 'lib/echoe.rb', line 156

def version
  @version
end

Class Method Details

.silenceObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/echoe/extensions.rb', line 18

def self.silence
  if !ENV['VERBOSE']
    stdout, stderr = $stdout.clone, $stderr.clone
    $stdout.reopen(File.new("#{Dir.tmpdir}/stdout.echoe", 'w'))
    $stderr.reopen(File.new("#{Dir.tmpdir}/stderr.echoe", 'w'))
    begin
      yield
    ensure
      $stdout.reopen(stdout)
      $stderr.reopen(stderr)
    end
  else
    yield
  end
end