aptly-api 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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