globus_client 0.8.0 → 0.9.1

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: 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.