cocoapods-nexus 0.0.3 → 0.0.8
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.
- 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.rb +0 -1
- data/lib/cocoapods-nexus/hook/manager.rb +8 -1
- data/lib/cocoapods-nexus/hook/specification.rb +19 -0
- data/lib/cocoapods-nexus/nexus_source.rb +252 -24
- metadata +20 -6
- data/lib/cocoapods-nexus/hook/installer.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ac4a898f34bf416710c9a860d1277a2b31e4724aa4227778db75a8a2fd66a50
|
4
|
+
data.tar.gz: 20eb9b143367130deb7da98ff04249773e5ca4ee92ef624b40ff79eb62a2416a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23514cadd69f45a3892775c5efb738a4173c4ee0e0edf5b7081a51a11cc7f141f611dbc1f56d3b914afd45852aea8729769c319cbfd46b88a3d332d313cb7040
|
7
|
+
data.tar.gz: 33d55877147c3bc40b7de688d3833d571cf324850ada1ef23c89f1712a1ca52c2fb1c2f29299f1a42d4fce15c6b7e0829a2ac60670eab6d3e3e381ad729b17fc
|
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.8'
|
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
|
data/lib/cocoapods-nexus/hook.rb
CHANGED
@@ -4,8 +4,9 @@ require 'cocoapods-nexus/nexus_source'
|
|
4
4
|
module Pod
|
5
5
|
class Source
|
6
6
|
class Manager
|
7
|
-
alias orgin_source_from_path source_from_path
|
8
7
|
|
8
|
+
alias orgin_source_from_path source_from_path
|
9
|
+
# 根据nexus配置文件加载source
|
9
10
|
def source_from_path(path)
|
10
11
|
@new_sources_by_path ||= Hash.new do |hash, key|
|
11
12
|
nexus_file_path = File.join(key, ".nexus")
|
@@ -17,6 +18,12 @@ module Pod
|
|
17
18
|
end
|
18
19
|
@new_sources_by_path[path]
|
19
20
|
end
|
21
|
+
|
22
|
+
alias orgin_source_with_url source_with_url
|
23
|
+
# 让nexus支持多repo
|
24
|
+
def source_with_url(url)
|
25
|
+
nil
|
26
|
+
end
|
20
27
|
end
|
21
28
|
end
|
22
29
|
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
|
@@ -88,11 +163,13 @@ module Pod
|
|
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
165
|
asset['downloadUrl'] if asset && asset['downloadUrl']
|
91
|
-
end
|
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.8
|
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-16 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
|
@@ -106,8 +120,8 @@ files:
|
|
106
120
|
- lib/cocoapods-nexus/downloader.rb
|
107
121
|
- lib/cocoapods-nexus/hook.rb
|
108
122
|
- lib/cocoapods-nexus/hook/analyzer.rb
|
109
|
-
- lib/cocoapods-nexus/hook/installer.rb
|
110
123
|
- lib/cocoapods-nexus/hook/manager.rb
|
124
|
+
- lib/cocoapods-nexus/hook/specification.rb
|
111
125
|
- lib/cocoapods-nexus/nexus_source.rb
|
112
126
|
- lib/cocoapods_plugin.rb
|
113
127
|
- spec/command/nexus_spec.rb
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# require 'cocoapods-core'
|
2
|
-
# require 'cocoapods-nexus/api'
|
3
|
-
|
4
|
-
# module Pod
|
5
|
-
# class Installer
|
6
|
-
# alias_method :old_root_specs, :root_specs
|
7
|
-
# def root_specs
|
8
|
-
# # 通过修改specs的source到nexus下载zip(不完美的解决方案)
|
9
|
-
# specs = old_root_specs
|
10
|
-
# specs = specs.map{|spec| modify_spec_if_find_last_version(spec)}
|
11
|
-
# specs
|
12
|
-
# end
|
13
|
-
|
14
|
-
# private
|
15
|
-
|
16
|
-
# def modify_spec_if_find_last_version(spec)
|
17
|
-
# attributes_hash = spec.attributes_hash
|
18
|
-
# spec_name = attributes_hash['name']
|
19
|
-
# spec_version = attributes_hash['version']
|
20
|
-
# artifacte = nexus_find_artifacte(spec_name: spec_name, spec_version: spec_version)
|
21
|
-
# if artifacte != nil
|
22
|
-
# asset_zip = artifacte['assets'].select{ |asset| asset['path'].end_with?('zip') }.first
|
23
|
-
# if asset_zip != nil
|
24
|
-
# attributes_hash['source'] = {
|
25
|
-
# 'http' => asset_zip['downloadUrl']
|
26
|
-
# }
|
27
|
-
# puts "Downloading #{spec_name}(#{spec_version})from nexus(#{asset_zip['downloadUrl']})"
|
28
|
-
# spec.attributes_hash = attributes_hash
|
29
|
-
# end
|
30
|
-
# end
|
31
|
-
# spec
|
32
|
-
# end
|
33
|
-
|
34
|
-
# def nexus_find_artifacte(spec_name:, spec_version:)
|
35
|
-
# artifacte = {}
|
36
|
-
# api.each do |api|
|
37
|
-
# artifactes = api.search_maven_component(artifact_id: spec_name)
|
38
|
-
# artifacte = artifactes.select{ |artifacte| artifacte['version'].start_with?(spec_version) }.sort_by{ |artifacte| artifacte['version'].downcase }.last
|
39
|
-
# break if artifacte != nil
|
40
|
-
# end
|
41
|
-
# artifacte
|
42
|
-
# end
|
43
|
-
|
44
|
-
# def api
|
45
|
-
# nexus_options = Pod::Config.instance.podfile.get_options || []
|
46
|
-
# @apis = @apis || nexus_options.map{|nexus| CocoapodsNexus::API.new(hostname: nexus['endpoint'], repo: nexus['repo'])}
|
47
|
-
# end
|
48
|
-
# end
|
49
|
-
# end
|