studio_api 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +93 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/lib/studio_api/appliance.rb +365 -0
- data/lib/studio_api/build.rb +17 -0
- data/lib/studio_api/connection.rb +102 -0
- data/lib/studio_api/file.rb +70 -0
- data/lib/studio_api/generic_request.rb +160 -0
- data/lib/studio_api/package.rb +12 -0
- data/lib/studio_api/pattern.rb +12 -0
- data/lib/studio_api/repository.rb +35 -0
- data/lib/studio_api/rpm.rb +33 -0
- data/lib/studio_api/running_build.rb +35 -0
- data/lib/studio_api/studio_resource.rb +70 -0
- data/lib/studio_api/template_set.rb +12 -0
- data/lib/studio_api/util.rb +38 -0
- data/lib/studio_api.rb +31 -0
- data/test/appliance_test.rb +189 -0
- data/test/build_test.rb +45 -0
- data/test/connection_test.rb +21 -0
- data/test/file_test.rb +52 -0
- data/test/generic_request_test.rb +66 -0
- data/test/repository_test.rb +42 -0
- data/test/resource_test.rb +49 -0
- data/test/responses/appliance.xml +27 -0
- data/test/responses/appliances.xml +199 -0
- data/test/responses/build.xml +17 -0
- data/test/responses/builds.xml +19 -0
- data/test/responses/file.xml +12 -0
- data/test/responses/files.xml +14 -0
- data/test/responses/gpg_key.xml +25 -0
- data/test/responses/gpg_keys.xml +77 -0
- data/test/responses/repositories.xml +42 -0
- data/test/responses/repository.xml +8 -0
- data/test/responses/rpm.xml +10 -0
- data/test/responses/rpms.xml +404 -0
- data/test/responses/running_build.xml +7 -0
- data/test/responses/running_builds.xml +23 -0
- data/test/responses/software.xml +50 -0
- data/test/responses/software_installed.xml +729 -0
- data/test/responses/software_search.xml +64 -0
- data/test/responses/status-broken.xml +9 -0
- data/test/responses/status.xml +4 -0
- data/test/responses/template_sets.xml +380 -0
- data/test/rpm_test.rb +59 -0
- data/test/running_build_test.rb +50 -0
- data/test/template_set_test.rb +35 -0
- metadata +181 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
require "studio_api/studio_resource"
|
2
|
+
require "cgi"
|
3
|
+
module StudioApi
|
4
|
+
# Represents overlay files which can be loaded to appliance.
|
5
|
+
#
|
6
|
+
# Supports finding files for appliance, updating metadata, deleting, uploading and downloading.
|
7
|
+
#
|
8
|
+
# @example Find files for appliance
|
9
|
+
# StudioApi::File.find :all, :params => { :appliance_id => 1234 }
|
10
|
+
#
|
11
|
+
# @example Upload file Xorg.conf
|
12
|
+
# File.open ("/tmp/xorg.conf) { |file|
|
13
|
+
# StudioApi::File.upload file, 1234, :path => "/etc/X11",
|
14
|
+
# :filename => "Xorg.conf", :permissions => "0755",
|
15
|
+
# :owner => "root"
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
# @example Update metadata
|
19
|
+
# file = StudioApi::File.find 1234
|
20
|
+
# file.owner = "root"
|
21
|
+
# file.path = "/etc"
|
22
|
+
# file.filename = "pg.conf"
|
23
|
+
# file.save
|
24
|
+
|
25
|
+
class File < ActiveResource::Base
|
26
|
+
extend StudioResource
|
27
|
+
self.element_name = "file"
|
28
|
+
|
29
|
+
# Downloads file to output. Allow downloading to stream or to path.
|
30
|
+
# @return [String] content of file
|
31
|
+
def content
|
32
|
+
rq = GenericRequest.new self.class.studio_connection
|
33
|
+
rq.get "/files/#{id.to_i}/data"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Overwritte file content and keep metadata ( of course without such things like size )
|
37
|
+
# Immediatelly store new content
|
38
|
+
# @param (File,#to_s) input new content for file as String or open file
|
39
|
+
# @return [StudioApi::File] self with updated metadata
|
40
|
+
def overwrite ( content )
|
41
|
+
request_str = "/files/#{id.to_i}/data"
|
42
|
+
rq = GenericRequest.new self.class.studio_connection
|
43
|
+
response = rq.put request_str, :file => content
|
44
|
+
load Hash.from_xml(response)["file"]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Uploads file to appliance
|
48
|
+
# @param (String,File) content as String or as opened File
|
49
|
+
# ( in this case its name is used as default for uploaded file name)
|
50
|
+
# @param (#to_i) appliance_id id of appliance where to upload
|
51
|
+
# @param (Hash<#to_s,#to_s>) options optional parameters, see API documentation
|
52
|
+
# @return [StudioApi::File] metadata of uploaded file
|
53
|
+
def self.upload ( content, appliance_id, options = {})
|
54
|
+
request_str = "files?appliance_id=#{appliance_id.to_i}"
|
55
|
+
options.each do |k,v|
|
56
|
+
request_str << "&#{CGI.escape k.to_s}=#{CGI.escape v.to_s}"
|
57
|
+
end
|
58
|
+
rq = GenericRequest.new studio_connection
|
59
|
+
response = rq.post request_str, :file => content
|
60
|
+
File.new Hash.from_xml(response)["file"]
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
# file uses for update parameter put
|
65
|
+
# @private
|
66
|
+
def new?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2010 Novell, Inc.
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public License as
|
7
|
+
# published by the Free Software Foundation; version 2.1 of the license.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public License
|
15
|
+
# along with this library; if not, contact Novell, Inc.
|
16
|
+
#
|
17
|
+
# To contact Novell about this file by physical or electronic mail,
|
18
|
+
# you may find current contact information at www.novell.com
|
19
|
+
|
20
|
+
require 'xmlsimple'
|
21
|
+
require 'uri'
|
22
|
+
require 'cgi'
|
23
|
+
require 'net/http'
|
24
|
+
require 'net/https'
|
25
|
+
require 'active_support'
|
26
|
+
require 'active_resource/formats'
|
27
|
+
require 'active_resource/connection'
|
28
|
+
|
29
|
+
require 'studio_api/util'
|
30
|
+
|
31
|
+
module StudioApi
|
32
|
+
# Class which use itself direct connection to studio for tasks where
|
33
|
+
# ActiveResource is not enough. For consistent api is all network exceptions
|
34
|
+
# mapped to ones used in ActiveResource.
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# rq = StudioApi::GenericRequest.new @connection
|
38
|
+
# rq.get "/appliances"
|
39
|
+
# rq.post "/file", :file => "/etc/config"
|
40
|
+
class GenericRequest
|
41
|
+
# Creates new instance of request for given connection
|
42
|
+
# @param (StudioApi::Connection) connection information about connection
|
43
|
+
def initialize(connection)
|
44
|
+
@connection = connection
|
45
|
+
if connection.proxy
|
46
|
+
proxy = connection.proxy
|
47
|
+
@http = Net::HTTP.new(connection.uri.host, connection.uri.port,
|
48
|
+
proxy.host, proxy.port, proxy.user, proxy.password)
|
49
|
+
else
|
50
|
+
@http = Net::HTTP.new(connection.uri.host, connection.uri.port)
|
51
|
+
end
|
52
|
+
@http.read_timeout = connection.timeout
|
53
|
+
if connection.uri.scheme == "https"
|
54
|
+
@http.use_ssl = true
|
55
|
+
Connection::SSL_ATTRIBUTES.each do |attr|
|
56
|
+
@http.send :"#{attr}=", connection.ssl[attr.to_sym] if connection.ssl[attr.to_sym]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# sends get request
|
62
|
+
# @param (String) path relative path from api root
|
63
|
+
# @return (String) response body from studio
|
64
|
+
# @raise [ActiveResource::ConnectionError] when problem occur during connection
|
65
|
+
def get(path)
|
66
|
+
do_request Net::HTTP::Get.new Util.join_relative_url @connection.uri.request_uri,path
|
67
|
+
end
|
68
|
+
|
69
|
+
# sends delete request
|
70
|
+
# @param (String) path relative path from api root
|
71
|
+
# @return (String) response body from studio
|
72
|
+
# @raise [ActiveResource::ConnectionError] when problem occur during connection
|
73
|
+
def delete(path)
|
74
|
+
#Even it is not dry I want to avoid meta programming with dynamic code evaluation so code is clear
|
75
|
+
do_request Net::HTTP::Delete.new Util.join_relative_url @connection.uri.request_uri,path
|
76
|
+
end
|
77
|
+
|
78
|
+
# sends post request
|
79
|
+
# @param (String) path relative path from api root
|
80
|
+
# @param (Hash<#to_s,#to_s>,Hash<#to_s,#path>) data hash containing data to attach to body
|
81
|
+
# @return (String) response body from studio
|
82
|
+
# @raise [ActiveResource::ConnectionError] when problem occur during connection
|
83
|
+
def post(path,data={})
|
84
|
+
request = Net::HTTP::Post.new Util.join_relative_url @connection.uri.request_uri,path
|
85
|
+
set_data(request,data) unless data.empty?
|
86
|
+
do_request request
|
87
|
+
end
|
88
|
+
|
89
|
+
# sends post request
|
90
|
+
# @param (String) path relative path from api root
|
91
|
+
# @param (Hash<#to_s,#to_s>,Hash<#to_s,#path>) data hash containing data to attach to body
|
92
|
+
# @return (String) response body from studio
|
93
|
+
# @raise [ActiveResource::ConnectionError] when problem occur during connection
|
94
|
+
def put(path,data={})
|
95
|
+
request = Net::HTTP::Put.new Util.join_relative_url @connection.uri.request_uri,path
|
96
|
+
set_data(request,data) unless data.empty?
|
97
|
+
do_request request
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def do_request(request)
|
102
|
+
request.basic_auth @connection.user, @connection.password
|
103
|
+
@http.start() do
|
104
|
+
response = @http.request request
|
105
|
+
unless response.kind_of? Net::HTTPSuccess
|
106
|
+
msg = error_message response
|
107
|
+
create_active_resource_exception response,msg
|
108
|
+
end
|
109
|
+
response.body
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
#XXX not so nice to use internal method, but better to be DRY and proper test if it works with supported rails
|
114
|
+
def create_active_resource_exception response,msg
|
115
|
+
response.instance_variable_set "@message",msg
|
116
|
+
ActiveResource::Connection.new('').send :handle_response, response
|
117
|
+
end
|
118
|
+
|
119
|
+
def error_message response
|
120
|
+
xml_parsed = XmlSimple.xml_in(response.body, {'KeepRoot' => true})
|
121
|
+
raise "Unknown error response from Studio: #{response.body}" unless xml_parsed['error']
|
122
|
+
msg = ""
|
123
|
+
xml_parsed['error'].each() {|error| msg << error['message'][0]+"\n" }
|
124
|
+
return msg
|
125
|
+
rescue RuntimeError
|
126
|
+
return response.message+"\n"+response.body
|
127
|
+
end
|
128
|
+
|
129
|
+
def set_data(request,data)
|
130
|
+
boundary = Time.now.to_i.to_s(16)
|
131
|
+
request["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
|
132
|
+
body = ""
|
133
|
+
data.each do |key,value|
|
134
|
+
esc_key = CGI.escape(key.to_s)
|
135
|
+
body << "--#{boundary}\r\n"
|
136
|
+
if value.respond_to?(:read) && value.respond_to?(:path)
|
137
|
+
# ::File is needed to use "Ruby" file instead this one
|
138
|
+
body << "Content-Disposition: form-data; name=\"#{esc_key}\"; filename=\"#{::File.basename(value.path)}\"\r\n"
|
139
|
+
body << "Content-Type: #{mime_type(value.path)}\r\n\r\n"
|
140
|
+
body << value.read
|
141
|
+
else
|
142
|
+
body << "Content-Disposition: form-data; name=\"#{esc_key}\"\r\n\r\n#{value}"
|
143
|
+
end
|
144
|
+
body << "\r\n"
|
145
|
+
end
|
146
|
+
body << "--#{boundary}--\r\n\r\n"
|
147
|
+
request.body = body
|
148
|
+
request["Content-Length"] = request.body.size
|
149
|
+
end
|
150
|
+
|
151
|
+
def mime_type(file)
|
152
|
+
case
|
153
|
+
when file =~ /\.jpe?g\z/i then 'image/jpg'
|
154
|
+
when file =~ /\.gif\z/i then 'image/gif'
|
155
|
+
when file =~ /\.png\z/i then 'image/png'
|
156
|
+
else 'application/octet-stream'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module StudioApi
|
2
|
+
# Represents package in appliance. Used mainly as data storage.
|
3
|
+
class Package
|
4
|
+
attr_accessor :name, :version, :repository_id, :arch, :checksum, :checksum_type
|
5
|
+
def initialize name, attributes = {}
|
6
|
+
@name = name
|
7
|
+
attributes.each do |k,v|
|
8
|
+
instance_variable_set "@#{k}", v
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module StudioApi
|
2
|
+
# Represents pattern in appliance. Used mainly as data storage.
|
3
|
+
class Pattern
|
4
|
+
attr_accessor :name, :version, :repository_id, :arch
|
5
|
+
def initialize name, attributes = {}
|
6
|
+
@name = name
|
7
|
+
attributes.each do |k,v|
|
8
|
+
instance_variable_set "@#{k}", v
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "studio_api/studio_resource"
|
2
|
+
module StudioApi
|
3
|
+
# Represents available repositories for appliance.
|
4
|
+
#
|
5
|
+
# Allows finding and importing repositories.
|
6
|
+
# When using find :all then there is optional parameters for base_system and filter
|
7
|
+
#
|
8
|
+
# @example Find repository with kde for SLE11
|
9
|
+
# StudioApi::Repository.find :all, :params => { :base_system => "sle11", :filter => "kde" }
|
10
|
+
|
11
|
+
class Repository < ActiveResource::Base
|
12
|
+
extend StudioResource
|
13
|
+
|
14
|
+
undef_method :save #save is useless there
|
15
|
+
undef_method :destroy #not allowed
|
16
|
+
|
17
|
+
# Import new repository to Studio
|
18
|
+
#
|
19
|
+
# note: Repository will be available to everyone
|
20
|
+
# @param (#to_s) url to repository
|
21
|
+
# @param (#to_s) name of created repository
|
22
|
+
# @return [StudioApi::Repository] imported repository
|
23
|
+
def self.import (url, name)
|
24
|
+
response = post '',:url => url, :name => name
|
25
|
+
attrs = Hash.from_xml response.body
|
26
|
+
Repository.new attrs["repository"]
|
27
|
+
end
|
28
|
+
private
|
29
|
+
#handle special studio collection method for import
|
30
|
+
def self.custom_method_collection_url(method_name, options = {})
|
31
|
+
prefix_options, query_options = split_options(options)
|
32
|
+
"#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "studio_api/studio_resource"
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module StudioApi
|
5
|
+
# Represents Additional rpms which can user upload to studio.
|
6
|
+
#
|
7
|
+
# Allows uploading, downloading, listing (via find) and deleting
|
8
|
+
#
|
9
|
+
# @example Delete own rpm
|
10
|
+
# rpms = StudioApi::Rpm.find :all, :params => { :base_system => "SLE11" }
|
11
|
+
# my_pac = rpms.find {|r| r.filename =~ /my_pac/ }
|
12
|
+
# my_pac.delete
|
13
|
+
class Rpm < ActiveResource::Base
|
14
|
+
extend StudioResource
|
15
|
+
undef_method :save
|
16
|
+
|
17
|
+
self.element_name = "rpm"
|
18
|
+
# Upload file to studio account (user repository)
|
19
|
+
# @param (String,File) content of rpm as String or as opened file, in which case name is used as name
|
20
|
+
# @param (#to_s) base_system for which is rpm compiled
|
21
|
+
# @return [StudioApi::Rpm] uploaded RPM
|
22
|
+
def self.upload content, base_system
|
23
|
+
response = GenericRequest.new(studio_connection).post "/rpms?base_system=#{CGI.escape base_system.to_s}", :file => content
|
24
|
+
self.new Hash.from_xml(response)["rpm"]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Downloads file to specified path.
|
28
|
+
# @return [String] content of rpm
|
29
|
+
def content
|
30
|
+
GenericRequest.new(self.class.studio_connection).get "/rpms/#{id.to_i}/data"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "studio_api/studio_resource"
|
2
|
+
|
3
|
+
require "cgi"
|
4
|
+
|
5
|
+
module StudioApi
|
6
|
+
# Represents running build in studio.
|
7
|
+
#
|
8
|
+
# Provide finding builds, canceling build process or running new build
|
9
|
+
# For parameters see API documentation
|
10
|
+
# @example Run new build and then cancel it
|
11
|
+
# rb = StudioApi::RunningBuild.new(:appliance_id => 1234, :force => "true", :multi => "true")
|
12
|
+
# rb.save!
|
13
|
+
# sleep 5
|
14
|
+
# rb.cancel
|
15
|
+
class RunningBuild < ActiveResource::Base
|
16
|
+
extend StudioResource
|
17
|
+
|
18
|
+
self.element_name = "running_build"
|
19
|
+
|
20
|
+
alias_method :cancel, :destroy
|
21
|
+
|
22
|
+
private
|
23
|
+
#overwrite create as studio doesn't interact well with enclosed parameters
|
24
|
+
def create
|
25
|
+
request_str = collection_path
|
26
|
+
request_str << "?appliance_id=#{attributes.delete("appliance_id").to_i}"
|
27
|
+
attributes.each do |k,v|
|
28
|
+
request_str << "&#{CGI.escape k.to_s}=#{CGI.escape v.to_s}"
|
29
|
+
end
|
30
|
+
connection.post(request_str,"",self.class.headers).tap do |response|
|
31
|
+
load_attributes_from_response response
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'active_resource'
|
3
|
+
require "studio_api/util"
|
4
|
+
require "studio_api/studio_resource"
|
5
|
+
|
6
|
+
module StudioApi
|
7
|
+
# Adds ability to ActiveResource::Base (short as ARes) to easy set connection to studio in
|
8
|
+
# dynamic way, which is not so easy as ARes is designed for static values.
|
9
|
+
# Also modify a few expectation of ActiveResource to fit studio API ( like
|
10
|
+
# missing xml suffix in calls ).
|
11
|
+
#
|
12
|
+
# @example Add new Studio Resource
|
13
|
+
# # enclose it in module allows to automatic settings with Util
|
14
|
+
# module StudioApi
|
15
|
+
# class NewCoolResource < ActiveResource::Base
|
16
|
+
# extend StudioResource
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
|
20
|
+
module StudioResource
|
21
|
+
# Gets studio connection. Mostly useful internally.
|
22
|
+
# @return (StudioApi::Connection,nil) object of studio connection or nil if not
|
23
|
+
# yet set
|
24
|
+
def studio_connection
|
25
|
+
@studio_connection
|
26
|
+
end
|
27
|
+
|
28
|
+
# Takes information from connection and sets it to ActiveResource::Base.
|
29
|
+
# Also take care properly of prefix as it need to join path from site with
|
30
|
+
# api prefix like appliance/:appliance_id .
|
31
|
+
# @param (StudioApi::Connection) connection source for connection in
|
32
|
+
# activeResource
|
33
|
+
# @return (StudioApi::Connection) unmodified parameter
|
34
|
+
def studio_connection= connection
|
35
|
+
self.site = connection.uri.to_s
|
36
|
+
# there is general problem, that when specified prefix in model, it doesn't
|
37
|
+
# contain uri.path as it is not know and uri is set during runtime, so we
|
38
|
+
# must add here manually adapt prefix otherwise site.path is ommitted in
|
39
|
+
# models which has own prefix in API
|
40
|
+
unless @original_prefix
|
41
|
+
if self.prefix_source == Util.join_relative_url(connection.uri.path,'/')
|
42
|
+
@original_prefix = "/"
|
43
|
+
else
|
44
|
+
@original_prefix = self.prefix_source
|
45
|
+
end
|
46
|
+
end
|
47
|
+
self.prefix = Util.join_relative_url connection.uri.path, @original_prefix
|
48
|
+
self.user = connection.user
|
49
|
+
self.password = connection.password
|
50
|
+
self.timeout = connection.timeout
|
51
|
+
self.proxy = connection.proxy.to_s if connection.proxy
|
52
|
+
self.ssl_options = connection.ssl
|
53
|
+
@studio_connection = connection
|
54
|
+
end
|
55
|
+
|
56
|
+
# We need to overwrite the paths methods because susestudio doesn't use the
|
57
|
+
# standard .xml filename extension which is expected by ActiveResource.
|
58
|
+
def element_path(id, prefix_options = {}, query_options = nil)
|
59
|
+
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
60
|
+
"#{prefix(prefix_options)}#{collection_name}/#{id}#{query_string(query_options)}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# We need to overwrite the paths methods because susestudio doesn't use the
|
64
|
+
# standard .xml filename extension which is expected by ActiveResource.
|
65
|
+
def collection_path(prefix_options = {}, query_options = nil)
|
66
|
+
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
67
|
+
"#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "studio_api/studio_resource"
|
2
|
+
|
3
|
+
module StudioApi
|
4
|
+
# Represents template sets. It is usefull when clone appliance.
|
5
|
+
# allows only reading
|
6
|
+
class TemplateSet < ActiveResource::Base
|
7
|
+
extend StudioResource
|
8
|
+
undef_method :save
|
9
|
+
undef_method :destroy
|
10
|
+
element_name = "template_set"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module StudioApi
|
2
|
+
# Utility class for handling whole stack of Studio Api
|
3
|
+
class Util
|
4
|
+
# Set connection for all StudioApi class, so then you can use it without explicit settings
|
5
|
+
# It is useful when program use only one studio credentials
|
6
|
+
# @example
|
7
|
+
# connection = StudioApi::Connection.new ( "user", "password", "http://localhost/api")
|
8
|
+
# StudioApi::Util.configure_studio_connection connection
|
9
|
+
# appliances = StudioApi::Appliance.find :all
|
10
|
+
# @param [StudioApi::Connection] connection which is used for communication with studio
|
11
|
+
# @return [Array<Class>] return set of classes which is set
|
12
|
+
|
13
|
+
def self.configure_studio_connection connection
|
14
|
+
classes = get_all_usable_class StudioApi
|
15
|
+
classes.each {|c| c.studio_connection = connection}
|
16
|
+
end
|
17
|
+
|
18
|
+
# joins relative url for unix servers as URI.join require at least one
|
19
|
+
# absolute adress. Especially take care about only one slash otherwise studio
|
20
|
+
# returns 404.
|
21
|
+
# @param (Array<String>) args list of Strings to join
|
22
|
+
# @return (String) joined String
|
23
|
+
def self.join_relative_url(*args)
|
24
|
+
args.reduce do |base, append|
|
25
|
+
base= base[0..-2] if base.end_with? "/" #remove ending slash in base
|
26
|
+
append = append[1..-1] if append.start_with? "/" #remove leading slash in append
|
27
|
+
"#{base}/#{append}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
private
|
31
|
+
def self.get_all_usable_class (modul)
|
32
|
+
classes = modul.constants.collect{ |c| modul.const_get(c) }
|
33
|
+
classes = classes.select { |c| c.class == Class && c.respond_to?(:studio_connection=) }
|
34
|
+
inner_classes = classes.collect { |c| get_all_usable_class(c) }.flatten
|
35
|
+
classes + inner_classes
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/studio_api.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Novell, Inc.
|
3
|
+
# All Rights Reserved.
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public License as
|
7
|
+
# published by the Free Software Foundation; version 2.1 of the license.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public License
|
15
|
+
# along with this library; if not, contact Novell, Inc.
|
16
|
+
#
|
17
|
+
# To contact Novell about this file by physical or electronic mail,
|
18
|
+
# you may find current contact information at www.novell.com
|
19
|
+
|
20
|
+
require 'studio_api/appliance'
|
21
|
+
require 'studio_api/build'
|
22
|
+
require 'studio_api/connection'
|
23
|
+
require 'studio_api/file'
|
24
|
+
require 'studio_api/generic_request'
|
25
|
+
require 'studio_api/package'
|
26
|
+
require 'studio_api/pattern'
|
27
|
+
require 'studio_api/repository'
|
28
|
+
require 'studio_api/rpm'
|
29
|
+
require 'studio_api/running_build'
|
30
|
+
require 'studio_api/studio_resource'
|
31
|
+
require 'studio_api/template_set'
|