globus_client 0.8.0 → 0.9.1

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
  SHA256:
3
- metadata.gz: 40f9903f67d10be16104fe3664bf68dd467b24414cb7f0c84bfb6539cd2acee5
4
- data.tar.gz: bbcc3c1f811df83d8a4d473ff3cd646b33d6f7f950aaa99c0f86e0e10165130d
3
+ metadata.gz: 4b87c64f97dd930fde77d12e01206ceb2b81900b987d1b47d8c0feb559255ef9
4
+ data.tar.gz: df241413512d952ff06fc81a7f216b79268903f5aed15147faa6f28fefa5e75d
5
5
  SHA512:
6
- metadata.gz: f5334d262c97ac5512d5a6bbaf9a0927e98fea577a318ba0b08c3dbac33bfbb53c01bdb95205df271886c36df2ce7144c078e7ae8deadc5bea8af9a8d9180479
7
- data.tar.gz: a850d0854a936f24653d0ebf0bfd96be478ab2a0c6be908c1cd47defb3872b306281a35d56b76cff898cc48ba9340d20dde4d4a96051d36007d6c29d3f5a4a53
6
+ metadata.gz: 6bcb102fa5457fc3f8ef38794efa9b2528c1ab608c62c54657f8d65bc0073e2d5f7e564a37f91ec111f91bfdbaa2e5900fd3f9b487896ef79069178d0c5be98c
7
+ data.tar.gz: 977be8baca2ebdbcecc0d47d26ccb8b273a199252ee71a56cff3d25751dd3d5c58fd46b5a5abe57324d3005a1f699e87832df345c808a13229473c2ce30708a2
data/Gemfile.lock CHANGED
@@ -1,15 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- globus_client (0.8.0)
4
+ globus_client (0.9.1)
5
5
  activesupport (>= 4.2, < 8)
6
6
  faraday
7
+ faraday-retry
7
8
  zeitwerk
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
- activesupport (7.0.4)
13
+ activesupport (7.0.4.2)
13
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
14
15
  i18n (>= 1.6, < 2)
15
16
  minitest (>= 5.1)
@@ -18,59 +19,64 @@ GEM
18
19
  public_suffix (>= 2.0.2, < 6.0)
19
20
  ast (2.4.2)
20
21
  byebug (11.1.3)
21
- concurrent-ruby (1.1.10)
22
+ concurrent-ruby (1.2.2)
22
23
  crack (0.4.5)
23
24
  rexml
24
25
  diff-lcs (1.5.0)
25
26
  docile (1.4.0)
26
- faraday (2.7.2)
27
+ faraday (2.7.4)
27
28
  faraday-net_http (>= 2.0, < 3.1)
28
29
  ruby2_keywords (>= 0.0.4)
29
30
  faraday-net_http (3.0.2)
31
+ faraday-retry (2.0.0)
32
+ faraday (~> 2.0)
30
33
  hashdiff (1.0.1)
31
34
  i18n (1.12.0)
32
35
  concurrent-ruby (~> 1.0)
33
36
  json (2.6.3)
34
- language_server-protocol (3.17.0.2)
37
+ language_server-protocol (3.17.0.3)
35
38
  minitest (5.17.0)
36
39
  parallel (1.22.1)
37
- parser (3.2.0.0)
40
+ parser (3.2.1.0)
38
41
  ast (~> 2.4.1)
39
42
  public_suffix (5.0.1)
40
43
  rainbow (3.1.1)
41
44
  rake (13.0.6)
42
- regexp_parser (2.6.1)
45
+ regexp_parser (2.7.0)
43
46
  rexml (3.2.5)
44
47
  rspec (3.12.0)
45
48
  rspec-core (~> 3.12.0)
46
49
  rspec-expectations (~> 3.12.0)
47
50
  rspec-mocks (~> 3.12.0)
48
- rspec-core (3.12.0)
51
+ rspec-core (3.12.1)
49
52
  rspec-support (~> 3.12.0)
50
53
  rspec-expectations (3.12.2)
51
54
  diff-lcs (>= 1.2.0, < 2.0)
52
55
  rspec-support (~> 3.12.0)
53
- rspec-mocks (3.12.2)
56
+ rspec-mocks (3.12.3)
54
57
  diff-lcs (>= 1.2.0, < 2.0)
55
58
  rspec-support (~> 3.12.0)
56
59
  rspec-support (3.12.0)
57
- rubocop (1.42.0)
60
+ rubocop (1.44.1)
58
61
  json (~> 2.3)
59
62
  parallel (~> 1.10)
60
- parser (>= 3.1.2.1)
63
+ parser (>= 3.2.0.0)
61
64
  rainbow (>= 2.2.2, < 4.0)
62
65
  regexp_parser (>= 1.8, < 3.0)
63
66
  rexml (>= 3.2.5, < 4.0)
64
67
  rubocop-ast (>= 1.24.1, < 2.0)
65
68
  ruby-progressbar (~> 1.7)
66
- unicode-display_width (>= 1.4.0, < 3.0)
67
- rubocop-ast (1.24.1)
68
- parser (>= 3.1.1.0)
69
+ unicode-display_width (>= 2.4.0, < 3.0)
70
+ rubocop-ast (1.26.0)
71
+ parser (>= 3.2.1.0)
72
+ rubocop-capybara (2.17.1)
73
+ rubocop (~> 1.41)
69
74
  rubocop-performance (1.15.2)
70
75
  rubocop (>= 1.7.0, < 2.0)
71
76
  rubocop-ast (>= 0.4.0)
72
- rubocop-rspec (2.16.0)
77
+ rubocop-rspec (2.18.1)
73
78
  rubocop (~> 1.33)
79
+ rubocop-capybara (~> 2.17)
74
80
  ruby-progressbar (1.11.0)
75
81
  ruby2_keywords (0.0.5)
76
82
  simplecov (0.22.0)
@@ -79,23 +85,24 @@ GEM
79
85
  simplecov_json_formatter (~> 0.1)
80
86
  simplecov-html (0.12.3)
81
87
  simplecov_json_formatter (0.1.4)
82
- standard (1.21.1)
88
+ standard (1.24.3)
83
89
  language_server-protocol (~> 3.17.0.2)
84
- rubocop (= 1.42.0)
90
+ rubocop (= 1.44.1)
85
91
  rubocop-performance (= 1.15.2)
86
- tzinfo (2.0.5)
92
+ tzinfo (2.0.6)
87
93
  concurrent-ruby (~> 1.0)
88
94
  unicode-display_width (2.4.2)
89
95
  webmock (3.18.1)
90
96
  addressable (>= 2.8.0)
91
97
  crack (>= 0.3.2)
92
98
  hashdiff (>= 0.4.0, < 2.0.0)
93
- zeitwerk (2.6.6)
99
+ zeitwerk (2.6.7)
94
100
 
95
101
  PLATFORMS
96
102
  x86_64-darwin-19
97
103
  x86_64-darwin-20
98
104
  x86_64-darwin-21
105
+ x86_64-darwin-22
99
106
  x86_64-linux
100
107
 
101
108
  DEPENDENCIES
data/api_test.rb CHANGED
@@ -30,6 +30,10 @@ Benchmark.bm(20) do |benchmark|
30
30
  @before_permissions = GlobusClient::Endpoint.new(GlobusClient.config, user_id:, path:).send(:access_rule)["permissions"]
31
31
  end
32
32
 
33
+ benchmark.report("has_files?:") do
34
+ @has_files = GlobusClient.has_files?(user_id:, path:)
35
+ end
36
+
33
37
  benchmark.report("list_files:") do
34
38
  GlobusClient.list_files(user_id:, path:) do |files|
35
39
  @files_count = files.count
@@ -49,6 +53,7 @@ Benchmark.bm(20) do |benchmark|
49
53
 
50
54
  puts "User #{user_id} exists: #{@user_exists}"
51
55
  puts "Initial directory permissions: #{@before_permissions}"
56
+ puts "Directory has files? #{@has_files}"
52
57
  puts "Number of files in directory: #{@files_count}"
53
58
  puts "Total size of files in directory: #{@total_size}"
54
59
  puts "List of files in directory: #{@files_list}"
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
33
33
 
34
34
  spec.add_dependency "activesupport", ">= 4.2", "< 8"
35
35
  spec.add_dependency "faraday"
36
+ spec.add_dependency "faraday-retry"
36
37
  spec.add_dependency "zeitwerk"
37
38
 
38
39
  spec.add_development_dependency "rake", "~> 13.0"
@@ -16,6 +16,10 @@ class GlobusClient
16
16
  @path = path
17
17
  end
18
18
 
19
+ def has_files?
20
+ ls_path(full_path, [], return_presence: true)
21
+ end
22
+
19
23
  def list_files
20
24
  ls_path(full_path, []).tap do |files|
21
25
  yield files if block_given?
@@ -61,11 +65,20 @@ class GlobusClient
61
65
  attr_reader :config, :path, :user_id
62
66
 
63
67
  def connection
64
- # Transfer API connection
68
+ # faraday/retry is used here to catch Faraday::ConnectionFailed exceptions
69
+ # see: https://github.com/sul-dlss/happy-heron/issues/3008
65
70
  @connection ||= Faraday.new(
66
71
  url: config.transfer_url,
67
72
  headers: {Authorization: "Bearer #{config.token}"}
68
- )
73
+ ) do |faraday|
74
+ faraday.request :retry, {
75
+ max: 10,
76
+ interval: 0.05,
77
+ interval_randomness: 0.5,
78
+ backoff_factor: 2,
79
+ exceptions: Faraday::Retry::Middleware::DEFAULT_EXCEPTIONS + [Faraday::ConnectionFailed]
80
+ }
81
+ end
69
82
  end
70
83
 
71
84
  def globus_identity_id
@@ -90,25 +103,38 @@ class GlobusClient
90
103
  end
91
104
 
92
105
  def path_segments
106
+ raise ArgumentError, "Unexpected path provided: #{path.inspect}" unless path.respond_to?(:split)
107
+
93
108
  path.split(PATH_SEPARATOR)
94
109
  end
95
110
 
111
+ # List files recursively at an endpoint https://docs.globus.org/api/transfer/file_operations/#list_directory_contents
96
112
  # @param filepath [String] an absolute path to look up contents e.g. /uploads/example/work123/version1
97
113
  # @param files [Array<FileInfo>] an array of FileInfo structs, each of which has a name and a size
98
- def ls_path(filepath, files)
99
- # List files recursively at an endpoint https://docs.globus.org/api/transfer/file_operations/#list_directory_contents
114
+ # @param return_presence [Boolean] if true, return a boolean to indicate if any files at all are present, short-circuiting the recursive operation
115
+ def ls_path(filepath, files, return_presence: false)
100
116
  response = connection.get("#{transfer_path}/ls?path=#{filepath}")
101
- if response.success?
102
- data = JSON.parse(response.body)["DATA"]
103
- data
104
- .select { |object| object["type"] == "file" }
105
- .each { |file| files << FileInfo.new("#{filepath}#{file["name"]}", file["size"]) }
106
- data
107
- .select { |object| object["type"] == "dir" }
108
- .each { |dir| ls_path("#{filepath}#{dir["name"]}/", files) }
109
- else
110
- UnexpectedResponse.call(response)
117
+ return UnexpectedResponse.call(response) unless response.success?
118
+
119
+ data = JSON.parse(response.body)["DATA"]
120
+ data
121
+ .select { |object| object["type"] == "file" }
122
+ .each do |file|
123
+ return true if return_presence
124
+
125
+ files << FileInfo.new("#{filepath}#{file["name"]}", file["size"])
126
+ end
127
+ data
128
+ .select { |object| object["type"] == "dir" }
129
+ .each do |dir|
130
+ # NOTE: This allows the recursive method to short-circuit iff ls_path
131
+ # returns true, which only happens when return_presence is true
132
+ # and the first file is found in the ls operation.
133
+ return true if ls_path("#{filepath}#{dir["name"]}/", files, return_presence:) == true
111
134
  end
135
+
136
+ return false if return_presence
137
+
112
138
  files
113
139
  end
114
140
 
@@ -3,7 +3,7 @@
3
3
  class GlobusClient
4
4
  # Wraps API operations to request new access token if expired
5
5
  class TokenWrapper
6
- def self.refresh(config, &block)
6
+ def self.refresh(config)
7
7
  yield
8
8
  rescue UnexpectedResponse::UnauthorizedError
9
9
  config.token = Authenticator.token(config.client_id, config.client_secret, config.auth_url)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class GlobusClient
4
- VERSION = "0.8.0"
4
+ VERSION = "0.9.1"
5
5
  end
data/lib/globus_client.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "active_support/core_ext/module/delegation"
4
4
  require "faraday"
5
+ require "faraday/retry"
5
6
  require "ostruct"
6
7
  require "singleton"
7
8
  require "zeitwerk"
@@ -34,7 +35,8 @@ class GlobusClient
34
35
  self
35
36
  end
36
37
 
37
- delegate :config, :disallow_writes, :file_count, :list_files, :mkdir, :total_size, :user_exists?, :get_filenames, to: :instance
38
+ delegate :config, :disallow_writes, :file_count, :list_files, :mkdir, :total_size,
39
+ :user_exists?, :get_filenames, :has_files?, to: :instance
38
40
 
39
41
  def default_transfer_url
40
42
  "https://transfer.api.globusonline.org"
@@ -93,6 +95,13 @@ class GlobusClient
93
95
  end
94
96
  end
95
97
 
98
+ def has_files?(...)
99
+ TokenWrapper.refresh(config) do
100
+ endpoint = Endpoint.new(config, ...)
101
+ endpoint.has_files?
102
+ end
103
+ end
104
+
96
105
  def user_exists?(...)
97
106
  TokenWrapper.refresh(config) do
98
107
  identity = Identity.new(config)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: globus_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Collier
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2023-01-09 00:00:00.000000000 Z
13
+ date: 2023-03-01 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -46,6 +46,20 @@ dependencies:
46
46
  - - ">="
47
47
  - !ruby/object:Gem::Version
48
48
  version: '0'
49
+ - !ruby/object:Gem::Dependency
50
+ name: faraday-retry
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
49
63
  - !ruby/object:Gem::Dependency
50
64
  name: zeitwerk
51
65
  requirement: !ruby/object:Gem::Requirement
@@ -195,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
209
  - !ruby/object:Gem::Version
196
210
  version: '0'
197
211
  requirements: []
198
- rubygems_version: 3.3.3
212
+ rubygems_version: 3.4.6
199
213
  signing_key:
200
214
  specification_version: 4
201
215
  summary: Interface for interacting with the Globus API.