aptly-api 0.7.0 → 0.8.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
  SHA1:
3
- metadata.gz: 9efbe6f74dd549cd105d0fcb98789e58ab3e4d79
4
- data.tar.gz: 8f2ec5e7dc006199444dcb714c3aea3e34a0940b
3
+ metadata.gz: e05f1603a52e6c576b35e475a2598c8c9b6192d0
4
+ data.tar.gz: 200046983723560e59038822e12f738c452b663b
5
5
  SHA512:
6
- metadata.gz: 3c899648d86ab6eeddc83d38368958adf3c829a1881c148beca3bb3b40c48cec0f9232c4dc6f969fbf1dffad3215f6b15fb4c0c2bffe04918e2320f702e69b18
7
- data.tar.gz: 29231774db283cfaad31859c0d6feb2355c010e1e8791ea9ec7df1d85d6b3388a2304db98b81175e054d306fecd279a9a028b355629adc8d0a0d3eca6ff445f8
6
+ metadata.gz: 9cb8262c9cfe2777f0588498cd7dcf43b656d10918345c3a08371c7eee7fd0213d73b7332f2846d579dce187b2cd4b3ab099e112d465a5f94d664eaa7fff7caf
7
+ data.tar.gz: d89fa0b8074a9c85fd76ad02586f4823f2e6f32ca38971224d595b20928ba20ee697774c6fa7f8ef71fe11882b319ad50adf5a3a3d7d3ad9c7ee0e623e3affa8
@@ -1,3 +1,6 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.1
3
3
 
4
+ # We are not going to require gems just so we can indent heredocs...
5
+ Layout/IndentHeredoc:
6
+ Enabled: false
@@ -1,5 +1,42 @@
1
1
  # Change Log
2
2
 
3
+ ## Unreleased
4
+ ### Added
5
+ - Configuration now has two new attributes timeout and write_timeout.
6
+ When you set a timeout manually on the Aptly configuration object it gets
7
+ used even if you have global timeouts set elsewhere.
8
+ As a side effect setting timeouts on faraday directly will not work anymore.
9
+ If you used to set a faraday-wide timeout we will try to use it,
10
+ iff longer than our default value. So, the effective default is at least
11
+ 15 minutes but may be longer depending on the Faraday timeout.
12
+ This Faraday fallback is getting removed in 1.0, so you should port
13
+ to the new attributes instead. For future reference you should avoid
14
+ talking to Faraday directly.
15
+ - `timeout` controls the general HTTP connection timeouts. It's set to
16
+ 1 minute by default which should be enough for most read operations.
17
+ - `write_timeout` controls the HTTP connection timeout of writing timeouts.
18
+ This applies in broad terms to all requests which we expect to require a
19
+ server-side lock to run and thus have high potential for timing out.
20
+ It defaults to 10 minutes which should allow most operations to finish.
21
+ The attribute will have tighter functionality if or when
22
+ https://github.com/smira/aptly/pull/459 gets merged and we can adopt a more
23
+ async API.
24
+ - Connection.new now takes a new `config` parameter that is the Configuration
25
+ instance to use for the Connection. This partially deprecates the `uri`
26
+ parameter which you can set through the Configuration instance now.
27
+
28
+ ```
29
+ Aptly::Connection.new(uri: uri)
30
+ # can become
31
+ Aptly::Connection.new(Aptly::Configuration.new(uri: uri))
32
+ ```
33
+
34
+ ### Changed
35
+ - Connection.new no longer catches arbitrary options but instead specifies
36
+ the accepted arguments in the method signature. It accepted two
37
+ well-known options before anyway, this enforces them properly on a language
38
+ level.
39
+
3
40
  ## [0.7.0]
4
41
  ### Added
5
42
  - Aptly.escape_prefix is a new helper method to turn prefixes into
@@ -1,3 +1,18 @@
1
+ # Copyright (C) 2015-2017 Harald Sitter <sitter@kde.org>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 3 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library. If not, see <http://www.gnu.org/licenses/>.
15
+
1
16
  require 'rubygems/deprecate'
2
17
 
3
18
  module Aptly
@@ -8,23 +23,54 @@ module Aptly
8
23
  # @!attribute uri
9
24
  # Generally any suitable URI is allowed. This can also be a Unix domain
10
25
  # socket which needs to be used in the notation unix:/tmp/sock.
11
- # @return [URI] the base URI for the API (http://localhost by default)
26
+ # @return [URI] the base URI for the API (http://localhost by default)
12
27
  attr_accessor :uri
13
28
 
29
+ # @!attribute timeout
30
+ # The request read timeout in seconds. HTTP connections not responding in
31
+ # this time limit will raise an error. Note that the server-side API is
32
+ # currently synchronous so a read request may time out for no better
33
+ # reason than it not getting a suitable database lock in time, so allowing
34
+ # for some leeway is recommended here.
35
+ # https://github.com/smira/aptly/pull/459
36
+ # @return [Integer] read timeout seconds
37
+ attr_accessor :timeout
38
+
39
+ # @!attribute write_timeout
40
+ # The request write timeout in seconds. HTTP connections not responding
41
+ # in this time limit will raise an error. When pushing data into Aptly
42
+ # or publishing large repositories this value should be suitably high.
43
+ # This timeout is used for API calls which we expect to need a write-lock
44
+ # on the server. Using a value of a couple minutes is recommended if
45
+ # you have concurrent write requests (multiple uploads from different
46
+ # sources) or the server performance isn't always assured (slow disk,
47
+ # load spikes).
48
+ # @return [Integer] write timeout seconds
49
+ attr_accessor :write_timeout
50
+
51
+ # rubocop:disable Metrics/ParameterLists So long because of deprecation.
52
+
14
53
  # Creates a new instance.
15
54
  # @param uri see {#uri}
55
+ # @param timeout see {#timeout}
56
+ # @param write_timeout see {#write_timeout}
16
57
  # @param host DEPRECATED use uri
17
58
  # @param port DEPRECATED use uri
18
59
  # @param path DEPRECATED use uri
19
60
  def initialize(uri: URI::HTTP.build(host: 'localhost',
20
61
  port: 80,
21
62
  path: '/'),
63
+ timeout: [60, faraday_default_timeout].max,
64
+ write_timeout: [10 * 60, timeout].max,
22
65
  host: nil, port: nil, path: nil)
66
+ @timeout = timeout
67
+ @write_timeout = write_timeout
23
68
  @uri = nil
24
69
  @uri = uri unless host || port || path
25
70
  return if @uri
26
71
  @uri = fallback_uri(host, port, path)
27
72
  end
73
+ # rubocop:enable Metrics/ParameterLists
28
74
 
29
75
  # @!attribute host
30
76
  # @deprecated use {#uri}
@@ -39,7 +85,7 @@ module Aptly
39
85
  # @return [String] path to use (defaults to /)
40
86
 
41
87
  # Fake deprecated attributes and redirect them to @uri
42
- [:host, :port, :path].each do |uri_attr|
88
+ %i[host port path].each do |uri_attr|
43
89
  define_method(uri_attr.to_s) do
44
90
  @uri.send(uri_attr)
45
91
  end
@@ -54,6 +100,10 @@ module Aptly
54
100
 
55
101
  private
56
102
 
103
+ def faraday_default_timeout
104
+ Faraday.default_connection_options[:request][:timeout] || -1
105
+ end
106
+
57
107
  def safe_port(port)
58
108
  port ? port.to_i : port
59
109
  end
@@ -1,7 +1,23 @@
1
+ # Copyright (C) 2015-2017 Harald Sitter <sitter@kde.org>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 3 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library. If not, see <http://www.gnu.org/licenses/>.
15
+
1
16
  require 'faraday'
2
17
  require 'json'
3
18
  require 'uri'
4
19
 
20
+ require_relative 'configuration'
5
21
  require_relative 'errors'
6
22
 
7
23
  module Aptly
@@ -10,9 +26,14 @@ module Aptly
10
26
  # automation on top of the raw HTTP actions.
11
27
  class Connection
12
28
  DEFAULT_QUERY = {}.freeze
13
- GETISH_ACTIONS = %i(get delete).freeze
14
- POSTISH_ACTIONS = %i(post put).freeze
29
+ private_constant :DEFAULT_QUERY
30
+ GETISH_ACTIONS = %i[get delete].freeze
31
+ private_constant :GETISH_ACTIONS
32
+ POSTISH_ACTIONS = %i[post put].freeze
33
+ private_constant :POSTISH_ACTIONS
15
34
  HTTP_ACTIONS = GETISH_ACTIONS + POSTISH_ACTIONS
35
+ WRITE_ACTIONS = (POSTISH_ACTIONS + %i[delete]).freeze
36
+ private_constant :WRITE_ACTIONS
16
37
 
17
38
  CODE_ERRORS = {
18
39
  400 => Errors::ClientError,
@@ -21,34 +42,44 @@ module Aptly
21
42
  409 => Errors::ConflictError,
22
43
  500 => Errors::ServerError
23
44
  }.freeze
24
-
25
- def initialize(**kwords)
26
- @query = kwords.fetch(:query, DEFAULT_QUERY)
27
- @base_uri = kwords.delete(:uri) { ::Aptly.configuration.uri.clone }
28
-
29
- raise if uri.nil?
30
- @connection = Faraday.new(uri) do |c|
45
+ private_constant :CODE_ERRORS
46
+
47
+ # New connection.
48
+ # @param config [Configuration] Configuration instance to use
49
+ # @param query [Hash] Default HTTP query paramaters, these get the
50
+ # specific query parameters merged upon.
51
+ # @param uri [URI] Base URI for the remote (default from
52
+ # {Configuration#uri}).
53
+ def initialize(config: ::Aptly.configuration, query: DEFAULT_QUERY,
54
+ uri: config.uri)
55
+ @query = query
56
+ @base_uri = uri
57
+ raise if faraday_uri.nil?
58
+ @config = config
59
+ @connection = Faraday.new(faraday_uri) do |c|
31
60
  c.request :multipart
32
61
  c.request :url_encoded
33
62
  c.adapter :excon, @adapter_options
34
63
  end
35
64
  end
36
65
 
37
- def method_missing(symbol, *args, **kwords)
38
- return super(symbol, *args, kwords) unless HTTP_ACTIONS.include?(symbol)
39
-
40
- kwords[:query] = build_query(kwords)
41
- kwords.delete(:query) if kwords[:query].empty?
66
+ HTTP_ACTIONS.each do |action|
67
+ # private api
68
+ define_method(action) do |relative_path = '', kwords = {}|
69
+ # NB: double splat is broken with Ruby 2.2.1's define_method, so we
70
+ # cannot splat kwords in the signature.
71
+ kwords[:query] = build_query(kwords)
72
+ kwords.delete(:query) if kwords[:query].empty?
42
73
 
43
- relative_path = args.shift
44
- http_call(symbol, add_api(relative_path), kwords)
74
+ http_call(action, add_api(relative_path), kwords)
75
+ end
45
76
  end
46
77
 
47
78
  private
48
79
 
49
- def uri
80
+ def faraday_uri
50
81
  @adapter_options ||= {}
51
- @uri ||= begin
82
+ @faraday_uri ||= begin
52
83
  uri = @base_uri.clone
53
84
  return uri unless uri.scheme == 'unix'
54
85
  # For Unix domain sockets we need to divide the bits apart as Excon
@@ -87,13 +118,21 @@ module Aptly
87
118
  [body, headers]
88
119
  end
89
120
 
121
+ def setup_request(action, request)
122
+ standard_timeout = @config.timeout
123
+ standard_timeout = @config.write_timeout if WRITE_ACTIONS.include?(action)
124
+ request.options.timeout = standard_timeout
125
+ end
126
+
90
127
  def run_postish(action, path, kwords)
91
128
  body = kwords.delete(:body)
92
129
  headers = kwords.delete(:headers)
93
130
 
94
131
  body, headers = mangle_post(body, headers, kwords)
95
132
 
96
- @connection.send(action, path, body, headers)
133
+ @connection.send(action, path, body, headers) do |request|
134
+ setup_request(action, request)
135
+ end
97
136
  end
98
137
 
99
138
  def run_getish(action, path, kwords)
@@ -102,6 +141,7 @@ module Aptly
102
141
  headers = kwords.delete(:headers)
103
142
 
104
143
  @connection.send(action, path, params, headers) do |request|
144
+ setup_request(action, request)
105
145
  if body
106
146
  request.headers[:content_type] = 'application/json'
107
147
  request.body = body
@@ -109,6 +149,12 @@ module Aptly
109
149
  end
110
150
  end
111
151
 
152
+ def handle_error(response)
153
+ error = CODE_ERRORS.fetch(response.status, nil)
154
+ raise error, response.body if error
155
+ response
156
+ end
157
+
112
158
  def http_call(action, path, kwords)
113
159
  if POSTISH_ACTIONS.include?(action)
114
160
  response = run_postish(action, path, kwords)
@@ -117,9 +163,9 @@ module Aptly
117
163
  else
118
164
  raise "Unknown http action: #{action}"
119
165
  end
120
- error = CODE_ERRORS.fetch(response.status, nil)
121
- raise error, response.body if error
122
- response
166
+ handle_error(response)
167
+ rescue Faraday::TimeoutError => e
168
+ raise Errors::TimeoutError, e.message
123
169
  end
124
170
  end
125
171
  end
@@ -1,4 +1,8 @@
1
1
  module Aptly
2
+ # TODO: 1.0 flatten this out. Either the classes should not have a suffix
3
+ # or they should not be in an errors module. They were originally put in
4
+ # here so its easy to view all errors in api documentation.
5
+
2
6
  # All aptly errors.
3
7
  module Errors
4
8
  # Generic HTTP error base.
@@ -22,6 +26,10 @@ module Aptly
22
26
  # Raised when a Snapshot consists of a unknown source type
23
27
  class UnknownSourceTypeError < StandardError; end
24
28
 
29
+ # Raised when a request times out waiting for the server to reply
30
+ # (this is the opposite of HTTP 408 where a server times out waiting for us)
31
+ class TimeoutError < StandardError; end
32
+
25
33
  # Raised when a file operation had an error.
26
34
  class RepositoryFileError < StandardError
27
35
  # @!attribute [r] failures
@@ -44,7 +52,7 @@ module Aptly
44
52
 
45
53
  # @return [String] (formatted) string representation
46
54
  def to_s
47
- <<-EOF
55
+ <<-DESCRIPTION
48
56
 
49
57
  ~~~
50
58
  Failed to process:
@@ -52,7 +60,7 @@ module Aptly
52
60
  Warnings:
53
61
  #{warnings.join("\n ")}
54
62
  ~~~
55
- EOF
63
+ DESCRIPTION
56
64
  end
57
65
 
58
66
  class << self
@@ -9,12 +9,8 @@ module Aptly
9
9
  # @param connection [Connection] connection to use
10
10
  # @return [Array<String>] list of files now on the remote
11
11
  def upload(files, directory, connection = Connection.new, **kwords)
12
- i = 0
13
- files.each do |f|
14
- kwords["file_#{i += 1}".to_sym] = f
15
- end
16
- response = connection.send(:post, "/files/#{directory}",
17
- kwords)
12
+ files.each_with_index { |f, i| kwords["file_#{i}".to_sym] = f }
13
+ response = connection.send(:post, "/files/#{directory}", kwords)
18
14
  JSON.parse(response.body)
19
15
  end
20
16
 
@@ -1,4 +1,4 @@
1
1
  # Aptly API
2
2
  module Aptly
3
- VERSION = '0.7.0'.freeze
3
+ VERSION = '0.8.0'.freeze
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptly-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harald Sitter
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2017-08-21 00:00:00.000000000 Z
12
+ date: 2017-11-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -167,7 +167,6 @@ files:
167
167
  - Gemfile
168
168
  - README.md
169
169
  - Rakefile
170
- - TODO
171
170
  - aptly-api.gemspec
172
171
  - bin/console
173
172
  - bin/setup
data/TODO DELETED
@@ -1,6 +0,0 @@
1
- - cookbook needs to install and run gpg to init keyring?
2
- - need signing support and testing
3
- - signing happens at publishing stage
4
-
5
- low prio:
6
- - package listing api to port install_check.rb to