V0.6.2 fix precompile #13
+100
@@ -1,6 +1,7 @@
|
|||||||
module garageS3
|
module garageS3
|
||||||
|
|
||||||
export
|
export
|
||||||
|
LifecycleExpiration, build_lifecycle_xml,
|
||||||
GarageStorage, put_file, get_file, list_files, delete_file,
|
GarageStorage, put_file, get_file, list_files, delete_file,
|
||||||
set_lifecycle_expiration, get_lifecycle, delete_lifecycle
|
set_lifecycle_expiration, get_lifecycle, delete_lifecycle
|
||||||
|
|
||||||
@@ -266,11 +267,110 @@ function delete_file(storage::GarageStorage, key::String)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# ===================================================================
|
||||||
|
# 3. Bucket Lifecycle Configuration
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
""" Lifecycle expiration configuration for a bucket.
|
||||||
|
|
||||||
|
# Fields
|
||||||
|
- `prefix::String`: Object key prefix this rule applies to.
|
||||||
|
- `days::Int`: Number of days after object creation to expire/delete.
|
||||||
|
- `enabled::Bool`: Whether the rule is active (default: `true`).
|
||||||
|
- `id::String`: Unique identifier for the rule (default: auto-generated).
|
||||||
|
"""
|
||||||
|
struct LifecycleExpiration
|
||||||
|
prefix::String
|
||||||
|
days::Int
|
||||||
|
enabled::Bool
|
||||||
|
id::String
|
||||||
|
end
|
||||||
|
function LifecycleExpiration(prefix::String, days::Int; enabled::Bool=true, id::String="")
|
||||||
|
rule_id = isempty(id) ? "expire-" * replace(prefix, "/" => "_") * "-" * string(days) * "d" : id
|
||||||
|
return LifecycleExpiration(prefix, days, enabled, rule_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
""" Build the XML body for a PutBucketLifecycleConfiguration request.
|
||||||
|
|
||||||
|
Supports a single rule with expiration by prefix.
|
||||||
|
"""
|
||||||
|
function build_lifecycle_xml(rule::LifecycleExpiration)::String
|
||||||
|
status = rule.enabled ? "Enabled" : "Disabled"
|
||||||
|
return """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<LifecycleConfiguration>
|
||||||
|
<Rule>
|
||||||
|
<ID>$(rule.id)</ID>
|
||||||
|
<Filter>
|
||||||
|
<Prefix>$(rule.prefix)</Prefix>
|
||||||
|
</Filter>
|
||||||
|
<Status>$status</Status>
|
||||||
|
<Expiration>
|
||||||
|
<Days>$(rule.days)</Days>
|
||||||
|
</Expiration>
|
||||||
|
</Rule>
|
||||||
|
</LifecycleConfiguration>"""
|
||||||
|
end
|
||||||
|
|
||||||
|
""" Set bucket lifecycle expiration rule.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `storage::GarageStorage`: The storage client instance.
|
||||||
|
- `rule::LifecycleExpiration`: The lifecycle expiration rule.
|
||||||
|
|
||||||
|
# Returns
|
||||||
|
- `Dict{String, Any}`: Parsed response from the server.
|
||||||
|
|
||||||
|
# Example
|
||||||
|
```julia
|
||||||
|
rule = LifecycleExpiration("uploads/", 30)
|
||||||
|
set_lifecycle_expiration(storage, rule)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function set_lifecycle_expiration(storage::GarageStorage, rule::LifecycleExpiration)
|
||||||
|
xml_body = build_lifecycle_xml(rule)
|
||||||
|
args = Dict{String,Any}("body" => xml_body)
|
||||||
|
return S3.put_bucket_lifecycle_configuration(storage.bucket, args; aws_config=storage.config)
|
||||||
|
end
|
||||||
|
|
||||||
|
""" Get the bucket lifecycle configuration.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `storage::GarageStorage`: The storage client instance.
|
||||||
|
|
||||||
|
# Returns
|
||||||
|
- `Dict{String, Any}`: Parsed lifecycle configuration, or `nothing` if no lifecycle is configured.
|
||||||
|
|
||||||
|
# Example
|
||||||
|
```julia
|
||||||
|
config = get_lifecycle(storage)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function get_lifecycle(storage::GarageStorage)::Union{Dict{String,Any},Nothing}
|
||||||
|
try
|
||||||
|
return S3.get_bucket_lifecycle_configuration(storage.bucket; aws_config=storage.config)
|
||||||
|
catch e
|
||||||
|
if isa(e, AWS.AWSException) && e.code == "NoSuchLifecycleConfiguration"
|
||||||
|
return nothing
|
||||||
|
end
|
||||||
|
rethrow(e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
""" Delete the bucket lifecycle configuration.
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
- `storage::GarageStorage`: The storage client instance.
|
||||||
|
|
||||||
|
# Returns
|
||||||
|
- `Dict{String, Any}`: Parsed response from the server.
|
||||||
|
|
||||||
|
# Example
|
||||||
|
```julia
|
||||||
|
delete_lifecycle(storage)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function delete_lifecycle(storage::GarageStorage)
|
||||||
|
return S3.delete_bucket_lifecycle(storage.bucket; aws_config=storage.config)
|
||||||
|
end
|
||||||
|
|
||||||
end # module GarageS3
|
end # module GarageS3
|
||||||
|
|||||||
@@ -343,4 +343,121 @@ using UUIDs: uuid4
|
|||||||
delete_file(storage, test_key)
|
delete_file(storage, test_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# --- Lifecycle configuration tests ---
|
||||||
|
|
||||||
|
@testset "LifecycleExpiration construction with default ID" begin
|
||||||
|
rule = LifecycleExpiration("uploads/", 30)
|
||||||
|
@test rule.prefix == "uploads/"
|
||||||
|
@test rule.days == 30
|
||||||
|
@test rule.enabled == true
|
||||||
|
@test rule.id == "expire-uploads_-30d"
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "LifecycleExpiration construction with custom ID" begin
|
||||||
|
rule = LifecycleExpiration("data/", 7; id="my-rule")
|
||||||
|
@test rule.prefix == "data/"
|
||||||
|
@test rule.days == 7
|
||||||
|
@test rule.enabled == true
|
||||||
|
@test rule.id == "my-rule"
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "LifecycleExpiration with disabled flag" begin
|
||||||
|
rule = LifecycleExpiration("temp/", 1; enabled=false)
|
||||||
|
@test rule.enabled == false
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "LifecycleExpiration with nested prefix" begin
|
||||||
|
rule = LifecycleExpiration("deep/nested/", 90)
|
||||||
|
@test rule.prefix == "deep/nested/"
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "build_lifecycle_xml generates valid XML" begin
|
||||||
|
rule = LifecycleExpiration("test/", 14; id="test-rule")
|
||||||
|
xml = build_lifecycle_xml(rule)
|
||||||
|
@test occursin("<?xml version=\"1.0\"", xml)
|
||||||
|
@test occursin("<LifecycleConfiguration>", xml)
|
||||||
|
@test occursin("<ID>test-rule</ID>", xml)
|
||||||
|
@test occursin("<Prefix>test/</Prefix>", xml)
|
||||||
|
@test occursin("<Status>Enabled</Status>", xml)
|
||||||
|
@test occursin("<Days>14</Days>", xml)
|
||||||
|
@test occursin("</LifecycleConfiguration>", xml)
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "build_lifecycle_xml generates disabled rule XML" begin
|
||||||
|
rule = LifecycleExpiration("temp/", 1; enabled=false)
|
||||||
|
xml = build_lifecycle_xml(rule)
|
||||||
|
@test occursin("<Status>Disabled</Status>", xml)
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "integration: lifecycle CRUD - set and get" begin
|
||||||
|
storage = GarageStorage(
|
||||||
|
"https://s3-api.yiem.cc",
|
||||||
|
"GKb080154a2e5b19100b1b2c6e",
|
||||||
|
"a2c6b1379c2f731d3e6e5a408dd4d6cffca7511717675f55114ff94828febca1",
|
||||||
|
"testbucket"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should return nothing when no lifecycle is set
|
||||||
|
lc = get_lifecycle(storage)
|
||||||
|
@test lc === nothing
|
||||||
|
|
||||||
|
# Set lifecycle
|
||||||
|
rule = LifecycleExpiration("lifecycle-test/", 45)
|
||||||
|
set_lifecycle_expiration(storage, rule)
|
||||||
|
|
||||||
|
# Should return configuration after setting
|
||||||
|
lc = get_lifecycle(storage)
|
||||||
|
@test lc !== nothing
|
||||||
|
@test haskey(lc, "Rule")
|
||||||
|
|
||||||
|
# Delete lifecycle
|
||||||
|
delete_lifecycle(storage)
|
||||||
|
|
||||||
|
# Should return nothing after deletion
|
||||||
|
lc = get_lifecycle(storage)
|
||||||
|
@test lc === nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "integration: lifecycle with nested prefix" begin
|
||||||
|
storage = GarageStorage(
|
||||||
|
"https://s3-api.yiem.cc",
|
||||||
|
"GKb080154a2e5b19100b1b2c6e",
|
||||||
|
"a2c6b1379c2f731d3e6e5a408dd4d6cffca7511717675f55114ff94828febca1",
|
||||||
|
"testbucket"
|
||||||
|
)
|
||||||
|
|
||||||
|
rule = LifecycleExpiration("a/b/c/", 20; id="nested-rule")
|
||||||
|
set_lifecycle_expiration(storage, rule)
|
||||||
|
|
||||||
|
lc = get_lifecycle(storage)
|
||||||
|
@test lc !== nothing
|
||||||
|
@test haskey(lc, "Rule")
|
||||||
|
|
||||||
|
delete_lifecycle(storage)
|
||||||
|
@test get_lifecycle(storage) === nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "integration: lifecycle enabled/disabled toggle" begin
|
||||||
|
storage = GarageStorage(
|
||||||
|
"https://s3-api.yiem.cc",
|
||||||
|
"GKb080154a2e5b19100b1b2c6e",
|
||||||
|
"a2c6b1379c2f731d3e6e5a408dd4d6cffca7511717675f55114ff94828febca1",
|
||||||
|
"testbucket"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set enabled rule
|
||||||
|
rule1 = LifecycleExpiration("toggle/", 10; enabled=true)
|
||||||
|
set_lifecycle_expiration(storage, rule1)
|
||||||
|
lc = get_lifecycle(storage)
|
||||||
|
@test lc !== nothing
|
||||||
|
|
||||||
|
# Override with disabled rule
|
||||||
|
rule2 = LifecycleExpiration("toggle/", 10; enabled=false)
|
||||||
|
set_lifecycle_expiration(storage, rule2)
|
||||||
|
lc = get_lifecycle(storage)
|
||||||
|
@test lc !== nothing
|
||||||
|
|
||||||
|
delete_lifecycle(storage)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user