cocoapods-nexus 0.0.2 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/cocoapods-nexus.gemspec +3 -2
- data/lib/cocoapods-nexus/api/components.rb +34 -7
- data/lib/cocoapods-nexus/api/connection.rb +1 -1
- data/lib/cocoapods-nexus/command/nexus/list.rb +1 -1
- data/lib/cocoapods-nexus/command/nexus/push.rb +10 -5
- data/lib/cocoapods-nexus/downloader.rb +3 -3
- data/lib/cocoapods-nexus/hook/specification.rb +19 -0
- data/lib/cocoapods-nexus/nexus_source.rb +253 -25
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96b8c8d75508a36b5121b69dadb1c71acec0edae13eff2b779d97793fcfbd33b
|
4
|
+
data.tar.gz: 05db6f85c0611aae05420f65e487221692e0c08cf50c5bab656584e7a14fe78a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32e7ac7b9fd22c4f41f7f30b25d96c2178b4122447c69fb7e58023c85f8d9286bb2795364e0e2b00ccf76d68f621b0f643e9d7b98cd71dfef551ab364ef5c066
|
7
|
+
data.tar.gz: 269c7f2054d40ec71345698aab553e5aa421d8738d21f2227f7e7ca773b522dfac13ad23e5605291d7085e8302888bf83eb64ec4930c7ecf71f8a2414790fe40
|
data/README.md
CHANGED
@@ -26,7 +26,7 @@ $ gem install cocoapods-nexus
|
|
26
26
|
```shell
|
27
27
|
$ pod nexus add RepoName NexusHostUrl
|
28
28
|
# 例如:
|
29
|
-
# pod nexus add ios_release http://ip:
|
29
|
+
# pod nexus add ios_release http://ip:port
|
30
30
|
```
|
31
31
|
|
32
32
|
#### List
|
@@ -45,7 +45,7 @@ $ pod nexus list
|
|
45
45
|
$ pod nexus push path/to/podspec --url=NexusHostUrl --repo=RepoName --artifact=path/to/预编译文件
|
46
46
|
|
47
47
|
# 例如:
|
48
|
-
# pod nexus push ~/demo.podspec --url=http://ip:
|
48
|
+
# pod nexus push ~/demo.podspec --url=http://ip:port --repo=ios_release --artifact=~/demo.zip
|
49
49
|
```
|
50
50
|
|
51
51
|
### Podfile配置
|
@@ -55,7 +55,7 @@ $ pod nexus push path/to/podspec --url=NexusHostUrl --repo=RepoName --artifact=p
|
|
55
55
|
plugin 'cocoapods-nexus', :sources => [
|
56
56
|
{
|
57
57
|
:name => "ios",
|
58
|
-
:url => "http://ip:
|
58
|
+
:url => "http://ip:port",
|
59
59
|
}
|
60
60
|
]
|
61
61
|
|
@@ -77,7 +77,7 @@ password nexus_password
|
|
77
77
|
|
78
78
|
### 2.服务器地址
|
79
79
|
|
80
|
-
插件关于nexus的相关操作只需要配置ip和
|
80
|
+
插件关于nexus的相关操作只需要配置ip和port,后续的mount地址默认为nexus,暂时不支持修改。
|
81
81
|
|
82
82
|
## 致谢
|
83
83
|
|
data/cocoapods-nexus.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'cocoapods-nexus'
|
7
|
-
spec.version =
|
7
|
+
spec.version = '0.0.7'
|
8
8
|
spec.authors = ['mrdaios']
|
9
9
|
spec.email = ['mrdaios@gmail.com']
|
10
10
|
spec.description = 'a cocoapods plugin for nexus.'
|
@@ -19,8 +19,9 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'cocoapods', '>= 1.9.3'
|
22
|
+
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.1'
|
22
23
|
spec.add_runtime_dependency 'rest-client', '~> 2.1.0'
|
23
|
-
spec.add_runtime_dependency '
|
24
|
+
spec.add_runtime_dependency 'typhoeus', '~> 1.0'
|
24
25
|
|
25
26
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
26
27
|
spec.add_development_dependency 'rake', '~> 13.0'
|
@@ -6,22 +6,49 @@ module CocoapodsNexus
|
|
6
6
|
end
|
7
7
|
|
8
8
|
# 上传组件
|
9
|
-
def upload_maven_component(artifact_id:, version:, group_id:, podspec:, artifact:, files:)
|
9
|
+
def upload_maven_component(artifact_id:, version:, group_id:, podspec:, artifact:, podspec_hook:, files:)
|
10
10
|
parameters = {
|
11
11
|
'maven2.artifactId' => artifact_id,
|
12
12
|
'maven2.version' => version,
|
13
13
|
'maven2.groupId' => group_id,
|
14
14
|
'maven2.generate-pom' => true,
|
15
|
-
'maven2.packaging' => artifact.nil? ? 'podspec' : File.extname(artifact).delete(
|
15
|
+
'maven2.packaging' => artifact.nil? ? 'podspec' : File.extname(artifact).delete('.')
|
16
16
|
}
|
17
17
|
upload_files = []
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
unless podspec.nil?
|
19
|
+
upload_files << {
|
20
|
+
'file' => podspec,
|
21
|
+
'extension' => 'podspec',
|
22
|
+
# 'classifier' => 'podspec'
|
23
|
+
}
|
24
|
+
end
|
25
|
+
unless artifact.nil?
|
26
|
+
upload_files << {
|
27
|
+
'file' => artifact,
|
28
|
+
'extension' => File.extname(artifact).delete('.')
|
29
|
+
}
|
30
|
+
end
|
31
|
+
unless podspec_hook.nil?
|
32
|
+
upload_files << {
|
33
|
+
'file' => podspec_hook,
|
34
|
+
'extension' => 'rb',
|
35
|
+
'classifier' => 'podspec_hook'
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
unless files.nil?
|
40
|
+
upload_files |= files.map do |file|
|
41
|
+
{
|
42
|
+
'file' => file,
|
43
|
+
'extension' => File.extname(file).delete('.'),
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
21
47
|
|
22
48
|
upload_files.each_index do |index|
|
23
|
-
parameters["maven2.asset#{index + 1}"] = File.open(upload_files[index], 'r:utf-8')
|
24
|
-
parameters["maven2.asset#{index + 1}.extension"] =
|
49
|
+
parameters["maven2.asset#{index + 1}"] = File.open(upload_files[index]['file'], 'r:utf-8')
|
50
|
+
parameters["maven2.asset#{index + 1}.extension"] = upload_files[index]['extension'] unless upload_files[index]['extension'].nil?
|
51
|
+
parameters["maven2.asset#{index + 1}.classifier"] = upload_files[index]['classifier'] unless upload_files[index]['classifier'].nil?
|
25
52
|
end
|
26
53
|
@connection.post(endpoint: "components?repository=#{@repo}", parameters: parameters, headers: {})
|
27
54
|
end
|
@@ -112,7 +112,7 @@ module CocoapodsNexus
|
|
112
112
|
|
113
113
|
def send_request(connection_method, endpoint, parameters: '', headers: {}, api_version: 'v1')
|
114
114
|
parameters = parameters.to_json if headers['Content-Type'] == 'application/json'
|
115
|
-
url =
|
115
|
+
url = File.join(@hostname,"/nexus/service/rest/#{api_version}/#{endpoint}")
|
116
116
|
catch_connection_error do
|
117
117
|
RestClient::Request.execute(
|
118
118
|
method: connection_method,
|
@@ -16,9 +16,10 @@ module Pod
|
|
16
16
|
|
17
17
|
def self.options
|
18
18
|
[
|
19
|
-
[
|
20
|
-
[
|
21
|
-
[
|
19
|
+
%w[--url=url nexus服务器地址(http://ip:port)],
|
20
|
+
%w[--repo=repo nexus的仓库名称],
|
21
|
+
%w[--artifact=artifact 制品文件],
|
22
|
+
%w[--podspec_hook=podspec_hook. podspec动态修改脚本文件]
|
22
23
|
].concat(super)
|
23
24
|
end
|
24
25
|
|
@@ -27,6 +28,7 @@ module Pod
|
|
27
28
|
@url = argv.option('url')
|
28
29
|
@repo = argv.option('repo')
|
29
30
|
@artifact = argv.option('artifact')
|
31
|
+
@podspec_hook = argv.option('podspec_hook')
|
30
32
|
super
|
31
33
|
end
|
32
34
|
|
@@ -40,8 +42,10 @@ module Pod
|
|
40
42
|
def run
|
41
43
|
podspec_path = File.expand_path(@podspec)
|
42
44
|
artifact_path = File.expand_path(@artifact) unless @artifact.nil?
|
45
|
+
podspec_hook_path = File.expand_path(@podspec_hook) unless @podspec_hook.nil?
|
43
46
|
|
44
|
-
|
47
|
+
|
48
|
+
UI.section("开始发布 #{File.basename(@podspec)} -> #{File.join(@url,"/nexus/#browse/browse:",@repo)}") do
|
45
49
|
spec = Specification.from_file(podspec_path)
|
46
50
|
artifact_id = spec.attributes_hash['name']
|
47
51
|
version = spec.attributes_hash['version']
|
@@ -52,7 +56,8 @@ module Pod
|
|
52
56
|
group_id: group_id,
|
53
57
|
podspec: podspec_path,
|
54
58
|
artifact: artifact_path,
|
55
|
-
|
59
|
+
podspec_hook: podspec_hook_path,
|
60
|
+
files: nil)
|
56
61
|
UI.puts "成功发布 #{artifact_id}(#{version})"
|
57
62
|
else
|
58
63
|
raise Informative, "发布失败 #{artifact_id}(#{version}),请检查~/.netrc文件或#{@repo}类型"
|
@@ -12,7 +12,7 @@ module Pod
|
|
12
12
|
executable :curl
|
13
13
|
|
14
14
|
def download!
|
15
|
-
@filename = "#{options[:name]}.#{
|
15
|
+
@filename = "#{options[:name]}.#{options[:type]}"
|
16
16
|
@download_path = @target_path + @filename
|
17
17
|
download_file(@download_path)
|
18
18
|
end
|
@@ -32,8 +32,8 @@ module Pod
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def user_agent_argument
|
35
|
-
"-A
|
35
|
+
"-A cocoapods-nexus"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
39
|
-
end
|
39
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cocoapods-core'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Specification
|
5
|
+
class << Specification
|
6
|
+
def _eval_nexus_podspec(nexus_podspec, parent_podspec)
|
7
|
+
podspec_string = nexus_podspec.gsub('Pod::Spec.new', 'Pod::Spec.nexus(parent_podspec)')
|
8
|
+
.gsub('Pod::Specification.new', 'Pod::Spec.nexus(parent_podspec)')
|
9
|
+
# rubocop:disable Eval
|
10
|
+
eval(podspec_string, binding)
|
11
|
+
# rubocop:enable Eval
|
12
|
+
end
|
13
|
+
|
14
|
+
def nexus(parent_podspec)
|
15
|
+
yield parent_podspec if block_given?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,9 +1,14 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
require 'typhoeus'
|
1
3
|
require 'cocoapods-nexus/api'
|
2
4
|
require 'cocoapods-nexus/downloader'
|
3
|
-
require '
|
5
|
+
require 'cocoapods-nexus/hook/specification'
|
4
6
|
|
5
7
|
module Pod
|
6
8
|
class NexusSource < Source
|
9
|
+
include Concurrent
|
10
|
+
HYDRA_EXECUTOR = Concurrent::SingleThreadExecutor.new
|
11
|
+
|
7
12
|
def initialize(repo, url)
|
8
13
|
@source_url = url
|
9
14
|
super(repo)
|
@@ -26,34 +31,87 @@ module Pod
|
|
26
31
|
'nexus'
|
27
32
|
end
|
28
33
|
|
34
|
+
# @return [Array<Version>] all the available versions for the Pod, sorted
|
35
|
+
# from highest to lowest.
|
36
|
+
#
|
37
|
+
# @param [String] name
|
38
|
+
# the name of the Pod.
|
39
|
+
#
|
40
|
+
def versions(name)
|
41
|
+
return nil unless specs_dir
|
42
|
+
raise ArgumentError, 'No name' unless name
|
43
|
+
|
44
|
+
return @versions_by_name[name] unless @versions_by_name[name].nil?
|
45
|
+
|
46
|
+
pod_path_actual = pod_path(name)
|
47
|
+
pod_path_relative = pod_path(name).relative_path_from(repo)
|
48
|
+
|
49
|
+
concurrent_requests_catching_errors do
|
50
|
+
loaders = []
|
51
|
+
components = nexus_api.search_maven_component(artifact_id: name)
|
52
|
+
if !components.nil? && components.count > 0
|
53
|
+
# 从服务器获取version
|
54
|
+
@versions_by_name[name] ||= components.map do |component|
|
55
|
+
# Optimization: ensure all the podspec files at least exist. The correct one will get refreshed
|
56
|
+
# in #specification_path regardless.
|
57
|
+
podspec_version_path_relative = Pathname.new(component["version"]).join("#{name}.podspec")
|
58
|
+
|
59
|
+
unless pod_path_actual.join(podspec_version_path_relative).exist?
|
60
|
+
remote_url = parse_artifacte_asset_url(component, 'podspec')
|
61
|
+
# Queue all podspec download tasks first
|
62
|
+
loaders << download_file_async(pod_path_relative.join(podspec_version_path_relative).to_s, remote_url)
|
63
|
+
end
|
64
|
+
|
65
|
+
begin
|
66
|
+
Version.new(component["version"]) if component["version"][0, 1] != '.'
|
67
|
+
rescue ArgumentError
|
68
|
+
raise Informative, 'An unexpected version directory ' \
|
69
|
+
"`#{component["version"]}` was encountered for the " \
|
70
|
+
"`#{pod_path_actual}` Pod in the `#{name}` repository."
|
71
|
+
end
|
72
|
+
end.compact.sort.reverse
|
73
|
+
end
|
74
|
+
# Block and wait for all to complete running on Hydra
|
75
|
+
Promises.zip_futures_on(HYDRA_EXECUTOR, *loaders).wait!
|
76
|
+
end
|
77
|
+
@versions_by_name[name]
|
78
|
+
end
|
79
|
+
|
29
80
|
# 从nexus查询依赖
|
30
81
|
# @param [Object] query
|
31
82
|
def search(query)
|
32
83
|
unless File.exist?("#{repo}/.nexus")
|
33
84
|
raise Informative, "Unable to find a source named: `#{name}`"
|
34
85
|
end
|
35
|
-
|
36
|
-
|
37
|
-
# 本地没查询到,则从nexus服务查询
|
38
|
-
if found == []
|
39
|
-
# 暂时这样处理
|
40
|
-
spec_version = query.requirement.requirements.last.last.to_s
|
41
|
-
artifacte = nexus_find_artifacte(spec_name: query.root_name, spec_version: spec_version)
|
42
|
-
if artifacte
|
43
|
-
download_url = parse_artifacte_asset_url(artifacte, 'podspec')
|
44
|
-
if download_url
|
45
|
-
target_path = "#{@repo}/#{query.root_name}/#{spec_version}"
|
46
|
-
downloader = Pod::Downloader::NexusHttp.new(target_path, download_url, {:type => 'podspec', :name => query.root_name})
|
47
|
-
downloader.download
|
48
|
-
|
49
|
-
found = find_local_podspec(query)
|
50
|
-
end
|
51
|
-
end
|
86
|
+
if query.is_a?(Dependency)
|
87
|
+
query = query.root_name
|
52
88
|
end
|
53
89
|
|
54
|
-
|
55
|
-
|
56
|
-
|
90
|
+
# found = find_local_podspec(query)
|
91
|
+
# # 本地没查询到,则从nexus服务查询
|
92
|
+
# if found == []
|
93
|
+
# # 暂时这样处理
|
94
|
+
# spec_version = query.requirement.requirements.last.last.to_s
|
95
|
+
# artifacte = nexus_find_artifacte(spec_name: query.root_name, spec_version: spec_version)
|
96
|
+
# if artifacte
|
97
|
+
# download_url = parse_artifacte_asset_url(artifacte, 'podspec')
|
98
|
+
# if download_url
|
99
|
+
# target_path = "#{@repo}/#{query.root_name}/#{spec_version}"
|
100
|
+
# downloader = Pod::Downloader::NexusHttp.new(target_path, download_url, {:type => 'podspec', :name => query.root_name})
|
101
|
+
# downloader.download
|
102
|
+
#
|
103
|
+
# found = find_local_podspec(query)
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
# end
|
107
|
+
|
108
|
+
# version信息暂时不缓存到本地
|
109
|
+
components = nexus_api.search_maven_component(artifact_id: query)
|
110
|
+
found = !components.nil? && components.count > 0 ? query : nil
|
111
|
+
|
112
|
+
if found
|
113
|
+
set = set(query)
|
114
|
+
set if set.specification_name == query
|
57
115
|
end
|
58
116
|
end
|
59
117
|
|
@@ -66,7 +124,24 @@ module Pod
|
|
66
124
|
specification.attributes_hash['source'] = {
|
67
125
|
'http' => download_url
|
68
126
|
}
|
69
|
-
|
127
|
+
|
128
|
+
# 执行自定义脚本
|
129
|
+
podspec_rb_url = parse_artifacte_asset_url(artifacte, 'podspec_hook.rb')
|
130
|
+
if podspec_rb_url
|
131
|
+
tmpdir = Dir.tmpdir
|
132
|
+
downloader = Pod::Downloader::NexusHttp.new(tmpdir, podspec_rb_url, {:type => 'rb', :name => name})
|
133
|
+
downloader.download
|
134
|
+
|
135
|
+
path = File.join(tmpdir, "#{name}.rb")
|
136
|
+
if File.exist?(path)
|
137
|
+
string = File.open(path, 'r:utf-8', &:read)
|
138
|
+
if string
|
139
|
+
Pod::Specification._eval_nexus_podspec(string, specification)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
else
|
143
|
+
specification.attributes_hash['vendored_frameworks'] = "#{name}.framework"
|
144
|
+
end
|
70
145
|
end
|
71
146
|
specification
|
72
147
|
end
|
@@ -87,12 +162,14 @@ module Pod
|
|
87
162
|
# 解析附件downloadUrl
|
88
163
|
def parse_artifacte_asset_url(artifacte, asset_type)
|
89
164
|
asset = artifacte['assets'].select { |asset| asset['path'].end_with?(asset_type) }.first
|
90
|
-
asset['downloadUrl'] if asset && asset['downloadUrl']
|
91
|
-
end
|
165
|
+
asset['downloadUrl'] if asset && asset['downloadUrl']
|
166
|
+
end
|
92
167
|
|
93
168
|
def nexus_find_artifacte(spec_name:, spec_version:)
|
94
169
|
artifactes = nexus_api.search_maven_component(artifact_id: spec_name)
|
95
|
-
artifacte = artifactes.select { |artifacte| artifacte['version'].start_with?(spec_version) }.sort_by { |artifacte| Versionomy.parse(artifacte['version'])}.last
|
170
|
+
# artifacte = artifactes.select { |artifacte| artifacte['version'].start_with?(spec_version) }.sort_by { |artifacte| Versionomy.parse(artifacte['version'])}.last
|
171
|
+
# 暂时只支持查询指定版本
|
172
|
+
artifacte = artifactes.select { |artifacte| artifacte['version'] == spec_version }.last
|
96
173
|
artifacte
|
97
174
|
end
|
98
175
|
|
@@ -100,5 +177,156 @@ module Pod
|
|
100
177
|
repo_name = File.basename(@repo).gsub('nexus_', '')
|
101
178
|
@nexus_api ||= CocoapodsNexus::API.new(hostname: url, repo: repo_name)
|
102
179
|
end
|
180
|
+
|
181
|
+
def concurrent_requests_catching_errors
|
182
|
+
yield
|
183
|
+
rescue MultipleErrors => e
|
184
|
+
# aggregated error message from `Concurrent`
|
185
|
+
errors = e.errors
|
186
|
+
raise Informative, "CDN: #{name} Repo update failed - #{e.errors.size} error(s):\n#{errors.join("\n")}"
|
187
|
+
end
|
188
|
+
|
189
|
+
def download_file_async(partial_url, remote_url)
|
190
|
+
file_remote_url = URI.encode(remote_url)
|
191
|
+
path = repo + partial_url
|
192
|
+
|
193
|
+
# file_okay = local_file_okay?(partial_url)
|
194
|
+
# if file_okay
|
195
|
+
# if @startup_time < File.mtime(path)
|
196
|
+
# debug "CDN: #{name} Relative path: #{partial_url} modified during this run! Returning local"
|
197
|
+
# return Promises.fulfilled_future(partial_url, HYDRA_EXECUTOR)
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# unless @check_existing_files_for_update
|
201
|
+
# debug "CDN: #{name} Relative path: #{partial_url} exists! Returning local because checking is only perfomed in repo update"
|
202
|
+
# return Promises.fulfilled_future(partial_url, HYDRA_EXECUTOR)
|
203
|
+
# end
|
204
|
+
# end
|
205
|
+
|
206
|
+
path.dirname.mkpath
|
207
|
+
|
208
|
+
# etag_path = path.sub_ext(path.extname + '.etag')
|
209
|
+
|
210
|
+
# etag = File.read(etag_path) if file_okay && File.exist?(etag_path)
|
211
|
+
# debug "CDN: #{name} Relative path: #{partial_url}, has ETag? #{etag}" unless etag.nil?
|
212
|
+
|
213
|
+
download_and_save_with_retries_async(partial_url, file_remote_url)
|
214
|
+
end
|
215
|
+
|
216
|
+
def download_and_save_with_retries_async(partial_url, file_remote_url, retries = 5)
|
217
|
+
path = repo + partial_url
|
218
|
+
# etag_path = path.sub_ext(path.extname + '.etag')
|
219
|
+
|
220
|
+
download_task = download_typhoeus_impl_async(file_remote_url, nil).then do |response|
|
221
|
+
case response.response_code
|
222
|
+
when 301
|
223
|
+
redirect_location = response.headers['location']
|
224
|
+
# debug "CDN: #{name} Redirecting from #{file_remote_url} to #{redirect_location}"
|
225
|
+
download_and_save_with_retries_async(partial_url, redirect_location, nil )
|
226
|
+
when 304
|
227
|
+
# debug "CDN: #{name} Relative path not modified: #{partial_url}"
|
228
|
+
# We need to update the file modification date, as it is later used for freshness
|
229
|
+
# optimization. See #initialize for more information.
|
230
|
+
FileUtils.touch path
|
231
|
+
partial_url
|
232
|
+
when 200
|
233
|
+
File.open(path, 'w') { |f| f.write(response.response_body.force_encoding('UTF-8')) }
|
234
|
+
|
235
|
+
# etag_new = response.headers['etag'] unless response.headers.nil?
|
236
|
+
# debug "CDN: #{name} Relative path downloaded: #{partial_url}, save ETag: #{etag_new}"
|
237
|
+
# File.open(etag_path, 'w') { |f| f.write(etag_new) } unless etag_new.nil?
|
238
|
+
partial_url
|
239
|
+
when 404
|
240
|
+
# debug "CDN: #{name} Relative path couldn't be downloaded: #{partial_url} Response: #{response.response_code}"
|
241
|
+
nil
|
242
|
+
when 502, 503, 504
|
243
|
+
# Retryable HTTP errors, usually related to server overloading
|
244
|
+
if retries <= 1
|
245
|
+
# raise Informative, "CDN: #{name} URL couldn't be downloaded: #{file_remote_url} Response: #{response.response_code} #{response.response_body}"
|
246
|
+
else
|
247
|
+
# debug "CDN: #{name} URL couldn't be downloaded: #{file_remote_url} Response: #{response.response_code} #{response.response_body}, retries: #{retries - 1}"
|
248
|
+
exponential_backoff_async(retries).then do
|
249
|
+
download_and_save_with_retries_async(partial_url, file_remote_url, nil , retries - 1)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
when 0
|
253
|
+
# Non-HTTP errors, usually network layer
|
254
|
+
if retries <= 1
|
255
|
+
raise Informative, "CDN: #{name} URL couldn't be downloaded: #{file_remote_url} Response: #{response.return_message}"
|
256
|
+
else
|
257
|
+
debug "CDN: #{name} URL couldn't be downloaded: #{file_remote_url} Response: #{response.return_message}, retries: #{retries - 1}"
|
258
|
+
exponential_backoff_async(retries).then do
|
259
|
+
download_and_save_with_retries_async(partial_url, file_remote_url, etag, retries - 1)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
else
|
263
|
+
raise Informative, "CDN: #{name} URL couldn't be downloaded: #{file_remote_url} Response: #{response.response_code} #{response.response_body}"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# Calling `Future#run` flattens the chained futures created by retries or redirects
|
268
|
+
#
|
269
|
+
# Does not, in fact, run the task - that is already happening in Hydra at this point
|
270
|
+
download_task.run
|
271
|
+
end
|
272
|
+
|
273
|
+
def exponential_backoff_async(retries)
|
274
|
+
sleep_async(backoff_time(retries))
|
275
|
+
end
|
276
|
+
|
277
|
+
def backoff_time(retries)
|
278
|
+
current_retry = MAX_NUMBER_OF_RETRIES - retries
|
279
|
+
4 * 2**current_retry
|
280
|
+
end
|
281
|
+
|
282
|
+
def sleep_async(seconds)
|
283
|
+
# Async sleep to avoid blocking either the main or the Hydra thread
|
284
|
+
Promises.schedule_on(HYDRA_EXECUTOR, seconds)
|
285
|
+
end
|
286
|
+
|
287
|
+
def download_typhoeus_impl_async(file_remote_url, etag)
|
288
|
+
# Create a prefereably HTTP/2 request - the protocol is ultimately responsible for picking
|
289
|
+
# the maximum supported protocol
|
290
|
+
# When debugging with proxy, use the following extra options:
|
291
|
+
# :proxy => 'http://localhost:8888',
|
292
|
+
# :ssl_verifypeer => false,
|
293
|
+
# :ssl_verifyhost => 0,
|
294
|
+
request = Typhoeus::Request.new(
|
295
|
+
file_remote_url,
|
296
|
+
:method => :get,
|
297
|
+
:http_version => :httpv2_0,
|
298
|
+
:timeout => 10,
|
299
|
+
:connecttimeout => 10,
|
300
|
+
:accept_encoding => 'gzip',
|
301
|
+
:netrc => :optional,
|
302
|
+
:netrc_file => Netrc.default_path,
|
303
|
+
:headers => etag.nil? ? {} : { 'If-None-Match' => etag },
|
304
|
+
)
|
305
|
+
|
306
|
+
future = Promises.resolvable_future_on(Concurrent::SingleThreadExecutor.new)
|
307
|
+
queue_request(request)
|
308
|
+
request.on_complete do |response|
|
309
|
+
future.fulfill(response)
|
310
|
+
end
|
311
|
+
|
312
|
+
# This `Future` should never reject, network errors are exposed on `Typhoeus::Response`
|
313
|
+
future
|
314
|
+
end
|
315
|
+
|
316
|
+
def queue_request(request)
|
317
|
+
@hydra ||= Typhoeus::Hydra.new
|
318
|
+
|
319
|
+
# Queue the request into the Hydra (libcurl reactor).
|
320
|
+
@hydra.queue(request)
|
321
|
+
|
322
|
+
# Cycle the reactor on a separate thread
|
323
|
+
#
|
324
|
+
# The way it works is that if more requests are queued while Hydra is in the `#run`
|
325
|
+
# method, it will keep executing them
|
326
|
+
#
|
327
|
+
# The upcoming calls to `#run` will simply run empty.
|
328
|
+
HYDRA_EXECUTOR.post(@hydra, &:run)
|
329
|
+
end
|
330
|
+
|
103
331
|
end
|
104
332
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cocoapods-nexus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mrdaios
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cocoapods
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.9.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: concurrent-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.1'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rest-client
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,19 +53,19 @@ dependencies:
|
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: 2.1.0
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: typhoeus
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
61
|
+
version: '1.0'
|
48
62
|
type: :runtime
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
68
|
+
version: '1.0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,7 @@ files:
|
|
108
122
|
- lib/cocoapods-nexus/hook/analyzer.rb
|
109
123
|
- lib/cocoapods-nexus/hook/installer.rb
|
110
124
|
- lib/cocoapods-nexus/hook/manager.rb
|
125
|
+
- lib/cocoapods-nexus/hook/specification.rb
|
111
126
|
- lib/cocoapods-nexus/nexus_source.rb
|
112
127
|
- lib/cocoapods_plugin.rb
|
113
128
|
- spec/command/nexus_spec.rb
|