open-build-service-api 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c5e147324f417fe00b366de7fbf147ba8226703afa23629694849d3432d1aea
4
- data.tar.gz: 96295d4f01c7f1988e1c491977d96f45a749abab67cb8559238cb3ef63afae1b
3
+ metadata.gz: 1f1e3cde838735b8f74df547f7409ad60ded20f5cdd25f6acd8e1328abcc14ad
4
+ data.tar.gz: 12e82fd311a6ffb074722f12d2edc25bbda0a0a6f89c8147155ed0856bfaa6bc
5
5
  SHA512:
6
- metadata.gz: ef3d73d904f39553846c60741c94aa52e3910140ba17ed352d686482e843aee016229aa20817bcb5f8155a889378e3783cd1e06787946c9d67a9e0339a288090
7
- data.tar.gz: 57d6e4b7f432b578a8deb7988ddacddd3a718da08390074fa773e6264cacb071adc1163f8481236c460212116c5605fd98c2ae9b4bd813d05994b071cd2d0ae8
6
+ metadata.gz: 1ff27e3f77889b45615a9042a1a8e1f340fe048fc8d64bcef26e1477d1f518089fdeaeb9dc34b18e5187c8d167bdd491c3ad20ee5a6916e2616b8dc16e1708f4
7
+ data.tar.gz: '019080bdede8c641971efc2f56ed07b4147f0e4eb546fdc8db09eba905688131f66e40c6a89d2a577383a4d87cdf5ab762ad293c24a57e3cc8fdd27ddebd3759'
@@ -1,3 +1,13 @@
1
+ ## Version: 0.3.0 (alpha)
2
+
3
+ - Added `#rebuild_failed!` method to `Package` model to rebuild only failed builds
4
+ - Added setter methods for package title and description
5
+ - Added `#dirty?` method to `Package` model to identify if a package needs to be saved
6
+ - Added `#repositories` method to `Project` model to list all build repositories
7
+ - Added `#binaries` method to `Package` model to list all built binaries
8
+ - Added `#run_service!` method to `Package` model to trigger remote services
9
+ - Added `#sources` method to `Package` model to retrieve sources of a package container
10
+
1
11
  ## Version: 0.2.0 (alpha)
2
12
 
3
13
  - Added `#public_key` method to `Project` model to retrieve a project's public key
@@ -3,7 +3,7 @@ module OpenBuildServiceAPI
3
3
  include Enumerable
4
4
  extend Forwardable
5
5
 
6
- def_delegators :@data, :each, :count
6
+ def_delegators :@data, :each, :count, :empty?
7
7
 
8
8
  def inspect
9
9
  count = 1
@@ -0,0 +1,18 @@
1
+ module OpenBuildServiceAPI
2
+ class BinariesCollection < AbstractCollection
3
+ attr_accessor :package
4
+
5
+ def initialize(params = {})
6
+ raise ArgumentError.new('The dataset needs to be provided as an Array.') if params[:data] && !params[:data].is_a?(Array)
7
+
8
+ @connection = params[:connection]
9
+ @package = params[:package]
10
+ @data = params[:data] ? params[:data] : []
11
+ end
12
+
13
+ def delete_all!
14
+ @connection.send_request(:post, "/build/#{CGI.escape(@package.project.name)}", cmd: :wipe, package: @package.name)
15
+ true
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module OpenBuildServiceAPI
2
+ class SourcesCollection < AbstractCollection
3
+ attr_accessor :package
4
+
5
+ def initialize(params = {})
6
+ raise ArgumentError.new('The dataset needs to be provided as an Array.') if params[:data] && !params[:data].is_a?(Array)
7
+
8
+ @connection = params[:connection]
9
+ @package = params[:package]
10
+ @data = params[:data] ? params[:data] : []
11
+ end
12
+ end
13
+ end
@@ -40,9 +40,11 @@ module OpenBuildServiceAPI
40
40
  class PackageDeletionPermissionError < APIError; end
41
41
  class PackageAlreadyExistsError < APIError; end
42
42
  class PackageNotFoundError < APIError; end
43
+ class NoSourceServiceDefinedError < APIError; end
43
44
 
44
45
  # library specific exceptions
45
46
  class GeneralError < Exception; end
46
47
  class ConnectionError < GeneralError; end
47
48
  class InvalidHTTPMethodWithBody < GeneralError; end
49
+ class InvalidDownloadDirectoryPath < GeneralError; end
48
50
  end
@@ -0,0 +1,7 @@
1
+ module OpenBuildServiceAPI
2
+ module BinaryHelper
3
+ def self.binary_file?(file_name)
4
+ file_name.end_with?('.rpm') || file_name.end_with?('.deb') || file_name.end_with?('.qcow2')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,54 @@
1
+ module OpenBuildServiceAPI
2
+ class Binary
3
+ attr_reader :name, :size, :created_at, :repository, :architecture, :local_file_path, :local_path
4
+ attr_accessor :package
5
+
6
+ def initialize(params = {})
7
+ raise ArgumentError.new('repository needs to be an instance of OpenBuildServiceAPI::Repository') unless params[:repository].is_a?(Repository)
8
+
9
+ @name = params[:name]
10
+ @size = Filesize.from(params[:size])
11
+ @created_at = Time.at(params[:created_at])
12
+ @repository = params[:repository]
13
+ @architecture = params[:architecture]
14
+ @package = params[:package]
15
+ @connection = params[:connection]
16
+ end
17
+
18
+ def to_s
19
+ @name
20
+ end
21
+
22
+ def download(destination=nil)
23
+ delete_local_copy!
24
+
25
+ if destination
26
+ raise InvalidDownloadDirectoryPath.new("Path '#{destination}' is not a directory.") unless File.directory?(destination)
27
+
28
+ destination = destination[0..-2] if destination.end_with?('/')
29
+ @tmp_dir = false
30
+ else
31
+ destination = Dir.mktmpdir('obs-binary-download')
32
+ @tmp_dir = true
33
+ end
34
+
35
+ @local_file_path = "#{destination}/#{@name}"
36
+ @local_path = destination
37
+
38
+ response = @connection.send_request(:get, "/build/#{CGI.escape(@package.project.name)}/#{CGI.escape(@repository.to_s)}/" \
39
+ "#{CGI.escape(@architecture)}/#{CGI.escape(@package.name)}/#{CGI.escape(@name)}")
40
+ File.write(@local_file_path, response.body)
41
+ @local_file_path
42
+ end
43
+
44
+ def delete_local_copy!
45
+ return false unless @local_file_path
46
+ return false unless File.exists?(@local_file_path)
47
+
48
+ File.delete(@local_file_path)
49
+ FileUtils.rm_r(@local_path) if Dir.empty?(@local_path) && @tmp_dir
50
+
51
+ true
52
+ end
53
+ end
54
+ end
@@ -14,15 +14,43 @@ module OpenBuildServiceAPI
14
14
  end
15
15
 
16
16
  def title
17
+ return @title_updated if @title_updated
18
+
17
19
  title = meta.xpath('//package/title')
18
20
  title.empty? ? nil : title[0].text
19
21
  end
20
22
 
23
+ def title=(value)
24
+ @dirty = true
25
+ @title_updated = value
26
+ end
27
+
21
28
  def description
29
+ return @description_updated if @description_updated
30
+
22
31
  description = meta.xpath('//package/description')
23
32
  description.empty? ? nil : description[0].text
24
33
  end
25
34
 
35
+ def description=(value)
36
+ @dirty = true
37
+ @description_updated = value
38
+ end
39
+
40
+ def run_service!
41
+ begin
42
+ @connection.send_request(:post, "/source/#{CGI.escape(@project.name)}/#{CGI.escape(@name)}", cmd: :runservice)
43
+ rescue RequestError => err
44
+ if err.error_code == 'not_found' && err.error_summary =~ /no source service defined/
45
+ raise NoSourceServiceDefinedError.new("Package '#{@name}' in project '#{@project.name}' has no source service defined.")
46
+ end
47
+
48
+ raise
49
+ end
50
+
51
+ true
52
+ end
53
+
26
54
  def meta(opts = {})
27
55
  if !@cached_meta || @meta_reload
28
56
  @cached_meta = @connection.send_request(:get, "/source/#{CGI.escape(@project.name)}/#{CGI.escape(@name)}/_meta").body
@@ -36,6 +64,69 @@ module OpenBuildServiceAPI
36
64
  end
37
65
  end
38
66
 
67
+ def sources
68
+ return @cached_sources if @cached_sources && !@sources_reload
69
+ collection_data = []
70
+
71
+ response_xml = Nokogiri::XML(@connection.send_request(:get, "/source/#{CGI.escape(@project.name)}/#{CGI.escape(@name)}").body)
72
+ response_xml.xpath('//entry').each do |file|
73
+ collection_data << Source.new(
74
+ name: file.attr('name'),
75
+ md5_hash: file.attr('md5'),
76
+ size: file.attr('size'),
77
+ updated_at: file.attr('mtime').to_i,
78
+ package: self,
79
+ connection: @connection
80
+ )
81
+ end
82
+
83
+ @sources_reload = false
84
+ @cached_sources = SourcesCollection.new(data: collection_data, package: self, connection: @connection)
85
+ end
86
+
87
+ def binaries
88
+ collection_data = []
89
+
90
+ @project.repositories.each do |repository|
91
+ binary_data = { repository: repository, binaries: [] }
92
+
93
+ repository.architectures.each do |arch|
94
+ begin
95
+ response = @connection.send_request(:get, "/build/#{CGI.escape(@project.name)}/#{CGI.escape(repository.to_s)}/#{CGI.escape(arch)}/#{CGI.escape(@name)}")
96
+ response_xml = Nokogiri::XML(response.body)
97
+
98
+ response_xml.xpath('//binarylist/binary').each do |binary|
99
+ file_name = binary.attr('filename')
100
+ file_size = binary.attr('size')
101
+ created_at = binary.attr('mtime').to_i
102
+
103
+ if BinaryHelper.binary_file?(file_name)
104
+ binary_data[:binaries] << Binary.new(
105
+ name: file_name,
106
+ size: file_size,
107
+ architecture: arch,
108
+ created_at: created_at,
109
+ repository: repository,
110
+ package: self,
111
+ connection: @connection
112
+ )
113
+ end
114
+ end
115
+ rescue RequestError => err
116
+ # in case the repository does no longer exist, we can ignore it. there are no binaries anyways
117
+ next if err.error_code == '404' && err.error_summary =~ /has no repository/
118
+
119
+ # raise any other error
120
+ raise
121
+ end
122
+ end
123
+
124
+ collection_data << binary_data unless binary_data[:binaries].empty?
125
+ end
126
+
127
+ BinariesCollection.new(data: collection_data, connection: @connection, package: self)
128
+ end
129
+
39
130
  def inspect
40
131
  "#<#{self.class.name}:#{"0x00%x" % (object_id << 1)} @name=\"#{@name}\", @project=\"#{@project.name}\">"
41
132
  end
@@ -45,6 +136,39 @@ module OpenBuildServiceAPI
45
136
  true
46
137
  end
47
138
 
139
+ def rebuild_failed!
140
+ @connection.send_request(:post, "/build/#{CGI.escape(@project.name)}", cmd: :rebuild, package: @name, code: :failed)
141
+ true
142
+ end
143
+
144
+ def dirty?
145
+ !!@dirty
146
+ end
147
+
148
+ def save!
149
+ return false unless @dirty
150
+
151
+ @meta_reload = true
152
+ meta_xml = meta
153
+
154
+ meta_xml.xpath('//package/title')[0].content = @title_updated if @title_updated
155
+ meta_xml.xpath('//package/description')[0].content = @description_updated if @description_updated
156
+
157
+ # update meta definition
158
+ @connection.send_request(:put, "/source/#{CGI.escape(@project.name)}/#{CGI.escape(@name)}/_meta", request_body: meta_xml.to_xml)
159
+
160
+ # reset updated values
161
+ @dirty = false
162
+
163
+ @title_updated = nil
164
+ @description_updated = nil
165
+
166
+ # updated cached meta
167
+ @cached_meta = meta_xml.to_xml
168
+
169
+ true
170
+ end
171
+
48
172
  def delete!(message=nil)
49
173
  begin
50
174
  @connection.send_request(:delete, "/source/#{CGI.escape(@project.name)}/#{CGI.escape(@name)}", comment: message)
@@ -59,6 +183,7 @@ module OpenBuildServiceAPI
59
183
 
60
184
  def reload!
61
185
  @meta_reload = true
186
+ @sources_reload = true
62
187
  end
63
188
  end
64
189
  end
@@ -25,6 +25,29 @@ module OpenBuildServiceAPI
25
25
  end
26
26
  end
27
27
 
28
+ def repositories
29
+ collection_data = []
30
+
31
+ meta.xpath('//repository').each do |repository|
32
+ paths = []
33
+ archs = []
34
+
35
+ repository.children.each do |child|
36
+ if child.is_a?(Nokogiri::XML::Element)
37
+ if child.name == 'path'
38
+ paths << { project: child.attr('project'), repository: child.attr('repository') }
39
+ elsif child.name == 'arch'
40
+ archs << child.text
41
+ end
42
+ end
43
+ end
44
+
45
+ collection_data << Repository.new(name: repository.attr('name'), paths: paths, architectures: archs, connection: @connection, project: self)
46
+ end
47
+
48
+ collection_data
49
+ end
50
+
28
51
  def delete!(message=nil)
29
52
  begin
30
53
  @connection.send_request(:delete, "/source/#{CGI.escape(@name)}", comment: message)
@@ -0,0 +1,25 @@
1
+ module OpenBuildServiceAPI
2
+ class Repository
3
+ attr_accessor :name, :project
4
+
5
+ def initialize(params = {})
6
+ @name = params[:name]
7
+ @paths = params[:paths]
8
+ @architectures = params[:architectures]
9
+ @project = params[:project]
10
+ @connection = params[:connection]
11
+ end
12
+
13
+ def to_s
14
+ @name
15
+ end
16
+
17
+ def paths
18
+ @paths
19
+ end
20
+
21
+ def architectures
22
+ @architectures
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module OpenBuildServiceAPI
2
+ class Source
3
+ attr_reader :name, :md5_hash, :size, :updated_at
4
+ attr_accessor :package
5
+
6
+ def initialize(params = {})
7
+ @name = params[:name]
8
+ @md5_hash = params[:md5_hash]
9
+ @size = Filesize.from(params[:size])
10
+ @updated_at = Time.at(params[:updated_at])
11
+ @package = params[:package]
12
+ @connection = params[:connection]
13
+ end
14
+
15
+ def to_s
16
+ @name
17
+ end
18
+ end
19
+ end
@@ -1,8 +1,11 @@
1
1
  require 'cgi'
2
2
  require 'date'
3
+ require 'filesize'
4
+ require 'fileutils'
3
5
  require 'forwardable'
4
6
  require 'net/http'
5
7
  require 'nokogiri'
8
+ require 'tmpdir'
6
9
  require_relative 'version'
7
10
  require_relative 'exception'
8
11
  require_relative 'connection'
@@ -11,10 +14,18 @@ require_relative 'connection'
11
14
  require_relative 'api/about'
12
15
  require_relative 'api/projects'
13
16
 
17
+ # Helpers
18
+ require_relative 'helpers/binary_helper'
19
+
14
20
  # Collections
15
21
  require_relative 'collections/abstract_collection'
22
+ require_relative 'collections/binaries_collection'
16
23
  require_relative 'collections/packages_collection'
24
+ require_relative 'collections/sources_collection'
17
25
 
18
26
  # Models
27
+ require_relative 'models/binary'
19
28
  require_relative 'models/package'
20
29
  require_relative 'models/project'
30
+ require_relative 'models/repository'
31
+ require_relative 'models/source'
@@ -1,4 +1,4 @@
1
1
  module OpenBuildServiceAPI
2
- VERSION = '0.2.0'
3
- RELEASE_DATE = '2019-06-24'
2
+ VERSION = '0.3.0'
3
+ RELEASE_DATE = '2019-06-25'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: open-build-service-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manuel Schnitzer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-24 00:00:00.000000000 Z
11
+ date: 2019-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: date
@@ -70,6 +70,46 @@ dependencies:
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
72
  version: 1.10.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: filesize
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0.2'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.2.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.2'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 0.2.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: fileutils
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.2'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.2.0
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.2'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 1.2.0
73
113
  - !ruby/object:Gem::Dependency
74
114
  name: byebug
75
115
  requirement: !ruby/object:Gem::Requirement
@@ -121,11 +161,17 @@ files:
121
161
  - lib/api/about.rb
122
162
  - lib/api/projects.rb
123
163
  - lib/collections/abstract_collection.rb
164
+ - lib/collections/binaries_collection.rb
124
165
  - lib/collections/packages_collection.rb
166
+ - lib/collections/sources_collection.rb
125
167
  - lib/connection.rb
126
168
  - lib/exception.rb
169
+ - lib/helpers/binary_helper.rb
170
+ - lib/models/binary.rb
127
171
  - lib/models/package.rb
128
172
  - lib/models/project.rb
173
+ - lib/models/repository.rb
174
+ - lib/models/source.rb
129
175
  - lib/open-build-service-api.rb
130
176
  - lib/version.rb
131
177
  homepage: https://github.com/mschnitzer/open-build-service-api