executable-hooks 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+