Skip to content

Commit 7e42dce

Browse files
committed
1.0.0 - extracted from rubygems-bundler
0 parents  commit 7e42dce

18 files changed

+423
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea
2+
*.gem
3+
.bundle
4+
Gemfile.lock
5+
pkg/*

.travis.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
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

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Gemfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
source "http://rubygems.org"
2+
3+
#ruby=1.8.7
4+
5+
gemspec

LICENSE

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

bin/executable-hooks-uninstaller

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'executable-hooks/uninstaller'
4+
5+
ExecutableHooks::Uninstaller.new.uninstall

bin/ruby_executable_hooks

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

executable-hooks.gemspec

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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 = ["[email protected]"]
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.executables = %w( executable-hooks-uninstaller )
19+
20+
s.add_development_dependency "tf"
21+
#s.add_development_dependency "smf-gem"
22+
end

lib/executable-hooks/hooks.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
end
17+
end
18+
end
19+
20+
class ExecutableHooks
21+
def self.run(original_file)
22+
Gem.load_executable_plugins
23+
Gem.executables_hooks.each do |hook|
24+
hook.call(original_file)
25+
end
26+
end
27+
end
28+
end

lib/executable-hooks/installer.rb

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
Gem.configuration[:custom_shebang] ||= '$env ruby_executable_hooks'
37+
ExecutableHooks::Wrapper.install
38+
execute_no_wrapper
39+
end
40+
41+
def execute_no_wrapper
42+
require 'executable-hooks/installer'
43+
name = get_one_optional_argument || ''
44+
specs = installed_gems.select{|spec| spec.name =~ /^#{name}/i }
45+
specs.each do |spec|
46+
unless spec.executables.empty?
47+
org_gem_path = Gem.path.find{|path|
48+
File.exists? File.join path, 'gems', spec.full_name
49+
} || Gem.dir
50+
cache_gem = File.join(org_gem_path, 'cache', spec.file_name)
51+
if File.exist? cache_gem
52+
puts "#{spec.name} #{spec.version}"
53+
inst = Gem::Installer.new Dir[cache_gem].first, :wrappers => true, :force => true, :install_dir => org_gem_path
54+
ExecutableHooksInstaller.bundler_generate_bin(inst)
55+
else
56+
puts "##{spec.name} #{spec.version} not found in GEM_PATH"
57+
end
58+
end
59+
end
60+
end
61+
62+
private
63+
def installed_gems
64+
if Gem::VERSION > '1.8' then
65+
Gem::Specification.to_a
66+
else
67+
Gem.source_index.map{|name,spec| spec}
68+
end
69+
end
70+
end

lib/executable-hooks/specification.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

lib/executable-hooks/uninstaller.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 ruby'
7+
RegenerateBinstubsCommand.new.execute_no_wrapper
8+
Wrapper.uninstall
9+
end
10+
end

lib/executable-hooks/version.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module ExecutableHooks
2+
VERSION = "1.0.0"
3+
end

0 commit comments

Comments
 (0)