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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG.md +23 -0
  5. data/Gemfile +41 -0
  6. data/Guardfile +27 -0
  7. data/LICENSE +15 -0
  8. data/README.md +123 -0
  9. data/Rakefile +1 -0
  10. data/Thorfile +66 -0
  11. data/VERSION +1 -0
  12. data/bin/nexus-cli +10 -0
  13. data/data/pom.xml.erb +13 -0
  14. data/features/nexus_oss.feature +259 -0
  15. data/features/pro/nexus_custom_metadata.feature +116 -0
  16. data/features/pro/nexus_pro.feature +101 -0
  17. data/features/step_definitions/cli_steps.rb +105 -0
  18. data/features/support/env.rb +64 -0
  19. data/lib/nexus_cli.rb +44 -0
  20. data/lib/nexus_cli/artifact.rb +44 -0
  21. data/lib/nexus_cli/base_remote.rb +16 -0
  22. data/lib/nexus_cli/cli.rb +7 -0
  23. data/lib/nexus_cli/configuration.rb +101 -0
  24. data/lib/nexus_cli/connection.rb +84 -0
  25. data/lib/nexus_cli/errors.rb +259 -0
  26. data/lib/nexus_cli/mixins/artifact_actions.rb +239 -0
  27. data/lib/nexus_cli/mixins/global_settings_actions.rb +64 -0
  28. data/lib/nexus_cli/mixins/logging_actions.rb +45 -0
  29. data/lib/nexus_cli/mixins/pro/custom_metadata_actions.rb +176 -0
  30. data/lib/nexus_cli/mixins/pro/smart_proxy_actions.rb +219 -0
  31. data/lib/nexus_cli/mixins/repository_actions.rb +245 -0
  32. data/lib/nexus_cli/mixins/user_actions.rb +125 -0
  33. data/lib/nexus_cli/n3_metadata.rb +77 -0
  34. data/lib/nexus_cli/remote/oss_remote.rb +11 -0
  35. data/lib/nexus_cli/remote/pro_remote.rb +59 -0
  36. data/lib/nexus_cli/remote_factory.rb +30 -0
  37. data/lib/nexus_cli/tasks.rb +507 -0
  38. data/lib/nexus_cli/version.rb +6 -0
  39. data/nexus_cli_nx.gemspec +32 -0
  40. data/spec/fixtures/metadata_search.xml +10 -0
  41. data/spec/fixtures/nexus.config +4 -0
  42. data/spec/spec_helper.rb +22 -0
  43. data/spec/unit/nexus_cli/artifact_spec.rb +82 -0
  44. data/spec/unit/nexus_cli/configuration_spec.rb +159 -0
  45. data/spec/unit/nexus_cli/mixins/pro/custom_metadata_actions_spec.rb +21 -0
  46. data/spec/unit/nexus_cli/oss_remote_spec.rb +83 -0
  47. data/spec/unit/nexus_cli/pro_remote_spec.rb +110 -0
  48. data/spec/unit/nexus_cli/remote_factory_spec.rb +42 -0
  49. 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