artrest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +20 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +31 -0
  7. data/artrest.gemspec +30 -0
  8. data/bin/artrest +194 -0
  9. data/lib/artrest.rb +81 -0
  10. data/lib/artrest/build.rb +31 -0
  11. data/lib/artrest/buildnumber.rb +26 -0
  12. data/lib/artrest/builds.rb +46 -0
  13. data/lib/artrest/dir_entry.rb +115 -0
  14. data/lib/artrest/repositories.rb +61 -0
  15. data/lib/artrest/repository.rb +42 -0
  16. data/lib/artrest/resource.rb +366 -0
  17. data/lib/artrest/resources.rb +54 -0
  18. data/lib/artrest/system.rb +74 -0
  19. data/lib/artrest/system_general_configuration.rb +45 -0
  20. data/lib/artrest/version.rb +3 -0
  21. data/spec/artrest/build_spec.rb +62 -0
  22. data/spec/artrest/buildnumber_spec.rb +45 -0
  23. data/spec/artrest/builds_spec.rb +69 -0
  24. data/spec/artrest/folder_spec.rb +88 -0
  25. data/spec/artrest/repositories_spec.rb +47 -0
  26. data/spec/artrest/repository_spec.rb +63 -0
  27. data/spec/artrest/resource_spec.rb +385 -0
  28. data/spec/artrest/resources_spec.rb +66 -0
  29. data/spec/artrest/system_general_configuration_spec.rb +72 -0
  30. data/spec/artrest/system_spec.rb +50 -0
  31. data/spec/artrest_spec.rb +30 -0
  32. data/spec/fixtures/build/build_response_correct.txt +7 -0
  33. data/spec/fixtures/buildnumber/buildnumber_25_response.txt +7 -0
  34. data/spec/fixtures/builds/build_api_response_correct.txt +7 -0
  35. data/spec/fixtures/folder/pom_file_response_1.txt +7 -0
  36. data/spec/fixtures/folder/sub_folder_response.txt +7 -0
  37. data/spec/fixtures/folder/top_folder_response.txt +7 -0
  38. data/spec/fixtures/repositories/libs_snapshot_local_folder_response.txt +7 -0
  39. data/spec/fixtures/repositories/repositories_response.txt +7 -0
  40. data/spec/fixtures/repository/libs_snapshot_local_response.txt +7 -0
  41. data/spec/fixtures/resource/artifact_response.txt +7 -0
  42. data/spec/fixtures/resource/build_response.txt +7 -0
  43. data/spec/fixtures/resource/buildnumber_response.txt +7 -0
  44. data/spec/fixtures/resource/builds_response.txt +7 -0
  45. data/spec/fixtures/resource/folder_response.txt +7 -0
  46. data/spec/fixtures/resource/json_response.txt +7 -0
  47. data/spec/fixtures/resource/repositories_response.txt +7 -0
  48. data/spec/fixtures/resource/repository_not_found_response.txt +7 -0
  49. data/spec/fixtures/resource/repository_response.txt +7 -0
  50. data/spec/fixtures/resource/repository_unauthorized_response.txt +8 -0
  51. data/spec/fixtures/resource/string_response.txt +188 -0
  52. data/spec/fixtures/resource/sub_response.txt +188 -0
  53. data/spec/fixtures/resource/system_general_configuration_response.txt +654 -0
  54. data/spec/fixtures/resource/system_response.txt +188 -0
  55. data/spec/fixtures/resources/resources_response.txt +7 -0
  56. data/spec/fixtures/system/200_OK_ping_response.txt +7 -0
  57. data/spec/fixtures/system/general_configuration_response.txt +654 -0
  58. data/spec/fixtures/system/system_response.txt +188 -0
  59. data/spec/spec.opts +5 -0
  60. data/spec/spec_helper.rb +38 -0
  61. metadata +269 -0
@@ -0,0 +1,26 @@
1
+
2
+ module ArtRest
3
+
4
+ # Represents an {Artifactory}[http://www.jfrog.com/home/v_artifactory_opensource_overview]
5
+ # {Build Info}[http://wiki.jfrog.org/confluence/display/RTF/Artifactory's+REST+API#Artifactory'sRESTAPI-BuildInfo]
6
+ # resource.
7
+ #
8
+ # === Example
9
+ #
10
+ # buildInfo = ArtRest::Buildnumber.new('http://localhost:8081/artifactory/api/build/wicket/51', { ... })
11
+ #
12
+ class Buildnumber < ArtRest::Resource
13
+
14
+ class << self
15
+
16
+ def matches_path(path, options) # :nodoc:
17
+ path =~ %r|^/api/build/[a-zA-Z+-._]+/\d+$|
18
+ end
19
+ end
20
+
21
+ self.mime_type = MIME::Types['application/json']
22
+
23
+ self.resource_attributes :uri,
24
+ :buildInfo
25
+ end
26
+ end
@@ -0,0 +1,46 @@
1
+
2
+ module ArtRest
3
+
4
+ # Represents an {Artifactory}[http://www.jfrog.com/home/v_artifactory_opensource_overview]
5
+ # {All Builds}[http://wiki.jfrog.org/confluence/display/RTF/Artifactory's+REST+API#Artifactory'sRESTAPI-AllBuilds]
6
+ # resource.
7
+ #
8
+ # === Example
9
+ #
10
+ # allBuilds = ArtRest::Builds.new('http://localhost:8081/artifactory/api/build', { ... })
11
+ #
12
+ class Builds < ArtRest::Resources
13
+
14
+ class << self
15
+ public
16
+
17
+ # Shortcut method to retrieve *the* ArtRest::Builds
18
+ # instance.
19
+ #
20
+ # * *Args* :
21
+ # - +base_url+ -> Our Artifactory server's base URL
22
+ # - +options+ -> A Hash containing username and password
23
+ # * *Returns* :
24
+ # - *The* ArtRest::Builds instance representing the
25
+ # collection of all Artifactory builds
26
+ #
27
+ def get(base_url, options)
28
+ Builds.new("#{base_url}/api/build", options)
29
+ end
30
+
31
+ def matches_path(path, options) # :nodoc:
32
+ path =~ %r|^/api/build/?$|
33
+ end
34
+ end
35
+
36
+ self.mime_type = MIME::Types['application/json']
37
+
38
+ self.resources_creator = Proc.new do |content, options|
39
+ self_url = content['uri']
40
+ (content['builds'] || []).map { |build| ArtRest::Build.new("#{self_url}#{build['uri']}", options) }
41
+ end
42
+
43
+ self.resource_attributes :uri,
44
+ :builds
45
+ end
46
+ end
@@ -0,0 +1,115 @@
1
+
2
+ module ArtRest
3
+
4
+ module DirEntry
5
+
6
+ def self.create_node(resource_url, options, resource_descriptor, &block)
7
+ if resource_descriptor['folder'] or not resource_descriptor['children'].nil?
8
+ ArtRest::Folder.new(resource_url, options, &block)
9
+ else
10
+ ArtRest::Artifact.new(resource_url, options, &block)
11
+ end
12
+ end
13
+ end
14
+
15
+
16
+ # Represents an {Artifactory}[http://www.jfrog.com/home/v_artifactory_opensource_overview]
17
+ # {Folder Info}[http://wiki.jfrog.org/confluence/display/RTF/Artifactory's+REST+API#Artifactory'sRESTAPI-FolderInfo]
18
+ # resource.
19
+ #
20
+ # === Example
21
+ #
22
+ # folder = ArtRest::Folder.new('http://localhost:8081/artifactory/api/storage/libs-release-local/commons-lang/commons-lang', { ... })
23
+ #
24
+ class Folder < ArtRest::Resources
25
+ include ArtRest::DirEntry
26
+
27
+ class << self
28
+
29
+ def matches_path(path, options) # :nodoc:
30
+ return false unless path =~ %r|^/api/storage/[a-zA-Z0-9_.+-]+/.+$|
31
+ content_hash = JSON.parse(RestClient::Resource.new([options[:base_url], path].join, options[:user], options[:password]).get)
32
+ return content_hash['children']
33
+ end
34
+ end
35
+
36
+ self.mime_type = MIME::Types['application/json']
37
+
38
+ self.resources_creator = Proc.new do |content, options|
39
+ (content['children'] || []).map { |child| ArtRest::DirEntry.create_node("#{content['uri']}#{child['uri']}", options, child) }
40
+ end
41
+
42
+ self.resource_attributes :path,
43
+ :lastUpdated,
44
+ :repo,
45
+ :uri,
46
+ :modifiedBy,
47
+ :created,
48
+ :createdBy,
49
+ :lastModified,
50
+ :metadataUri
51
+
52
+ public
53
+
54
+ def [](suburl, &new_block) # :nodoc:
55
+ subresource_content = JSON.parse(RestClient::Resource.new(url, options, &new_block)[suburl].get)
56
+ ArtRest::DirEntry.create_node([url, suburl].join, options, subresource_content, &new_block)
57
+ end
58
+
59
+ def traverse(&block)
60
+ each do |child_entry|
61
+ block.call(child_entry)
62
+ if child_entry.is_a?(ArtRest::Folder) then
63
+ child_entry.each &block
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ # Represents an {Artifactory}[http://www.jfrog.com/home/v_artifactory_opensource_overview]
70
+ # {File Info}[http://wiki.jfrog.org/confluence/display/RTF/Artifactory's+REST+API#Artifactory'sRESTAPI-FileInfo]
71
+ # resource.
72
+ #
73
+ # === Example
74
+ #
75
+ # file = ArtRest::File.new('http://localhost:8081/artifactory/api/storage/libs-release-local/commons-lang/commons-lang/3.2/commons-lang-3.2.jar', { ... })
76
+ #
77
+ class Artifact < ArtRest::Resource
78
+ include ArtRest::DirEntry
79
+
80
+ class << self
81
+
82
+ def matches_path(path, options) # :nodoc:
83
+ return false unless path =~ %r|^/api/storage/[a-zA-Z0-9_.+-]+/.+$|
84
+ content_hash = JSON.parse(RestClient::Resource.new([options[:base_url], path].join, options[:user], options[:password]).get)
85
+ return ! content_hash['children']
86
+ end
87
+ end
88
+
89
+ self.mime_type = MIME::Types['application/json']
90
+
91
+ self.resource_attributes :path,
92
+ :lastUpdated,
93
+ :repo,
94
+ :uri,
95
+ :modifiedBy,
96
+ :created,
97
+ :createdBy,
98
+ :lastModified,
99
+ :metadataUri,
100
+ :mimeType,
101
+ :downloadUri,
102
+ :size,
103
+ :checksums,
104
+ :originalChecksums
105
+
106
+ public
107
+
108
+ # Overwritten to always throw NotImplementedError since ArtRest::Artifacts
109
+ # don't have sub resources.
110
+ #
111
+ def [](suburl, &new_block)
112
+ raise NotImplementedError.new("Instances of ArtRest::Artifact don't have child resources")
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,61 @@
1
+
2
+ module ArtRest
3
+
4
+ # Represents an {Artifactory}[http://www.jfrog.com/home/v_artifactory_opensource_overview]
5
+ # {Repositories}[http://wiki.jfrog.org/confluence/display/RTF/Artifactory's+REST+API#Artifactory'sRESTAPI-GetRepositories]
6
+ # resource.
7
+ #
8
+ # === Example
9
+ #
10
+ # repos = ArtRest::Repositories.new('http://localhost:8081/artifactory/api/repositories', { ... })
11
+ #
12
+ class Repositories < ArtRest::Resources
13
+
14
+ class << self
15
+ public
16
+
17
+ # Shortcut method to retrieve *the* ArtRest::Repositories
18
+ # instance.
19
+ #
20
+ # * *Args* :
21
+ # - +base_url+ -> Our Artifactory server's base URL
22
+ # - +options+ -> A Hash containing username and password
23
+ # * *Returns* :
24
+ # - *The* ArtRest::Repositories instance representing the
25
+ # collection of all Artifactory repositories
26
+ #
27
+ def get(base_url, options)
28
+ Repositories.new("#{base_url}/api/repositories", options)
29
+ end
30
+
31
+ def matches_path(path, options) # :nodoc:
32
+ path =~ %r|^/api/repositories/?$|
33
+ end
34
+ end
35
+
36
+ self.mime_type = MIME::Types['application/json']
37
+
38
+ self.resources_creator = Proc.new do |content, options|
39
+ content.map { |repo| ArtRest::Repository.new(repo['url'], options) }
40
+ end
41
+
42
+ # Look up and return the repository[rdoc-ref:ArtRest::Repository] named
43
+ # +repo_name+. Optionally yield that repository to a block provided a
44
+ # block is given.
45
+ #
46
+ # * *Args* :
47
+ # [+repo_name+] Name of the repository to return
48
+ # * *Returns* :
49
+ # - The repository named +repo_name+, an ArtRest::Repository instance
50
+ # * *Raises* :
51
+ # [+RestClient::ResourceNotFound+] If +repo_name+ does not point to an
52
+ # existing repository
53
+ #
54
+ def repository(repo_name) # :yields: repository
55
+ repo_url = concat_urls(base_url, "/#{repo_name}/")
56
+ repo = ArtRest::Repository.new(repo_url, options, block)
57
+ yield repo if block_given?
58
+ repo
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,42 @@
1
+
2
+ module ArtRest
3
+
4
+ # Represents an {Artifactory}[http://www.jfrog.com/home/v_artifactory_opensource_overview]
5
+ # repository resource.
6
+ #
7
+ # *IMPORTANT* This is *not* the {Repository Configuration}[http://wiki.jfrog.org/confluence/display/RTF/Artifactory's+REST+API#Artifactory'sRESTAPI-RepositoryConfiguration]
8
+ # resource as this would require Artifactory Pro. It is rather a repository's
9
+ # top-level {folder}[rdoc-ref:ArtRest::Folder] "/".
10
+ #
11
+ # === Example
12
+ #
13
+ # libs_releas_local = ArtRest::Repository.new('http://localhost:8081/artifactory/api/storage/libs-release-local', { ... })
14
+ #
15
+ class Repository < ArtRest::Resources
16
+
17
+ class << self
18
+
19
+ def matches_path(path, options) # :nodoc:
20
+ path =~ %r|^/api/storage/[a-zA-Z+-._]+/?$|
21
+ end
22
+ end
23
+
24
+ self.mime_type = MIME::Types['application/json']
25
+
26
+ self.resources_creator = Proc.new do |content, options|
27
+ self_url = content['uri']
28
+ (content['children'] || []).map { |child| ArtRest::DirEntry.create_node("#{self_url}#{child['uri']}", options, child) }
29
+ end
30
+
31
+ self.resource_attributes :path,
32
+ :lastUpdated,
33
+ :repo,
34
+ :uri,
35
+ :modifiedBy,
36
+ :created,
37
+ :createdBy,
38
+ :lastModified,
39
+ :metadataUri,
40
+ :children
41
+ end
42
+ end
@@ -0,0 +1,366 @@
1
+
2
+ module ArtRest
3
+
4
+ # Abstract base class for all Artifactory resources.
5
+ #
6
+ class Resource < RestClient::Resource
7
+
8
+ class << self
9
+
10
+ public
11
+
12
+ # Add +subclass+ to the list of known subclasses.
13
+ #
14
+ # * *Args* :
15
+ # - +subclass+ -> The subclass to add
16
+ #
17
+ def inherited(subclass)
18
+ @@subclasses ||= []
19
+ @@subclasses << subclass
20
+ end
21
+
22
+ # Define a singleton method +mime_type+ on the class this
23
+ # method is called on, where calling +mime_type+ will return
24
+ # +value+.
25
+ #
26
+ # This essentially emulates a "proper" class variable
27
+ # +mime_type+.
28
+ #
29
+ # * *Args* :
30
+ # - +value+ -> This class' mime type [MIME::Type/required]
31
+ #
32
+ def mime_type=(value)
33
+ self.singleton_class.class_eval do
34
+ define_method(:mime_type) do
35
+ value
36
+ end
37
+ end
38
+ end
39
+
40
+ # Take an array of symbols +attrs+ and for each symbol
41
+ # "attr" define an instance method +attr+ on this class
42
+ # that returns <tt>content["attr"]</tt>.
43
+ #
44
+ # So, given an attribute <tt>:modifiedBy</tt> this will define
45
+ #
46
+ # def modifiedBy
47
+ # content['modifiedBy']
48
+ # end
49
+ #
50
+ def resource_attributes(*attrs)
51
+ attrs.each do |attr|
52
+ define_method(attr) do
53
+ return content[attr.to_s] unless block_given?
54
+ yield content[attr.to_s]
55
+ end
56
+ end
57
+ end
58
+
59
+ # Factory method: create and return an instance of a concrete
60
+ # ArtRest::Resource subclass appropriate for the supplied
61
+ # +resource_url+.
62
+ #
63
+ # === Example
64
+ #
65
+ # ArtRest::Resource.create('http://localhost:8081/artifactory/api/system,
66
+ # options)
67
+ #
68
+ # will return an ArtRest::System instance.
69
+ #
70
+ # * *Args* :
71
+ # [+resource_url+] URL of the resource to create [required]
72
+ # [+options+] Options hash holding base_url, user and
73
+ # password [required]
74
+ # [+block+] Passed on to <tt>RestClient::Resource.initialize</tt> [optional]
75
+ # * *Returns* :
76
+ # - An instance of a concrete ArtRest::Resource subclass appropriate
77
+ # for the supplied +resource_url+
78
+ #
79
+ def create(resource_url, options, &block)
80
+ check_options(options)
81
+ @@subclasses.each do |subclass|
82
+ return subclass.new(resource_url, options, &block) if
83
+ subclass.respond_to?(:matches_path) and
84
+ subclass.matches_path(relative_path(resource_url, options), options)
85
+ end
86
+ raise ArgumentError.new("Unsupported resource URL #{resource_url}")
87
+ end
88
+
89
+ def check_options(options) # :nodoc:
90
+ raise ArgumentError, "Must pass :base_url" unless options[:base_url]
91
+ raise ArgumentError, "Must pass :user" unless options[:user]
92
+ raise ArgumentError, "Must pass :password" unless options[:password]
93
+ end
94
+
95
+ protected
96
+
97
+ def relative_path(resource_url, options) # :nodoc:
98
+ check_options(options)
99
+ base_path = Addressable::URI.parse(options[:base_url]).path
100
+ resource_path = Addressable::URI.parse(resource_url).path
101
+ resource_path.slice!(base_path)
102
+ resource_path
103
+ end
104
+ end
105
+
106
+ # This class' mime type
107
+ self.mime_type = MIME::Types['application/json']
108
+
109
+ public
110
+
111
+ # Create a new ArtRest::Resource instance, representing the Artifactory
112
+ # resource located at +resource_url+. Use username and password
113
+ # contained in +options+ to authenticate against the Artifactory server.
114
+ # Optionally take and cache the parsed +content+ of the resource pointed
115
+ # to by +resource_url+ in case the caller has already accessed that
116
+ # resource. A +block+, if given, will transparently be passed on to
117
+ # RestClient::Resource's - our ancestor's - constructor.
118
+ #
119
+ # * *Args* :
120
+ # - +resource_url+ -> URL of the Artifactory resource
121
+ # - +options+ -> A hash containing our Artifactory server's base url,
122
+ # and a username and a password to authenticate against that server
123
+ # - +content+ -> The *parsed* content of the resource, if the caller
124
+ # has already accessed that resource [optional]
125
+ # - +block+ -> A block that will be passed on to
126
+ # RestClient::Resource#initialize [optional]
127
+ #
128
+ def initialize(resource_url, options, content = nil, &block)
129
+ self.class.check_options(options)
130
+ super(resource_url, options, &block)
131
+ @content = content if content
132
+ end
133
+
134
+ # Return our Artifactory server's <em>base url</em>.
135
+ #
136
+ # === Example
137
+ #
138
+ # http://localhost:8081/artifactory
139
+ #
140
+ def base_url
141
+ options[:base_url]
142
+ end
143
+
144
+ # Return this resource's *parsed* content. In almost all cases this will
145
+ # be a Hash representing this resource's JSON content. The only
146
+ # exception is ArtRest::System, where the content is a plain text
147
+ # representation and thus returned as a String.
148
+ #
149
+ # If called with a +block+, yield this resource's parsed content to that
150
+ # block.
151
+ #
152
+ # * *Args* :
153
+ # [+block+] A block to yield this resource's parsed content to [optional]
154
+ # * *Returns* :
155
+ # - If called *without* a block, this resource's *parsed* content, most
156
+ # often a +Hash+, otherwise a +String+.
157
+ # If called *with* a block, +self+
158
+ # * *Raises* :
159
+ # [+RestClient::ResourceNotFound+] If the resource this instance
160
+ # represents does in fact not exist
161
+ # on the server
162
+ # [+RestClient::Unauthorized+] If accessing this resource is not
163
+ # authorized
164
+ #
165
+ def content # :yields: content
166
+ return _content unless block_given?
167
+ # If our block returns a value, this will become this resource's new
168
+ # content
169
+ yield _content
170
+ self
171
+ end
172
+
173
+ # Return this resource's *unparsed* content as a string[rdoc-ref:String].
174
+ #
175
+ # Most of Artifactory's resources are represented in JSON, and these
176
+ # will be parsed into an equivalent ruby {hash}[rdoc-ref:Hash] upon load. This
177
+ # method will *unparse* that hash back into a JSON string.
178
+ #
179
+ # In all other cases, when a resource's mime type is *not*
180
+ # 'application/json', that resource's representation will remain
181
+ # unchanged, i.e. will be stored as a string, and this method will
182
+ # return that string as is.
183
+ #
184
+ # * *Returns* :
185
+ # - This resource's unparsed content, a {string}[rdoc-ref:String]
186
+ # * *Raises* :
187
+ # [+RestClient::ResourceNotFound+] If the resource this instance
188
+ # represents does in fact not exist
189
+ # on the server
190
+ # [+RestClient::Unauthorized+] If accessing this resource is not
191
+ # authorized
192
+ #
193
+ def unparsed_content(fmt = :plain)
194
+ return _content unless self.class.mime_type == MIME::Types['application/json']
195
+ case fmt
196
+ when :pretty then
197
+ JSON.pretty_generate(_content)
198
+ else
199
+ JSON.generate(_content)
200
+ end
201
+ end
202
+
203
+ # Set this resource's representation to +value+. Handle +value+ as
204
+ # appropriate for this resource's mime type:
205
+ #
206
+ # === application/json
207
+ #
208
+ # If we are dealing with a JSON resource - the most common case -
209
+ # +value+ may be one of
210
+ #
211
+ # * Hash: will be accepted as is
212
+ # * String: will be interpreted as a JSON encoded string and parsed into a
213
+ # ruby Hash
214
+ #
215
+ # Raise an +ArgumentError+ in all other cases.
216
+ #
217
+ # === text/plain or application/xml
218
+ #
219
+ # In this case, +value+ may be of any kind, but will be converted into a
220
+ # String via calling +value+.#to_s.
221
+ #
222
+ # * *Args* :
223
+ # - +value+ -> This resource's new content/representation. See above.
224
+ # * *Raises* :
225
+ # - +ArgumentError+ -> If this resource's mime type is
226
+ # +application/json+ and value is neither a Hash nor a String
227
+ #
228
+ def content=(value)
229
+ if value.nil?
230
+ @content = nil
231
+ return
232
+ end
233
+ case self.class.mime_type
234
+ when MIME::Types['application/json'] then
235
+ if value.is_a? Hash
236
+ @content = value
237
+ elsif value.is_a? String
238
+ @content = JSON.parse(value)
239
+ else
240
+ raise ArgumentError, "Can only accept Hash and String. Got: #{value.class}"
241
+ end
242
+ else
243
+ @content = value.to_s
244
+ end
245
+ end
246
+
247
+ # Yield this resource's parsed content to +block+. If block returns a value,
248
+ # accept this value as this resource's new content. Calling this method
249
+ # is therefore a potentially destructive operation.
250
+ #
251
+ # Also see #content.
252
+ #
253
+ # * *Args* :
254
+ # [+block+] A block to yield this resource's parsed content to
255
+ # * *Returns* :
256
+ # - +self+ This instance
257
+ # * *Raises* :
258
+ # [+RestClient::ResourceNotFound+] If the resource this instance
259
+ # represents does in fact not exist
260
+ # on the server
261
+ # [+RestClient::Unauthorized+] If accessing this resource is not
262
+ # authorized
263
+ #
264
+ def content! &block # :yields: content
265
+ # If our block returns a value, this will become this resource's new
266
+ # content
267
+ new_content = yield _content
268
+ self.content = new_content if new_content
269
+ self
270
+ end
271
+
272
+ # Look up and return the ArtRest::Resource instance that is located at
273
+ # +relative_path+ relative to this resource. Take care to return the
274
+ # appropriate ArtRest::Resource subtype.
275
+ #
276
+ # === Example
277
+ #
278
+ # Given
279
+ #
280
+ # repository = ArtRest::Repository.new('http://localhost:8081/artifactory/api/storage/libs-release-local', { ... })
281
+ #
282
+ # the expression
283
+ #
284
+ # folder = repository['/commons-lang/commons-lang/3.2.0']
285
+ #
286
+ # will return an ArtRest::Folder instance.
287
+ #
288
+ # * *Args* :
289
+ # [+relative_path+] The path of the resource to look up, relative to
290
+ # this resource
291
+ # [+block+] A block that will be transparently passed on to
292
+ # RestClient::Resource#initialize [optional]
293
+ # * *Returns* :
294
+ # - An ArtRest::Resource instance of appropriate type representing the
295
+ # Artifactory resource located at +relative_path+ relative to this resource
296
+ #
297
+ def [](relative_path, &new_block)
298
+ case
299
+ when block_given? then
300
+ ArtRest::Resource.create(concat_urls(url, relative_path), options, &new_block)
301
+ when block then
302
+ ArtRest::Resource.create(concat_urls(url, relative_path), options, &block)
303
+ else
304
+ ArtRest::Resource.create(concat_urls(url, relative_path), options)
305
+ end
306
+ end
307
+
308
+ # Hide method from RestClient::Resource by default since they
309
+ # may make no sense on a concrete subclass.
310
+ protected :get, :post, :put, :delete, :head, :patch
311
+
312
+ protected
313
+
314
+ # Post changes made to this resource's content/representation since
315
+ # loading it from Artifactory - if any - back to the server, i.e.
316
+ # *update* the resource this instance represents.
317
+ #
318
+ # === Example
319
+ #
320
+ # sysConfig = ArtRest::System::GeneralConfiguration.get
321
+ # sysConfig.content = ...
322
+ # sysConfig.update!
323
+ #
324
+ # * *Args* :
325
+ # - +additional_headers+ -> Any additional headers to be set on the
326
+ # POST request
327
+ #
328
+ def update!(additional_headers = {}, &block)
329
+ post(self.unparsed_content, additional_headers, &block)
330
+ end
331
+
332
+ # Take +content+ and make it this resource's new #content by calling
333
+ # #content= +content+. Subsequently, post this resource's changes back to
334
+ # Artifactory, i.e. *update* the resource this instance represents.
335
+ #
336
+ # Calling this method on a resource +res+ is therefore equivalent to
337
+ #
338
+ # res.content = content
339
+ # res.update!(additional_headers, &block)
340
+ #
341
+ # * *Args* :
342
+ # [+content+] This resource's new #content
343
+ # [+additional_headers+] Any additional headers to be set on this POST
344
+ # request that calling this method entails
345
+ # [+block+] A block that will be passed on to
346
+ # RestClient::Resource#post, i.e. it will handle
347
+ # the response to our POST request
348
+ #
349
+ def update_with!(content, additional_headers = {}, &block)
350
+ self.content = content
351
+ update!(additional_headers, &block)
352
+ end
353
+
354
+ private
355
+
356
+ def _content # :nodoc:
357
+ return @content if @content
358
+ raw = get
359
+ @content = case self.class.mime_type
360
+ when MIME::Types['application/json'] then JSON.parse(raw)
361
+ else raw
362
+ end
363
+ @content
364
+ end
365
+ end
366
+ end