-
Notifications
You must be signed in to change notification settings - Fork 14
/
rubygems_plugin.rb
201 lines (164 loc) · 6.3 KB
/
rubygems_plugin.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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
# frozen-string-literal: true
require 'rubygems'
require 'net/https'
module Gem
class Src
class << self
def post_install_hook(installer)
return true if installer.class.name == 'Bundler::Source::Path::Installer'
return true if !!ENV['GEMSRC_SKIP']
gem_src = Gem::Src.new installer
gem_src.git_clone_homepage_or_source_code_uri_or_homepage_uri_or_github_organization_uri
gem_src.repositorize_installed_gem
true
end
end
def initialize(installer)
@installer, @spec, @tested_repositories = installer, installer.spec, []
end
# Guess the git repo from the gemspec and perform git clone
def git_clone_homepage_or_source_code_uri_or_homepage_uri_or_github_organization_uri
return false if File.exist? clone_dir
now = Time.now
if IRREGULAR_REPOSITORIES.key? @spec.name
return git_clone IRREGULAR_REPOSITORIES[@spec.name]
end
result =
git_clone_if_github(github_url(source_code_uri_from_metadata)) ||
git_clone_if_github(source_code_uri_from_metadata) ||
git_clone_if_github(github_url(@spec.homepage)) ||
git_clone_if_github(@spec.homepage) ||
git_clone_if_github(github_url(source_code_uri)) ||
git_clone_if_github(source_code_uri) ||
git_clone_if_github(github_url(homepage_uri)) ||
git_clone_if_github(homepage_uri) ||
git_clone(github_url(source_code_uri_from_metadata)) ||
git_clone(source_code_uri_from_metadata) ||
git_clone(github_url(@spec.homepage)) ||
git_clone(@spec.homepage) ||
git_clone(github_url(source_code_uri)) ||
git_clone(source_code_uri) ||
git_clone(github_url(homepage_uri)) ||
git_clone(homepage_uri) ||
git_clone(github_organization_uri(@spec.name))
if verbose?
puts "gem-src: #{@spec.name} - !!! Failed to find a repo." if result.nil?
puts "gem-src: #{@spec.name} - #{Time.now - now}s"
end
result
end
# git init the installed gem so that we can directly edit the files there
def repositorize_installed_gem
# Do this only when gemsrc_clone_root is configured.
# Because if gemsrc_clone_root is not configured, gem_dir/src is already a git repo,
# and making gem_dir a git repo would cause "adding embedded git repository: src" warning
return unless gemsrc_clone_root
if File.directory? gem_dir
puts "gem-src: #{@spec.name} - repositorizing..." if verbose?
`cd #{gem_dir} && ! git rev-parse --is-inside-work-tree 2> /dev/null && git init && git checkout -qb gem-src_init && git add -A && git commit -m 'Initial commit by gem-src'`
end
# git remote add from the installed gem to the cloned repo so that we can easily transfer patches
if File.directory?(clone_dir) && File.directory?(gem_dir)
puts "gem-src: #{@spec.name} - adding remotes..." if verbose?
`cd #{gem_dir} && git remote add src #{clone_dir}`
origin = `cd #{clone_dir} && git remote get-url origin`.chomp
`cd #{gem_dir} && git config remote.origin.url #{origin}` if origin
end
end
private
def gemsrc_clone_root
ENV['GEMSRC_CLONE_ROOT'] || Gem.configuration[:gemsrc_clone_root]
end
def clone_dir
@clone_dir ||= if gemsrc_clone_root
File.expand_path @spec.name, gemsrc_clone_root
else
File.join gem_dir, 'src'
end
end
def gem_dir
if @installer.respond_to?(:gem_dir)
@installer.gem_dir
elsif @installer.respond_to?(:gem_home) # old rubygems
File.expand_path(File.join(@installer.gem_home, 'gems', @spec.full_name))
else # bundler
File.expand_path(File.join(Gem.dir, 'gems', @spec.full_name))
end
end
def github_url(url)
if url =~ /\Ahttps?:\/\/([^.]+)\.github\.(?:com|io)\/(.+)/
if $1 == 'www'
"https://github.com/#{$2}"
elsif $1 == 'wiki'
# https://wiki.github.com/foo/bar => https://github.com/foo/bar
"https://github.com/#{$2}"
else
# https://foo.github.com/bar => https://github.com/foo/bar
"https://github.com/#{$1}/#{$2}"
end
elsif url =~ %r[\A(https?://github\.com/.+/.+)/tree/]
# https://github.com/foo/bar/tree/v1.2.3
$1
end
end
def git?(url)
!`git ls-remote #{url} 2> /dev/null`.empty?
end
def github?(url)
URI.parse(url).host == 'github.com'
end
def github_page_exists?(url)
Net::HTTP.new('github.com', 443).tap {|h| h.use_ssl = true }.request_head(url).code != '404'
end
def source_code_uri_from_metadata
@source_code_uri_from_metadata ||= @spec.metadata['source_code_uri']
end
def api
require 'open-uri'
@api ||= OpenURI.open_uri("https://rubygems.org/api/v1/gems/#{@spec.name}.yaml", &:read)
rescue OpenURI::HTTPError
""
end
def source_code_uri
@source_code_uri ||= api_uri_for('source_code')
end
def homepage_uri
@homepage_uri ||= api_uri_for('homepage')
end
def github_organization_uri(name)
"https://github.com/#{name}/#{name}"
end
def git_clone(repository)
return if repository.nil? || repository.empty?
return if repository.include? 'rubyforge.org'
return if @tested_repositories.include? repository
@tested_repositories << repository
return if github?(repository) && !github_page_exists?(repository)
puts "gem-src: #{@spec.name} - Cloning from #{repository}..." if verbose?
if use_ghq?
system 'ghq', 'get', repository
else
system 'git', 'clone', repository, clone_dir if git?(repository)
end
end
def git_clone_if_github(repository)
return if repository.nil? || repository.empty?
return unless github?(repository)
git_clone repository
end
def use_ghq?
ENV['GEMSRC_USE_GHQ'] || Gem.configuration[:gemsrc_use_ghq]
end
def api_uri_for(key)
uri = api[Regexp.new("^#{key}_uri: (.*)$"), 1]
uri =~ /\A(?:https?|git):\/\// ? uri : nil
end
def verbose?
!!ENV['GEMSRC_VERBOSE'] || Gem.configuration[:gemsrc_verbose]
end
end unless defined?(Src) # for rubygems test suite.
end
require 'gem/src/irregular_repositories'
Gem.post_install do |installer|
Gem::Src.post_install_hook installer
end