cocoapods-nexus-downloader 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3c8c852aa349b236b4cf219847aff4876ab6540ba4951ad91be9c22b74992962
4
+ data.tar.gz: a6d6d9dcad0fc4979ca7f62f115b373a7e8cbdfe6c94940a0935b78ac69d17ec
5
+ SHA512:
6
+ metadata.gz: 3524e18e04501317d01dac4b987213ffcd8ae78b4f4c61e612f282db11ccb076abcf5357929cc7823e890ea457c136aeb4fc5ad59f1bfb1efc1a74edbf65a83c
7
+ data.tar.gz: f126a15e3b06df0fda848ecdbd7bac822bb6be55c86985d0d2b79392f8fc447544a795761aadf9fdc54fc877ae4111e4ff46c542a9189c177d73d922562c1dfb
@@ -0,0 +1,44 @@
1
+ module Pod
2
+ class Command
3
+ # This is an example of a cocoapods plugin adding a top-level subcommand
4
+ # to the 'pod' command.
5
+ #
6
+ # You can also create subcommands of existing or new commands. Say you
7
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
8
+ # (e.g. `pod list deprecated`), there are a few things that would need
9
+ # to change.
10
+ #
11
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
12
+ # the class to exist in the the Pod::Command::List namespace
13
+ # - change this class to extend from `List` instead of `Command`. This
14
+ # tells the plugin system that it is a subcommand of `list`.
15
+ # - edit `lib/cocoapods_plugins.rb` to require this file
16
+ #
17
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
18
+ # in the `plugins.json` file, once your plugin is released.
19
+ #
20
+ class Nexus < Command
21
+ self.summary = 'Short description of cocoapods-nexus.'
22
+
23
+ self.description = <<-DESC
24
+ Longer description of cocoapods-Nexus.
25
+ DESC
26
+
27
+ self.arguments = 'NAME'
28
+
29
+ def initialize(argv)
30
+ @name = argv.shift_argument
31
+ super
32
+ end
33
+
34
+ def validate!
35
+ super
36
+ help! 'A Pod name is required.' unless @name
37
+ end
38
+
39
+ def run
40
+ UI.puts "Add your implementation for the cocoapods-nexus plugin in #{__FILE__}"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1 @@
1
+ require 'cocoapods-nexus-downloader/command/nexus'
@@ -0,0 +1,3 @@
1
+ module CocoapodsNexusDownloader
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'cocoapods-downloader'
2
+ require 'cocoapods-nexus-downloader/nexus-downloader'
3
+
4
+ module Pod
5
+ module Downloader
6
+ class <<self
7
+ alias_method :real_downloader_class_by_key, :downloader_class_by_key
8
+ end
9
+
10
+ def self.downloader_class_by_key
11
+ original = self.real_downloader_class_by_key
12
+ original[:nexus] = NexusDownloader
13
+ original
14
+ end
15
+
16
+ end
17
+ end
18
+
@@ -0,0 +1,256 @@
1
+ # require 'addressable'
2
+ require 'cocoapods-downloader'
3
+ require 'uri'
4
+ require 'net/http'
5
+ require 'json'
6
+
7
+ module Pod
8
+ module Downloader
9
+
10
+ class NexusDownloader < Base
11
+ def self.options
12
+ [:repo, :group, :artifact, :version, :type, :md5, :sha1,]
13
+ end
14
+
15
+ USER_AGENT_HEADER = 'User-Agent'.freeze
16
+
17
+ class UnsupportedFileTypeError < StandardError; end
18
+
19
+ private
20
+
21
+ executable :curl
22
+ # executable :mvn
23
+ executable :unzip
24
+ executable :tar
25
+ executable :hdiutil
26
+ # @return [String] the url of the remote source.
27
+ #
28
+ attr_accessor :filename, :download_path
29
+
30
+ def self.preprocess_options(options)
31
+
32
+ debug_puts "preprocess_options: #{options}"
33
+ artifact_item = self.request_artifact(options[:nexus], options)
34
+ debug_puts artifact_item
35
+ md5Val = artifact_item.checksum.md5
36
+
37
+ if options.key?(:md5)
38
+ raise "md5 value is not matched with remote file" unless options[:md5] == md5Val
39
+ else
40
+ options[:md5] = md5Val
41
+ end
42
+
43
+
44
+ # TODO: also check sha1
45
+ options
46
+ end
47
+
48
+ def self.request_artifact(url, options)
49
+
50
+ # https://stackoverflow.com/a/70596332/11884593
51
+ # http://192.168.138.192:8081/#admin/system/api
52
+ uri = URI("#{url}/service/rest/v1/search/assets")
53
+ params = {
54
+ 'sort' => 'version',
55
+ 'repository' => options[:repo],
56
+ 'maven.groupId' => options[:group],
57
+ 'maven.artifactId' => options[:artifact],
58
+ # maven don't allow '/' in version, so we replace it with '_' automatically
59
+ 'maven.baseVersion' => options[:version].gsub('/', '_'),
60
+ 'maven.extension' => options[:type],
61
+ 'prerelease' => false
62
+ }
63
+ uri.query = URI.encode_www_form(params)
64
+
65
+ debug_puts("uri: #{uri}")
66
+ res = Net::HTTP.get_response(uri)
67
+ raise DownloaderError, 'Search failed!' if res.is_a?(Net::HTTPError) || res.body.to_s.empty?
68
+ debug_puts "res.body: #{res.body.to_s}"
69
+
70
+ parsed_model = JSON.parse(res.body, object_class: OpenStruct)
71
+ raise DownloaderError, "Can't find matched artifact!" if parsed_model.items.empty?
72
+ debug_puts "aaa3: #{parsed_model.items.first}"
73
+ parsed_model.items.to_a.first
74
+
75
+ end
76
+
77
+ def download!
78
+ @filename = filename_with_type(type)
79
+ @download_path = target_path + @filename
80
+ download_file(@download_path)
81
+ verify_checksum(@download_path)
82
+ extract_with_type(@download_path, type)
83
+ end
84
+
85
+ def type
86
+ if options[:type]
87
+ options[:type].to_sym
88
+ else
89
+ type_with_url(url)
90
+ end
91
+ end
92
+
93
+ def headers
94
+ options[:headers]
95
+ end
96
+
97
+ # @note The archive is flattened if it contains only one folder and its
98
+ # extension is either `tgz`, `tar`, `tbz` or the options specify
99
+ # it.
100
+ #
101
+ # @return [Bool] Whether the archive should be flattened if it contains
102
+ # only one folder.
103
+ #
104
+ def should_flatten?
105
+ if options.key?(:flatten)
106
+ options[:flatten]
107
+ elsif %i[tgz tar tbz txz].include?(type)
108
+ true # those archives flatten by default
109
+ else
110
+ false # all others (actually only .zip) default not to flatten
111
+ end
112
+ end
113
+
114
+ def type_with_url(url)
115
+ case URI.parse(url).path
116
+ when /\.zip$/
117
+ :zip
118
+ when /\.(tgz|tar\.gz)$/
119
+ :tgz
120
+ when /\.tar$/
121
+ :tar
122
+ when /\.(tbz|tar\.bz2)$/
123
+ :tbz
124
+ when /\.(txz|tar\.xz)$/
125
+ :txz
126
+ when /\.dmg$/
127
+ :dmg
128
+ end
129
+ end
130
+
131
+ def filename_with_type(type = :zip)
132
+ case type
133
+ when :zip, :tgz, :tar, :tbz, :txz, :dmg
134
+ "file.#{type}"
135
+ else
136
+ raise UnsupportedFileTypeError, "Unsupported file type: #{type}"
137
+ end
138
+ end
139
+
140
+ def extract_with_type(full_filename, type = :zip)
141
+ unpack_from = full_filename
142
+ unpack_to = @target_path
143
+
144
+ case type
145
+ when :zip
146
+ unzip! unpack_from, '-d', unpack_to
147
+ when :tar, :tgz, :tbz, :txz
148
+ tar! 'xf', unpack_from, '-C', unpack_to
149
+ when :dmg
150
+ extract_dmg(unpack_from, unpack_to)
151
+ else
152
+ raise UnsupportedFileTypeError, "Unsupported file type: #{type}"
153
+ end
154
+
155
+ # If the archive is a tarball and it only contained a folder, move its
156
+ # contents to the target (#727)
157
+ #
158
+ if should_flatten?
159
+ contents = target_path.children
160
+ contents.delete(target_path + @filename)
161
+ entry = contents.first
162
+ if contents.count == 1 && entry.directory?
163
+ tmp_entry = entry.sub_ext("#{entry.extname}.tmp")
164
+ begin
165
+ FileUtils.move(entry, tmp_entry)
166
+ FileUtils.move(tmp_entry.children, target_path)
167
+ ensure
168
+ FileUtils.remove_entry(tmp_entry)
169
+ end
170
+ end
171
+ end
172
+
173
+ FileUtils.rm(unpack_from) if File.exist?(unpack_from)
174
+ end
175
+
176
+ def extract_dmg(unpack_from, unpack_to)
177
+ require 'rexml/document'
178
+ plist_s = hdiutil! 'attach', '-plist', '-nobrowse', unpack_from, '-mountrandom', unpack_to
179
+ plist = REXML::Document.new plist_s
180
+ xpath = '//key[.="mount-point"]/following-sibling::string'
181
+ mount_point = REXML::XPath.first(plist, xpath).text
182
+ FileUtils.cp_r(Dir.glob(mount_point + '/*'), unpack_to)
183
+ hdiutil! 'detach', mount_point
184
+ end
185
+
186
+ def compare_hash(filename, hasher, hash)
187
+ incremental_hash = hasher.new
188
+
189
+ File.open(filename, 'rb') do |file|
190
+ buf = ''
191
+ incremental_hash << buf while file.read(1024, buf)
192
+ end
193
+
194
+ computed_hash = incremental_hash.hexdigest
195
+
196
+ return unless computed_hash != hash
197
+
198
+ raise DownloaderError, 'Verification checksum was incorrect, ' \
199
+ "expected #{hash}, got #{computed_hash}"
200
+ end
201
+
202
+ # Verify that the downloaded file matches a sha1 hash
203
+ #
204
+ def verify_sha1_hash(filename, hash)
205
+ require 'digest/sha1'
206
+ compare_hash(filename, Digest::SHA1, hash)
207
+ end
208
+
209
+ # Verify that the downloaded file matches a sha256 hash
210
+ #
211
+ def verify_sha256_hash(filename, hash)
212
+ require 'digest/sha2'
213
+ compare_hash(filename, Digest::SHA2, hash)
214
+ end
215
+
216
+ # Verify that the downloaded file matches the hash if set
217
+ #
218
+ def verify_checksum(filename)
219
+ if options[:sha256]
220
+ verify_sha256_hash(filename, options[:sha256])
221
+ elsif options[:sha1]
222
+ verify_sha1_hash(filename, options[:sha1])
223
+ end
224
+ end
225
+
226
+ def download_file(download_path)
227
+ debug_puts "hl: download_file: #{download_path}"
228
+ artifact_item = NexusDownloader.request_artifact(url, options)
229
+ source_url = artifact_item.downloadUrl
230
+ parameters = ['-f', '-L', '-o', download_path, source_url, '--create-dirs', '--netrc-optional', '--retry', '2']
231
+ parameters << user_agent_argument if headers.nil? ||
232
+ headers.none? { |header| header.casecmp(USER_AGENT_HEADER).zero? }
233
+
234
+ unless headers.nil?
235
+ headers.each do |h|
236
+ parameters << '-H'
237
+ parameters << h
238
+ end
239
+ end
240
+
241
+ debug_puts "curl parameters: #{parameters}"
242
+ curl! parameters
243
+ end
244
+
245
+ # Returns a cURL command flag to add the CocoaPods User-Agent.
246
+ #
247
+ # @return [String] cURL command -A flag and User-Agent.
248
+ #
249
+ def user_agent_argument
250
+ debug_puts "1"
251
+ "-A '#{Http.user_agent_string}'"
252
+ end
253
+
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,23 @@
1
+ def debug_puts(content)
2
+ return unless CocoapodsNexusDownloader.debug
3
+
4
+ puts content
5
+ end
6
+
7
+ module CocoapodsNexusDownloader
8
+ class << self
9
+ # @return [Bool] the url of the remote source.
10
+ #
11
+ attr_accessor :debug
12
+
13
+ Pod::HooksManager.register('cocoapods-nexus-downloader', :pre_install) do |_context, options|
14
+ CocoapodsNexusDownloader.pre_install(options)
15
+ end
16
+
17
+ def pre_install(options)
18
+ debug_puts "pre_install hook: #{options}"
19
+ # Now we can configure the downloader to use the Azure CLI for downloading pods from the given hosts
20
+ @debug = options.fetch(:debug, false)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ require 'cocoapods-nexus-downloader/gem_version'
2
+ require 'cocoapods-nexus-downloader/pre-install'
3
+ require 'cocoapods-nexus-downloader/hook-cocoapods-downloader'
@@ -0,0 +1 @@
1
+ require 'cocoapods-nexus-downloader'
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cocoapods-nexus-downloader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Hanley Lee
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Host the pod's framework file on Nexus and download it using ':nexus'.
42
+ email:
43
+ - hanley.lei@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/cocoapods-nexus-downloader.rb
49
+ - lib/cocoapods-nexus-downloader/command.rb
50
+ - lib/cocoapods-nexus-downloader/command/nexus.rb
51
+ - lib/cocoapods-nexus-downloader/gem_version.rb
52
+ - lib/cocoapods-nexus-downloader/hook-cocoapods-downloader.rb
53
+ - lib/cocoapods-nexus-downloader/nexus-downloader.rb
54
+ - lib/cocoapods-nexus-downloader/pre-install.rb
55
+ - lib/cocoapods_plugin.rb
56
+ homepage: https://github.com/hanleylee/cocoapods-nexus-downloader
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.4.10
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: A CocoaPods plugin that enables referencing a pod using ':nexus' and downloading
79
+ it from Nexus in maven type.
80
+ test_files: []