nexus_cli_nx 4.1.2
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 +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile +41 -0
- data/Guardfile +27 -0
- data/LICENSE +15 -0
- data/README.md +123 -0
- data/Rakefile +1 -0
- data/Thorfile +66 -0
- data/VERSION +1 -0
- data/bin/nexus-cli +10 -0
- data/data/pom.xml.erb +13 -0
- data/features/nexus_oss.feature +259 -0
- data/features/pro/nexus_custom_metadata.feature +116 -0
- data/features/pro/nexus_pro.feature +101 -0
- data/features/step_definitions/cli_steps.rb +105 -0
- data/features/support/env.rb +64 -0
- data/lib/nexus_cli.rb +44 -0
- data/lib/nexus_cli/artifact.rb +44 -0
- data/lib/nexus_cli/base_remote.rb +16 -0
- data/lib/nexus_cli/cli.rb +7 -0
- data/lib/nexus_cli/configuration.rb +101 -0
- data/lib/nexus_cli/connection.rb +84 -0
- data/lib/nexus_cli/errors.rb +259 -0
- data/lib/nexus_cli/mixins/artifact_actions.rb +239 -0
- data/lib/nexus_cli/mixins/global_settings_actions.rb +64 -0
- data/lib/nexus_cli/mixins/logging_actions.rb +45 -0
- data/lib/nexus_cli/mixins/pro/custom_metadata_actions.rb +176 -0
- data/lib/nexus_cli/mixins/pro/smart_proxy_actions.rb +219 -0
- data/lib/nexus_cli/mixins/repository_actions.rb +245 -0
- data/lib/nexus_cli/mixins/user_actions.rb +125 -0
- data/lib/nexus_cli/n3_metadata.rb +77 -0
- data/lib/nexus_cli/remote/oss_remote.rb +11 -0
- data/lib/nexus_cli/remote/pro_remote.rb +59 -0
- data/lib/nexus_cli/remote_factory.rb +30 -0
- data/lib/nexus_cli/tasks.rb +507 -0
- data/lib/nexus_cli/version.rb +6 -0
- data/nexus_cli_nx.gemspec +32 -0
- data/spec/fixtures/metadata_search.xml +10 -0
- data/spec/fixtures/nexus.config +4 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/unit/nexus_cli/artifact_spec.rb +82 -0
- data/spec/unit/nexus_cli/configuration_spec.rb +159 -0
- data/spec/unit/nexus_cli/mixins/pro/custom_metadata_actions_spec.rb +21 -0
- data/spec/unit/nexus_cli/oss_remote_spec.rb +83 -0
- data/spec/unit/nexus_cli/pro_remote_spec.rb +110 -0
- data/spec/unit/nexus_cli/remote_factory_spec.rb +42 -0
- metadata +263 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module NexusCli
|
5
|
+
# @author Kyle Allan <kallan@riotgames.com>
|
6
|
+
module ArtifactActions
|
7
|
+
|
8
|
+
# Retrieves a file from the Nexus server using the given [String]
|
9
|
+
# coordinates. Optionally provide a destination [String].
|
10
|
+
#
|
11
|
+
# @param [String] coordinates
|
12
|
+
# @param [String] destination
|
13
|
+
#
|
14
|
+
# @return [Hash] Some information about the artifact that was pulled.
|
15
|
+
def pull_artifact(coordinates, destination=nil)
|
16
|
+
artifact = Artifact.new(coordinates)
|
17
|
+
|
18
|
+
if artifact.version.casecmp("latest")
|
19
|
+
artifact.version = REXML::Document.new(get_artifact_info(coordinates)).elements["//version"].text
|
20
|
+
end
|
21
|
+
|
22
|
+
file_name = artifact.file_name
|
23
|
+
destination = File.join(File.expand_path(destination || "."), file_name)
|
24
|
+
query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
|
25
|
+
query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
|
26
|
+
response = nexus.get(nexus_url("service/local/artifact/maven/redirect"), :query => query)
|
27
|
+
case response.status
|
28
|
+
when 301, 307
|
29
|
+
# Follow redirect and stream in chunks.
|
30
|
+
artifact_file = File.open(destination, "wb") do |io|
|
31
|
+
nexus.get(response.content.gsub(/If you are not automatically redirected use this url: /, "")) do |chunk|
|
32
|
+
io.write(chunk)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
when 404
|
36
|
+
raise ArtifactNotFoundException
|
37
|
+
else
|
38
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
39
|
+
end
|
40
|
+
{
|
41
|
+
:file_name => file_name,
|
42
|
+
:file_path => File.expand_path(destination),
|
43
|
+
:version => artifact.version,
|
44
|
+
:size => File.size(File.expand_path(destination))
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Pushes the given [file] to the Nexus server
|
49
|
+
# under the given [artifact] identifier.
|
50
|
+
#
|
51
|
+
# @param coordinates [String] the Maven identifier
|
52
|
+
# @param file [type] the path to the file
|
53
|
+
#
|
54
|
+
# @return [Boolean] returns true when successful
|
55
|
+
def push_artifact(coordinates, file)
|
56
|
+
artifact = Artifact.new(coordinates)
|
57
|
+
put_string = "content/repositories/#{configuration['repository']}/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}/#{artifact.version}/#{artifact.file_name}"
|
58
|
+
response = nexus.put(nexus_url(put_string), File.open(file))
|
59
|
+
|
60
|
+
case response.status
|
61
|
+
when 201
|
62
|
+
pom_name = "#{artifact.artifact_id}-#{artifact.version}.pom"
|
63
|
+
put_string = "content/repositories/#{configuration['repository']}/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}/#{artifact.version}/#{pom_name}"
|
64
|
+
pom_file = generate_fake_pom(pom_name, artifact)
|
65
|
+
nexus.put(nexus_url(put_string), File.open(pom_file))
|
66
|
+
delete_string = "/service/local/metadata/repositories/#{configuration['repository']}/content/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}"
|
67
|
+
nexus.delete(nexus_url(delete_string))
|
68
|
+
return true
|
69
|
+
when 400
|
70
|
+
raise BadUploadRequestException
|
71
|
+
when 401
|
72
|
+
raise PermissionsException
|
73
|
+
when 403
|
74
|
+
raise PermissionsException
|
75
|
+
when 404
|
76
|
+
raise NexusHTTP404.new(response.content)
|
77
|
+
else
|
78
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def delete_artifact(coordinates)
|
83
|
+
artifact = Artifact.new(coordinates)
|
84
|
+
response = nexus.delete(nexus_url("content/repositories/#{configuration['repository']}/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}/#{artifact.version}"))
|
85
|
+
case response.status
|
86
|
+
when 204
|
87
|
+
return true
|
88
|
+
else
|
89
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Retrieves information about the given [artifact] and returns
|
95
|
+
# it in as a [String] of XML.
|
96
|
+
#
|
97
|
+
# @param coordinates [String] the Maven identifier
|
98
|
+
#
|
99
|
+
# @return [String] A string of XML data about the desired artifact
|
100
|
+
def get_artifact_info(coordinates)
|
101
|
+
artifact = Artifact.new(coordinates)
|
102
|
+
query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
|
103
|
+
query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
|
104
|
+
response = nexus.get(nexus_url("service/local/artifact/maven/resolve"), query)
|
105
|
+
case response.status
|
106
|
+
when 200
|
107
|
+
return response.content
|
108
|
+
when 404
|
109
|
+
raise ArtifactNotFoundException
|
110
|
+
when 503
|
111
|
+
raise CouldNotConnectToNexusException
|
112
|
+
else
|
113
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# Searches for an artifact using the given identifier.
|
119
|
+
#
|
120
|
+
# @param coordinates [String] the Maven identifier
|
121
|
+
# @example com.artifact:my-artifact
|
122
|
+
#
|
123
|
+
# @return [Array<String>] a formatted Array of results
|
124
|
+
# @example
|
125
|
+
# 1.0.0 `nexus-cli pull com.artifact:my-artifact:tgz:1.0.0`
|
126
|
+
# 2.0.0 `nexus-cli pull com.artifact:my-artifact:tgz:2.0.0`
|
127
|
+
# 3.0.0 `nexus-cli pull com.artifact:my-artifact:tgz:3.0.0`
|
128
|
+
def search_for_artifacts(coordinates)
|
129
|
+
group_id, artifact_id = coordinates.split(":")
|
130
|
+
response = nexus.get(nexus_url("service/local/data_index"), :query => {:g => group_id, :a => artifact_id})
|
131
|
+
case response.status
|
132
|
+
when 200
|
133
|
+
return response.content
|
134
|
+
else
|
135
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Searches for an artifact using the lucene indexer.
|
140
|
+
# requires UI: Search role
|
141
|
+
# https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/path__lucene_search.html
|
142
|
+
#
|
143
|
+
# @param coordinates [String] the Maven identifier
|
144
|
+
# @example com.artifact:my-artifact:jar:4.9.*
|
145
|
+
#
|
146
|
+
# @return [String]
|
147
|
+
def search_artifacts_lucene(coordinates)
|
148
|
+
artifact = Artifact.new(coordinates)
|
149
|
+
query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
|
150
|
+
query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
|
151
|
+
response = nexus.get(nexus_url("service/local/lucene/search"), query)
|
152
|
+
case response.status
|
153
|
+
when 200
|
154
|
+
return response.content
|
155
|
+
else
|
156
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def transfer_artifact(coordinates, from_repository, to_repository)
|
161
|
+
do_transfer_artifact(coordinates, from_repository, to_repository)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Gets the Nexus download URL for the given [artifact].
|
165
|
+
#
|
166
|
+
# @param coordinates [String] the Maven identifier
|
167
|
+
# @example com.artifact:my-artifact
|
168
|
+
#
|
169
|
+
# @return [String] The Nexus download url for the artifact
|
170
|
+
# @example
|
171
|
+
# https://nexus.my-domain.com/content/repositories/my-repository/my-artifact/1.0.0/my-artifact-1.0.0.tgz
|
172
|
+
def get_artifact_download_url(coordinates)
|
173
|
+
artifact = Artifact.new(coordinates)
|
174
|
+
query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
|
175
|
+
query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
|
176
|
+
response = nexus.get(nexus_url("service/local/artifact/maven/redirect"), :query => query)
|
177
|
+
case response.status
|
178
|
+
when 301, 307
|
179
|
+
# Follow redirect and return download URL.
|
180
|
+
return response.content.gsub(/If you are not automatically redirected use this url: /, "")
|
181
|
+
when 404
|
182
|
+
raise ArtifactNotFoundException
|
183
|
+
else
|
184
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
# Formats the given XML into an [Array<String>] so it
|
191
|
+
# can be displayed nicely.
|
192
|
+
#
|
193
|
+
# @param doc [REXML::Document] the xml search results
|
194
|
+
# @param group_id [String] the group id
|
195
|
+
# @param artifact_id [String] the artifact id
|
196
|
+
#
|
197
|
+
# @return [type] [description]
|
198
|
+
def format_search_results(doc, group_id, artifact_id)
|
199
|
+
|
200
|
+
versions = []
|
201
|
+
REXML::XPath.each(doc, "//version") { |matched_version| versions << matched_version.text }
|
202
|
+
if versions.length > 0
|
203
|
+
indent_size = versions.max{|a,b| a.length <=> b.length}.size+4
|
204
|
+
formated_results = ['Found Versions:']
|
205
|
+
versions.inject(formated_results) do |array,version|
|
206
|
+
temp_version = version + ":"
|
207
|
+
array << "#{temp_version.ljust(indent_size)} `nexus-cli pull #{group_id}:#{artifact_id}:#{version}:tgz`"
|
208
|
+
end
|
209
|
+
else
|
210
|
+
formated_results = ['No Versions Found.']
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Transfers an artifact from one repository
|
215
|
+
# to another. Sometimes called a `promotion`
|
216
|
+
#
|
217
|
+
# @param coordinates [String] a Maven identifier
|
218
|
+
# @param from_repository [String] the name of the from repository
|
219
|
+
# @param to_repository [String] the name of the to repository
|
220
|
+
#
|
221
|
+
# @return [Boolean] returns true when successful
|
222
|
+
def do_transfer_artifact(coordinates, from_repository, to_repository)
|
223
|
+
Dir.mktmpdir do |temp_dir|
|
224
|
+
configuration["repository"] = sanitize_for_id(from_repository)
|
225
|
+
artifact_file = pull_artifact(coordinates, temp_dir)
|
226
|
+
configuration["repository"] = sanitize_for_id(to_repository)
|
227
|
+
push_artifact(coordinates, artifact_file[:file_path])
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def generate_fake_pom(pom_name, artifact)
|
232
|
+
Tempfile.open(pom_name) do |file|
|
233
|
+
template_path = File.join(NexusCli.root, "data", "pom.xml.erb")
|
234
|
+
file.puts ERB.new(File.read(template_path)).result(binding)
|
235
|
+
file
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module NexusCli
|
4
|
+
# @author Kyle Allan <kallan@riotgames.com>
|
5
|
+
module GlobalSettingsActions
|
6
|
+
|
7
|
+
# Retrieves the global settings of the Nexus server
|
8
|
+
#
|
9
|
+
# @return [File] a File with the global settings.
|
10
|
+
def get_global_settings
|
11
|
+
json = get_global_settings_json
|
12
|
+
pretty_json = JSON.pretty_generate(JSON.parse(json))
|
13
|
+
Dir.mkdir(File.expand_path("~/.nexus")) unless Dir.exists?(File.expand_path("~/.nexus"))
|
14
|
+
destination = File.join(File.expand_path("~/.nexus"), "global_settings.json")
|
15
|
+
artifact_file = File.open(destination, 'wb') do |file|
|
16
|
+
file.write(pretty_json)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_global_settings_json
|
21
|
+
response = nexus.get(nexus_url("service/local/global_settings/current"), :header => DEFAULT_ACCEPT_HEADER)
|
22
|
+
case response.status
|
23
|
+
when 200
|
24
|
+
return response.content
|
25
|
+
else
|
26
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def upload_global_settings(json=nil)
|
31
|
+
global_settings = nil
|
32
|
+
if json == nil
|
33
|
+
global_settings = File.read(File.join(File.expand_path("~/.nexus"), "global_settings.json"))
|
34
|
+
else
|
35
|
+
global_settings = json
|
36
|
+
end
|
37
|
+
response = nexus.put(nexus_url("service/local/global_settings/current"), :body => global_settings, :header => DEFAULT_CONTENT_TYPE_HEADER)
|
38
|
+
case response.status
|
39
|
+
when 204
|
40
|
+
return true
|
41
|
+
when 400
|
42
|
+
raise BadSettingsException.new(response.content)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def reset_global_settings
|
47
|
+
response = nexus.get(nexus_url("service/local/global_settings/default"), :header => DEFAULT_ACCEPT_HEADER)
|
48
|
+
case response.status
|
49
|
+
when 200
|
50
|
+
default_json = response.content
|
51
|
+
else
|
52
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
53
|
+
end
|
54
|
+
|
55
|
+
response = nexus.put(nexus_url("service/local/global_settings/current"), :body => default_json, :header => DEFAULT_CONTENT_TYPE_HEADER)
|
56
|
+
case response.status
|
57
|
+
when 204
|
58
|
+
return true
|
59
|
+
else
|
60
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module NexusCli
|
2
|
+
# @author Kyle Allan <kallan@riotgames.com>
|
3
|
+
module LoggingActions
|
4
|
+
|
5
|
+
# Gets information about the current logging
|
6
|
+
# levels in Nexus.
|
7
|
+
#
|
8
|
+
#
|
9
|
+
# @return [String] a String of JSON representing the current logging levels of Nexus
|
10
|
+
def get_logging_info
|
11
|
+
response = nexus.get(nexus_url("service/local/log/config"), :header => DEFAULT_ACCEPT_HEADER)
|
12
|
+
case response.status
|
13
|
+
when 200
|
14
|
+
return response.content
|
15
|
+
else
|
16
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# Sets the logging level of Nexus to one of
|
22
|
+
# "INFO", "DEBUG", or "ERROR".
|
23
|
+
#
|
24
|
+
# @param level [String] the logging level to set
|
25
|
+
#
|
26
|
+
# @return [Boolean] true if the logging level has been set, false otherwise
|
27
|
+
def set_logger_level(level)
|
28
|
+
raise InvalidLoggingLevelException unless ["INFO", "DEBUG", "ERROR"].include?(level.upcase)
|
29
|
+
response = nexus.put(nexus_url("service/local/log/config"), :body => create_logger_level_json(level), :header => DEFAULT_CONTENT_TYPE_HEADER)
|
30
|
+
case response.status
|
31
|
+
when 200
|
32
|
+
return true
|
33
|
+
else
|
34
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def create_logger_level_json(level)
|
41
|
+
params = {:rootLoggerLevel => level.upcase}
|
42
|
+
JSON.dump(:data => params)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module NexusCli
|
2
|
+
# @author Kyle Allan <kallan@riotgames.com>
|
3
|
+
module CustomMetadataActions
|
4
|
+
|
5
|
+
# Gets the custom metadata for an artifact
|
6
|
+
# @param [String] coordinates The GAVE string of the artifact
|
7
|
+
# @result [String] The resulting custom metadata xml from the get operation
|
8
|
+
def get_artifact_custom_info_raw(coordinates)
|
9
|
+
artifact = Artifact.new(coordinates)
|
10
|
+
encoded_string = N3Metadata::create_base64_subject(artifact)
|
11
|
+
response = nexus.get(nexus_url("service/local/index/custom_metadata/#{configuration['repository']}/#{encoded_string}"))
|
12
|
+
case response.status
|
13
|
+
when 200
|
14
|
+
if N3Metadata::missing_custom_metadata?(response.content)
|
15
|
+
raise N3NotFoundException
|
16
|
+
else
|
17
|
+
return response.content
|
18
|
+
end
|
19
|
+
when 404
|
20
|
+
raise ArtifactNotFoundException
|
21
|
+
else
|
22
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Gets the custom metadata for an artifact in a simplified XML format
|
27
|
+
# @param [String] coordinates The GAVE string of the artifact
|
28
|
+
# @result [String] The resulting custom metadata xml from the get operation
|
29
|
+
def get_artifact_custom_info(coordinates)
|
30
|
+
N3Metadata::convert_result_to_simple_xml(get_artifact_custom_info_raw(coordinates))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Updates custom metadata for an artifact
|
34
|
+
# @param [String] coordinates The GAVE string of the artifact
|
35
|
+
# @param [Array] *params The array of key:value strings
|
36
|
+
# @result [Integer] The resulting exit code of the operation
|
37
|
+
def update_artifact_custom_info(coordinates, *params)
|
38
|
+
target_n3 = parse_custom_metadata_update_params(*params)
|
39
|
+
nexus_n3 = get_custom_metadata_hash(coordinates)
|
40
|
+
|
41
|
+
do_update_custom_metadata(coordinates, nexus_n3, target_n3)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Clears all custom metadata from an artifact
|
45
|
+
# @param [String] The GAVE string of the artifact
|
46
|
+
# @result [Integer] The resulting exit code of the operation
|
47
|
+
def clear_artifact_custom_info(coordinates)
|
48
|
+
get_artifact_custom_info(coordinates) # Check that artifact has custom metadata
|
49
|
+
artifact = Artifact.new(coordinates)
|
50
|
+
encoded_string = N3Metadata::create_base64_subject(artifact)
|
51
|
+
response = nexus.post(nexus_url("service/local/index/custom_metadata/#{configuration['repository']}/#{encoded_string}"), :body => create_custom_metadata_clear_json, :header => DEFAULT_CONTENT_TYPE_HEADER)
|
52
|
+
case response.status
|
53
|
+
when 201
|
54
|
+
return true
|
55
|
+
else
|
56
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Searches for artifacts using custom metadata
|
61
|
+
# @param [Array] *params The array of key:type:value strings
|
62
|
+
# @result [String] The resulting xml from the search
|
63
|
+
def search_artifacts_custom(*params)
|
64
|
+
nodesets = Array.new
|
65
|
+
parse_custom_metadata_search_params(*params).each do |param|
|
66
|
+
response = nexus.get(nexus_url("service/local/search/m2/freeform"), :query => {:p => param[0], :t => param[1], :v => param[2]})
|
67
|
+
case response.status
|
68
|
+
when 200
|
69
|
+
nodesets.push(REXML::Document.new(response.body).elements["/search-results/data"])
|
70
|
+
when 400
|
71
|
+
raise BadSearchRequestException
|
72
|
+
when 404
|
73
|
+
raise ArtifactNotFoundException
|
74
|
+
else
|
75
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
# Perform array intersection across all NodeSets for the final common set.
|
79
|
+
result = nodesets.inject(nodesets.first) {|memo, nodeset| get_common_artifact_set(memo, nodeset)}
|
80
|
+
formatter = REXML::Formatters::Pretty.new(4)
|
81
|
+
formatter.compact = true
|
82
|
+
return result.nil? ? "" : formatter.write(result, "")
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def get_custom_metadata_hash(coordinates)
|
88
|
+
begin
|
89
|
+
N3Metadata::convert_result_to_hash(get_artifact_custom_info_raw(coordinates))
|
90
|
+
rescue N3NotFoundException
|
91
|
+
Hash.new
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def do_update_custom_metadata(coordinates, source_metadata, target_metadata)
|
96
|
+
artifact = Artifact.new(coordinates)
|
97
|
+
encoded_string = N3Metadata::create_base64_subject(artifact)
|
98
|
+
response = nexus.post(nexus_url("service/local/index/custom_metadata/#{configuration['repository']}/#{encoded_string}"), :body => create_custom_metadata_update_json(source_metadata, target_metadata), :header => DEFAULT_CONTENT_TYPE_HEADER)
|
99
|
+
case response.code
|
100
|
+
when 201
|
101
|
+
return true
|
102
|
+
else
|
103
|
+
raise UnexpectedStatusCodeException.new(response.status)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Converts an array of parameters used to update custom metadata
|
108
|
+
# @param [Array] *params The array of key:value strings
|
109
|
+
# @return [Hash] The resulting hash of parsed key:value items
|
110
|
+
# @example
|
111
|
+
# parse_custom_metadata_update_params(["cookie:oatmeal raisin"]) #=> {"cookie"=>"oatmeal raisin"}
|
112
|
+
def parse_custom_metadata_update_params(*params)
|
113
|
+
params.inject({}) do |parsed_params, param|
|
114
|
+
# param = key:value
|
115
|
+
metadata_key, metadata_value = param.split(":", 2)
|
116
|
+
if N3Metadata::valid_n3_key?(metadata_key) && N3Metadata::valid_n3_value?(metadata_value)
|
117
|
+
parsed_params[metadata_key] = metadata_value
|
118
|
+
else
|
119
|
+
raise N3ParameterMalformedException
|
120
|
+
end
|
121
|
+
parsed_params
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Converts an array of parameters used to search by custom metadata
|
126
|
+
# @param [Array] *params The array of key:type:value strings
|
127
|
+
# @result [Array] The resulting array of parsed key:type:value items
|
128
|
+
# @example
|
129
|
+
# parse_custom_metadata_search_params(["cookie:matches:oatmeal raisin"]) #=> #=> [["cookie","matches","oatmeal raisin"]]
|
130
|
+
def parse_custom_metadata_search_params(*params)
|
131
|
+
params.inject([]) do |parsed_params, param|
|
132
|
+
# param = key:type:value
|
133
|
+
metadata_key, search_type, metadata_value = param.split(":", 3)
|
134
|
+
if N3Metadata::valid_n3_key?(metadata_key) && N3Metadata::valid_n3_value?(metadata_value) && N3Metadata::valid_n3_search_type?(search_type)
|
135
|
+
parsed_params.push([metadata_key, search_type, metadata_value])
|
136
|
+
else
|
137
|
+
raise SearchParameterMalformedException
|
138
|
+
end
|
139
|
+
parsed_params
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def create_custom_metadata_update_json(source, target)
|
144
|
+
JSON.dump(:data => N3Metadata::create_metadata_hash(source, target))
|
145
|
+
end
|
146
|
+
|
147
|
+
def create_custom_metadata_clear_json
|
148
|
+
JSON.dump(:data => {})
|
149
|
+
end
|
150
|
+
|
151
|
+
# Gets the intersection of two artifact arrays, returning the common set
|
152
|
+
#
|
153
|
+
# @param [REXML::Document] left_document, right_document
|
154
|
+
# The two REXML::Document objects to intersect
|
155
|
+
#
|
156
|
+
# @result [REXML::Document nil]
|
157
|
+
# The resulting object generated from the intersectection or nil
|
158
|
+
def get_common_artifact_set(left_document, right_document)
|
159
|
+
intersection = get_artifact_array(left_document) & get_artifact_array(right_document)
|
160
|
+
return intersection.count > 0 ? REXML::Document.new("<data>#{intersection.join}</data>").root : nil
|
161
|
+
end
|
162
|
+
|
163
|
+
# Collect <artifact> elements into an array
|
164
|
+
#
|
165
|
+
# @info This will allow use of array intersection to find common artifacts in searches
|
166
|
+
#
|
167
|
+
# @param [REXML::Document] document The object to be divided by <artifact> elements
|
168
|
+
#
|
169
|
+
# @result [Array<String>] The result array of artifact elements
|
170
|
+
def get_artifact_array(document)
|
171
|
+
artifacts = []
|
172
|
+
REXML::XPath.each(document, "//artifact") { |matched_artifact| artifacts << matched_artifact.text }
|
173
|
+
artifacts
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|