1- struct S3Path{A<: AbstractAWSConfig } <: AbstractPath
1+ struct S3Path{A<: AbstractS3PathConfig } <: AbstractPath
22 segments:: Tuple{Vararg{String}}
33 root:: String
44 drive:: String
@@ -21,7 +21,7 @@ function S3Path(
2121 drive:: AbstractString ,
2222 isdirectory:: Bool ,
2323 version:: AbstractS3Version ,
24- config:: AbstractAWSConfig ,
24+ config:: AbstractS3PathConfig ,
2525)
2626 return S3Path {typeof(config)} (segments, root, drive, isdirectory, version, config)
2727end
4040
4141"""
4242 S3Path()
43- S3Path(str; version=nothing, config::AbstractAWSConfig=global_aws_config() )
43+ S3Path(str; config::$(AbstractS3PathConfig) =nothing, version=nothing )
4444
4545Construct a new AWS S3 path type which should be of the form
4646"s3://<bucket>/prefix/to/my/object".
@@ -60,23 +60,23 @@ NOTES:
6060- If `version` argument is `nothing`, will return latest version of object. Version
6161 can be provided via either kwarg `version` or as suffix "?versionId=<object_version>"
6262 of `str`, e.g., "s3://<bucket>/prefix/to/my/object?versionId=<object_version>".
63+ - If `config` is left at its default value of `nothing`, then the
64+ latest `global_aws_config()` will be used in any operations involving the
65+ path. To "freeze" the config at construction time, explicitly pass an
66+ `AbstractAWSConfig` to the `config` keyword argument.
67+ - If `version` argument is `nothing`, will return latest version of object.
6368"""
64- function S3Path ()
65- config = global_aws_config ()
66- account_id = aws_account_number (config)
67- region = config. region
69+ S3Path () = S3Path ((), " /" , " " , true , nothing , nothing )
6870
69- return S3Path ((), " /" , " s3://$account_id -$region " , true , nothing , config)
70- end
7171# below definition needed by FilePathsBase
72- S3Path {A} () where {A<: AbstractAWSConfig } = S3Path ()
72+ S3Path {A} () where {A<: AbstractS3PathConfig } = S3Path ()
7373
7474function S3Path (
7575 bucket:: AbstractString ,
7676 key:: AbstractString ;
7777 isdirectory:: Bool = false ,
7878 version:: AbstractS3Version = nothing ,
79- config:: AbstractAWSConfig = global_aws_config () ,
79+ config:: AbstractS3PathConfig = nothing ,
8080)
8181 return S3Path (
8282 Tuple (filter! (! isempty, split (key, " /" ))),
@@ -93,7 +93,7 @@ function S3Path(
9393 key:: AbstractPath ;
9494 isdirectory:: Bool = false ,
9595 version:: AbstractS3Version = nothing ,
96- config:: AbstractAWSConfig = global_aws_config () ,
96+ config:: AbstractS3PathConfig = nothing ,
9797)
9898 return S3Path (
9999 key. segments, " /" , normalize_bucket_name (bucket), isdirectory, version, config
103103# To avoid a breaking change.
104104function S3Path (
105105 str:: AbstractString ;
106- config:: AbstractAWSConfig = global_aws_config (),
107106 version:: AbstractS3Version = nothing ,
107+ config:: AbstractS3PathConfig = nothing ,
108108)
109109 result = tryparse (S3Path, str; config= config)
110110 result != = nothing || throw (ArgumentError (" Invalid s3 path string: $str " ))
@@ -117,16 +117,12 @@ function S3Path(
117117 return result
118118end
119119
120- # if config=nothing, will not try to talk to AWS until after string is confirmed to be an s3 path
121120function Base. tryparse (
122- :: Type{<:S3Path} , str:: AbstractString ; config:: Union{Nothing,AbstractAWSConfig} = nothing
121+ :: Type{<:S3Path} , str:: AbstractString ; config:: AbstractS3PathConfig = nothing
123122)
124123 uri = URI (str)
125124 uri. scheme == " s3" || return nothing
126125
127- # we do this here so that the `@p_str` macro only tries to call AWS if it actually has an S3 path
128- config === nothing && (config = global_aws_config ())
129-
130126 drive = " s3://$(uri. host) "
131127 root = isempty (uri. path) ? " " : " /"
132128 isdirectory = isempty (uri. path) || endswith (uri. path, ' /' )
@@ -207,9 +203,13 @@ function FilePathsBase.parents(fp::S3Path)
207203 end
208204end
209205
206+ # Use `fp.config` unless it is nothing; in that case, get the latest `global_aws_config`
207+ get_config (fp:: S3Path ) = @something (fp. config, global_aws_config ())
208+
210209function FilePathsBase. exists (fp:: S3Path )
211- return s3_exists (fp . config , fp. bucket, fp. key; version= fp. version)
210+ return s3_exists (get_config (fp) , fp. bucket, fp. key; version= fp. version)
212211end
212+
213213Base. isfile (fp:: S3Path ) = ! fp. isdirectory && exists (fp)
214214function Base. isdir (fp:: S3Path )
215215 if isempty (fp. segments)
@@ -220,7 +220,7 @@ function Base.isdir(fp::S3Path)
220220 return false
221221 end
222222
223- objects = s3_list_objects (fp . config , fp. bucket, key; max_items= 1 )
223+ objects = s3_list_objects (get_config (fp) , fp. bucket, key; max_items= 1 )
224224
225225 # `objects` is a `Channel`, so we call iterate to see if there are any objects that
226226 # match our directory key.
231231
232232function FilePathsBase. walkpath (fp:: S3Path ; kwargs... )
233233 # Select objects with that prefix
234- objects = s3_list_objects (fp . config , fp. bucket, fp. key; delimiter= " " )
234+ objects = s3_list_objects (get_config (fp) , fp. bucket, fp. key; delimiter= " " )
235235
236236 # Construct a new Channel using a recursive internal `_walkpath!` function
237237 return Channel (; ctype= typeof (fp)) do chnl
@@ -299,7 +299,8 @@ function Base.stat(fp::S3Path)
299299 last_modified = DateTime (0 )
300300
301301 if exists (fp)
302- resp = s3_get_meta (fp. config, fp. bucket, fp. key; version= fp. version)
302+ resp = s3_get_meta (get_config (fp), fp. bucket, fp. key; version= fp. version)
303+
303304 # Example: "Thu, 03 Jan 2019 21:09:17 GMT"
304305 last_modified = DateTime (
305306 resp[" Last-Modified" ][1 : (end - 4 )], dateformat " e, d u Y H:M:S"
@@ -354,7 +355,7 @@ function Base.rm(fp::S3Path; recursive=false, kwargs...)
354355 end
355356
356357 @debug " delete: $fp "
357- return s3_delete (fp . config , fp. bucket, fp. key; version= fp. version)
358+ return s3_delete (get_config (fp) , fp. bucket, fp. key; version= fp. version)
358359end
359360
360361# We need to special case sync with S3Paths because of how directories
@@ -478,7 +479,7 @@ function Base.readdir(fp::S3Path; join=false, sort=true)
478479 if ! isempty (token)
479480 params[" continuation-token" ] = token
480481 end
481- S3. list_objects_v2 (fp. bucket, params; aws_config= fp . config )
482+ S3. list_objects_v2 (fp. bucket, params; aws_config= get_config (fp) )
482483 catch e
483484 @delay_retry if ecode (e) in [" NoSuchBucket" ]
484485 end
502503function Base. read (fp:: S3Path ; byte_range= nothing )
503504 return Vector {UInt8} (
504505 s3_get (
505- fp . config ,
506+ get_config (fp) ,
506507 fp. bucket,
507508 fp. key;
508509 raw= true ,
@@ -528,11 +529,11 @@ function Base.write(
528529 fp. version === nothing ||
529530 throw (ArgumentError (" Can't write to a specific object version ($(fp. version) )" ))
530531 if ! multipart || length (content) < MAX_HTTP_BYTES
531- return s3_put (fp . config , fp. bucket, fp. key, content)
532+ return s3_put (get_config (fp) , fp. bucket, fp. key, content)
532533 else
533534 io = IOBuffer (content)
534535 return s3_multipart_upload (
535- fp . config , fp. bucket, fp. key, io, part_size_mb; other_kwargs...
536+ get_config (fp) , fp. bucket, fp. key, io, part_size_mb; other_kwargs...
536537 )
537538 end
538539end
0 commit comments