executable-hooks 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .idea
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,38 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - jruby-18mode
8
+ - jruby-19mode
9
+ - jruby-head
10
+ - ruby-head
11
+ - rbx-18mode
12
+ - rbx-19mode
13
+ before_install:
14
+ - 'rm -rf $rvm_path/gems/*/{bin,gems}/rubygems-bundler-* $rvm_path/gems/*/{bin,gems}/executable-hooks-* $rvm_path/gems/*/bin/ruby_*_{wrapper,hooks}'
15
+ - hash -r
16
+ - 'curl -L https://get.smf.sh | sh'
17
+ - 'export PATH=~/.sm/bin:$PATH'
18
+ - 'sm ext install gem mpapis/sm_gem'
19
+ install: gem install tf -v '>=0.4.1'
20
+ before_script:
21
+ - unset BUNDLE_GEMFILE
22
+ script: tf --text test/tf/*
23
+ notifications:
24
+ irc:
25
+ channels:
26
+ - "irc.freenode.org#rubygems-bundler"
27
+ email:
28
+ recipients:
29
+ - mpapis@gmail.com
30
+ on_failure: change
31
+ matrix:
32
+ allow_failures:
33
+ - rvm: jruby-18mode
34
+ - rvm: jruby-19mode
35
+ - rvm: jruby-head
36
+ - rvm: rbx-18mode
37
+ - rvm: rbx-19mode
38
+ - rvm: ruby-head
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+ date: 2013-07-10
5
+
6
+ - extracted hooking to rubygems executables from https://github.com/mpapis/rubygems-bundler
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ #ruby=1.8.7
4
+
5
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2013 Michal Papis
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # Rubygems executable hooks
2
+
3
+ Add next rubygems plugin support for executables.
4
+
5
+ ## Usage
6
+
7
+ Install the gem:
8
+
9
+ gem install executable-hooks
10
+
11
+ In gem `lib` dir create `rubygems_executable_plugin.rb`:
12
+
13
+ Gem.execute do |original_file|
14
+ warn("Executing: #{original_file}")
15
+ end
16
+
17
+ Generate and install the new gem with executable hook.
18
+
19
+ Now try it:
20
+
21
+ gem install haml
22
+ haml --version
23
+
24
+ Returns:
25
+
26
+ Executing: /home/mpapis/.rvm/gems/ruby-1.8.7-p374-new1/bin/haml
27
+ Haml 4.0.3
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'executable-hooks/uninstaller'
4
+
5
+ ExecutableHooks.uninstall
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ original_file=ARGV[0]
4
+ ARGV.shift
5
+ $PROGRAM_NAME=original_file
6
+
7
+ require 'rubygems'
8
+ begin
9
+ require 'executable-hooks/hooks'
10
+ Gem::ExecutableHooks.run(original_file)
11
+ rescue LoadError
12
+ warn "unable to load executable-hooks/hooks" if ENV.key?('ExecutableHooks_DEBUG')
13
+ end
14
+
15
+ eval File.read(original_file), binding, original_file
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ Kernel.load(File.expand_path("../lib/executable-hooks/version.rb", __FILE__))
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "executable-hooks"
8
+ s.version = ExecutableHooks::VERSION
9
+ s.authors = ["Michal Papis"]
10
+ s.email = ["mpapis@gmail.com"]
11
+ s.homepage = "https://github.com/mpapis/executable-hooks"
12
+ s.summary = %q{
13
+ Hook into rubygems executables allowing extra actions to be taken before executable is run.
14
+ }
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.extensions = %w( ext/wrapper_installer/extconf.rb )
19
+ s.executables = %w( executable-hooks-uninstaller )
20
+
21
+ s.add_development_dependency "tf"
22
+ #s.add_development_dependency "smf-gem"
23
+ end
@@ -0,0 +1,22 @@
1
+ # Fake building extension
2
+ File.open('Makefile', 'w') { |f| f.write("all:\n\ninstall:\n\n") }
3
+ File.open('make', 'w') do |f|
4
+ f.write('#!/bin/sh')
5
+ f.chmod(f.stat.mode | 0111)
6
+ end
7
+ File.open('wrapper_installer.so', 'w') {}
8
+ File.open('wrapper_installer.dll', 'w') {}
9
+ File.open('nmake.bat', 'w') { |f| }
10
+
11
+
12
+ # add the gem to load path
13
+ $: << File.expand_path("../../../lib", __FILE__)
14
+ # load the uninstaller
15
+ require 'executable-hooks/uninstaller'
16
+ # call the action
17
+ RegenerateBinstubsCommand.new.execute
18
+ # unload the path, what was required stays ... but there is that much we can do
19
+ $:.pop
20
+
21
+ # just in case - it worked
22
+ true
@@ -0,0 +1,46 @@
1
+ module Gem
2
+ @executables_hooks ||= []
3
+
4
+ class << self
5
+ unless method_defined?(:execute)
6
+ def execute(&hook)
7
+ @executables_hooks << hook
8
+ end
9
+
10
+ attr_reader :executables_hooks
11
+ end
12
+
13
+ unless method_defined?(:load_executable_plugins)
14
+ def load_executable_plugins
15
+ load_plugin_files(find_files('rubygems_executable_plugin', false))
16
+ rescue ArgumentError, NoMethodError
17
+ # old rubygems
18
+ plugins = find_files('rubygems_executable_plugin')
19
+
20
+ plugins.each do |plugin|
21
+
22
+ # Skip older versions of the GemCutter plugin: Its commands are in
23
+ # RubyGems proper now.
24
+
25
+ next if plugin =~ /gemcutter-0\.[0-3]/
26
+
27
+ begin
28
+ load plugin
29
+ rescue ::Exception => e
30
+ details = "#{plugin.inspect}: #{e.message} (#{e.class})"
31
+ warn "Error loading RubyGems plugin #{details}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ class ExecutableHooks
39
+ def self.run(original_file)
40
+ Gem.load_executable_plugins
41
+ Gem.executables_hooks.each do |hook|
42
+ hook.call(original_file)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,95 @@
1
+ module ExecutableHooksInstaller
2
+ # Iterate through executables and generate wrapper for each one,
3
+ # extract of rubygems code
4
+ def self.bundler_generate_bin(inst)
5
+ return if inst.spec.executables.nil? or inst.spec.executables.empty?
6
+ bindir = inst.bin_dir ? inst.bin_dir : Gem.bindir(inst.gem_home)
7
+ inst.spec.executables.each do |filename|
8
+ filename.untaint
9
+ original = File.join bindir, filename
10
+ if File.exists?( original )
11
+ bin_script_path = File.join bindir, inst.formatted_program_filename(filename)
12
+ FileUtils.rm_f bin_script_path
13
+ File.open bin_script_path, 'wb', 0755 do |file|
14
+ file.print bundler_app_script_text(inst, filename)
15
+ end
16
+ inst.say bin_script_path if Gem.configuration.really_verbose
17
+ else
18
+ inst.say "Can not find #{inst.spec.name} in GEM_PATH"
19
+ break
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ def self.shebang(inst, bin_file_name)
26
+ # options were defined first in 1.5, we want to support back to 1.3.7
27
+ ruby_name = Gem::ConfigMap[:ruby_install_name] if inst.instance_variable_get(:@env_shebang)
28
+ bindir = inst.bin_dir ? inst.bin_dir : Gem.bindir(inst.gem_home)
29
+ path = File.join bindir, inst.formatted_program_filename(bin_file_name)
30
+ first_line = File.open(path, "rb") {|file| file.gets}
31
+
32
+ if /\A#!/ =~ first_line then
33
+ # Preserve extra words on shebang line, like "-w". Thanks RPA.
34
+ shebang = first_line.sub(/\A\#!.*?ruby\S*((\s+\S+)+)/, "#!#{Gem.ruby}")
35
+ opts = $1
36
+ shebang.strip! # Avoid nasty ^M issues.
37
+ end
38
+
39
+ if which = Gem.configuration[:custom_shebang]
40
+ which = which.gsub(/\$(\w+)/) do
41
+ case $1
42
+ when "env"
43
+ @env_path ||= Gem::Installer::ENV_PATHS.find {|env_path| File.executable? env_path }
44
+ when "ruby"
45
+ "#{Gem.ruby}#{opts}"
46
+ when "exec"
47
+ bin_file_name
48
+ when "name"
49
+ inst.spec.name
50
+ end
51
+ end
52
+
53
+ return "#!#{which}"
54
+ end
55
+
56
+ if not ruby_name then
57
+ "#!#{Gem.ruby}#{opts}"
58
+ elsif opts then
59
+ "#!/bin/sh\n'exec' #{ruby_name.dump} '-x' \"$0\" \"$@\"\n#{shebang}"
60
+ else
61
+ @env_path ||= Gem::Installer::ENV_PATHS.find {|env_path| File.executable? env_path }
62
+ "#!#{@env_path} #{ruby_name}"
63
+ end
64
+ end
65
+
66
+ # Return the text for an application file.
67
+ def self.bundler_app_script_text(inst, bin_file_name)
68
+ <<-TEXT
69
+ #{shebang(inst, bin_file_name)}
70
+ #
71
+ # This file was generated by RubyGems.
72
+ #
73
+ # The application '#{inst.spec.name}' is installed as part of a gem, and
74
+ # this file is here to facilitate running it.
75
+ #
76
+
77
+ require 'rubygems'
78
+
79
+ version = "#{Gem::Requirement.default}"
80
+
81
+ if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
82
+ version = $1
83
+ ARGV.shift
84
+ end
85
+
86
+ gem '#{inst.spec.name}', version
87
+ load Gem.bin_path('#{inst.spec.name}', '#{bin_file_name}', version)
88
+ TEXT
89
+ end
90
+
91
+ end
92
+
93
+ Gem.post_install do |inst|
94
+ ExecutableHooksInstaller.bundler_generate_bin(inst)
95
+ end
@@ -0,0 +1,69 @@
1
+ require 'rubygems/command_manager'
2
+ require 'rubygems/installer'
3
+ require 'rubygems/version'
4
+ require 'executable-hooks/wrapper'
5
+
6
+ class RegenerateBinstubsCommand < Gem::Command
7
+ def initialize
8
+ super 'regenerate_binstubs', 'Re run generation of executable wrappers for gems.'
9
+ end
10
+
11
+ def arguments # :nodoc:
12
+ "STRING start of gem name to regenerate binstubs"
13
+ end
14
+
15
+ def usage # :nodoc:
16
+ "#{program_name} [STRING]"
17
+ end
18
+
19
+ def defaults_str # :nodoc:
20
+ ""
21
+ end
22
+
23
+ def description # :nodoc:
24
+ 'Re run generation of executable wrappers for all gems. '+
25
+ 'Wrappers will be compatible with both rubygems and bundler. '+
26
+ 'The switcher is BUNDLE_GEMFILE environment variable, '+
27
+ 'when set it switches to bundler mode, when not set, '+
28
+ 'then the command will work as it was with pure rubygems.'
29
+ end
30
+
31
+ def execute
32
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('2.0.0') then
33
+ # https://github.com/rubygems/rubygems/issues/326
34
+ puts "try also: gem pristine --binstubs"
35
+ end
36
+ ExecutableHooks::Wrapper.install
37
+ execute_no_wrapper
38
+ end
39
+
40
+ def execute_no_wrapper
41
+ require 'executable-hooks/installer'
42
+ name = get_one_optional_argument || ''
43
+ specs = installed_gems.select{|spec| spec.name =~ /^#{name}/i }
44
+ specs.each do |spec|
45
+ unless spec.executables.empty?
46
+ org_gem_path = Gem.path.find{|path|
47
+ File.exists? File.join path, 'gems', spec.full_name
48
+ } || Gem.dir
49
+ cache_gem = File.join(org_gem_path, 'cache', spec.file_name)
50
+ if File.exist? cache_gem
51
+ puts "#{spec.name} #{spec.version}"
52
+ inst = Gem::Installer.new Dir[cache_gem].first, :wrappers => true, :force => true, :install_dir => org_gem_path
53
+ ExecutableHooksInstaller.bundler_generate_bin(inst)
54
+ else
55
+ puts "##{spec.name} #{spec.version} not found in GEM_PATH"
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+ def installed_gems
63
+ if Gem::VERSION > '1.8' then
64
+ Gem::Specification.to_a
65
+ else
66
+ Gem.source_index.map{|name,spec| spec}
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ module ExecutableHooks
2
+ module Specification
3
+ def self.find
4
+ @executable_hooks_spec ||=
5
+ if Gem::Specification.respond_to?(:find_by_name)
6
+ Gem::Specification.find_by_name("executable-hooks")
7
+ else
8
+ Gem.source_index.find_name("executable-hooks").last
9
+ end
10
+ rescue Gem::LoadError
11
+ nil
12
+ end
13
+ def self.version
14
+ find ? find.version.to_s : nil
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ require 'executable-hooks/wrapper'
2
+ require 'executable-hooks/regenerate_binstubs_command'
3
+
4
+ module ExecutableHooks
5
+ def self.uninstall
6
+ Gem.configuration[:custom_shebang] = "$env #{Gem.default_exec_format % "ruby"}"
7
+ RegenerateBinstubsCommand.new.execute_no_wrapper
8
+ Wrapper.uninstall
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module ExecutableHooks
2
+ VERSION = "1.1.0"
3
+ end
@@ -0,0 +1,53 @@
1
+ # install / uninstall wrapper
2
+ require 'fileutils'
3
+ require 'rubygems'
4
+ require 'executable-hooks/specification'
5
+
6
+ module ExecutableHooks
7
+ module Wrapper
8
+ def self.wrapper_name
9
+ 'ruby_executable_hooks'
10
+ end
11
+ def self.expanded_wrapper_name
12
+ Gem.default_exec_format % self.wrapper_name
13
+ end
14
+ def self.bindir
15
+ Gem.respond_to?(:bindir,true) ? Gem.send(:bindir) : File.join(Gem.dir, 'bin')
16
+ end
17
+ def self.destination
18
+ File.expand_path( expanded_wrapper_name, bindir )
19
+ end
20
+ def self.ensure_custom_shebang
21
+ expected_shebang = "$env #{expanded_wrapper_name}"
22
+
23
+ Gem.configuration[:custom_shebang] ||= expected_shebang
24
+
25
+ if Gem.configuration[:custom_shebang] != expected_shebang
26
+ warn("
27
+ Warning:
28
+ Found custom_shebang: '#{Gem.configuration[:custom_shebang]}',
29
+ Expected custom_shebang: '#{expected_shebang}',
30
+ this can potentially break 'executable-hooks' and gem executables overall!
31
+ ")
32
+ end
33
+ end
34
+ def self.install
35
+ ensure_custom_shebang
36
+
37
+ executable_hooks_spec = ExecutableHooks::Specification.find
38
+
39
+ if executable_hooks_spec
40
+ wrapper_path = File.expand_path( "bin/#{wrapper_name}", executable_hooks_spec.full_gem_path )
41
+
42
+ if File.exist?(wrapper_path) && !File.exist?(destination)
43
+ FileUtils.mkdir_p(bindir)
44
+ FileUtils.cp(wrapper_path, destination)
45
+ File.chmod(0775, destination)
46
+ end
47
+ end
48
+ end
49
+ def self.uninstall
50
+ FileUtils.rm_f(destination) if File.exist?(destination)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ Gem.execute do |original_file|
2
+ warn("Executing: #{original_file}") if ENV.key?('ExecutableHooks_DEBUG')
3
+ end
@@ -0,0 +1,26 @@
1
+ # Simulate require_relative - it's required as the plugin can be called in wrong version or from bundler.
2
+ require File.expand_path('../executable-hooks/specification.rb', __FILE__)
3
+
4
+ called_path, called_version = __FILE__.match(/^(.*\/executable-hooks-([^\/]+)\/lib).*$/)[1..2]
5
+
6
+ # continue only if loaded and called versions all the same, and not shared gems disabled in bundler
7
+ if
8
+ ( $:.include?(called_path) || ExecutableHooks::Specification.version == called_version ) and
9
+ ( !defined?(Bundler) || ( defined?(Bundler) && Bundler::SharedHelpers.in_bundle? && !Bundler.settings[:disable_shared_gems]) )
10
+
11
+ require 'rubygems/version'
12
+ require 'executable-hooks/wrapper'
13
+
14
+ # Set the custom_shebang if user did not set one
15
+ Gem.pre_install do |inst|
16
+ ExecutableHooks::Wrapper.install
17
+ end
18
+
19
+ if Gem::Version.new(Gem::VERSION) < Gem::Version.new('2.0') then
20
+ # Add custom_shebang support to rubygems
21
+ require 'executable-hooks/installer'
22
+ end
23
+
24
+ require 'executable-hooks/regenerate_binstubs_command'
25
+ Gem::CommandManager.instance.register_command :regenerate_binstubs
26
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: executable-hooks
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 1
9
+ - 0
10
+ version: 1.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Michal Papis
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-07-11 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: tf
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ description:
36
+ email:
37
+ - mpapis@gmail.com
38
+ executables:
39
+ - executable-hooks-uninstaller
40
+ extensions:
41
+ - ext/wrapper_installer/extconf.rb
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - .gitignore
46
+ - .travis.yml
47
+ - CHANGELOG.md
48
+ - Gemfile
49
+ - LICENSE
50
+ - README.md
51
+ - bin/executable-hooks-uninstaller
52
+ - bin/ruby_executable_hooks
53
+ - executable-hooks.gemspec
54
+ - ext/wrapper_installer/extconf.rb
55
+ - lib/executable-hooks/hooks.rb
56
+ - lib/executable-hooks/installer.rb
57
+ - lib/executable-hooks/regenerate_binstubs_command.rb
58
+ - lib/executable-hooks/specification.rb
59
+ - lib/executable-hooks/uninstaller.rb
60
+ - lib/executable-hooks/version.rb
61
+ - lib/executable-hooks/wrapper.rb
62
+ - lib/rubygems_executable_plugin.rb
63
+ - lib/rubygems_plugin.rb
64
+ has_rdoc: true
65
+ homepage: https://github.com/mpapis/executable-hooks
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project:
94
+ rubygems_version: 1.3.7
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Hook into rubygems executables allowing extra actions to be taken before executable is run.
98
+ test_files: []
99
+