Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions doc/man/task-sync.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,26 @@ default profile, or an instance profile, set
$ task config sync.aws.default_credentials true
.fi

.SS S3-Compatible Storage

To synchronize with an S3-compatible storage service other than AWS, configure
the service's endpoint URL in addition to the region, bucket, credentials, and
encryption secret described above:

.nf
$ task config sync.aws.endpoint_url <endpoint-url>
.fi

Some S3-compatible services require path-style bucket URLs. To enable them, set:

.nf
$ task config sync.aws.force_path_style true
.fi

The endpoint URL must include the scheme, such as \(oqhttp://\(cq or
\(oqhttps://\(cq. Consult the storage service's documentation for the region and
URL style it requires.

.SS Local Synchronization

In order to take advantage of synchronization's side effect of saving disk
Expand Down
2 changes: 2 additions & 0 deletions src/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ std::string configurationDefaults =
"#sync.aws.secret_access_key # secret_access_key for AWS sync\n"
"#sync.aws.profile # profile name for AWS sync\n"
"#sync.aws.default_credentials # use default credentials for AWS sync\n"
"#sync.aws.endpoint_url # endpoint URL for S3-compatible sync\n"
"#sync.aws.force_path_style=0 # use path-style S3 URLs\n"
"#sync.gcp.credential_path # Path to JSON file containing credentials to "
"authenticate GCP Sync\n"
"#sync.gcp.bucket # Bucket for sync to GCP\n"
Expand Down
2 changes: 2 additions & 0 deletions src/commands/CmdShow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ int CmdShow::execute(std::string& output) {
" sync.aws.access_key_id"
" sync.aws.bucket"
" sync.aws.default_credentials"
" sync.aws.endpoint_url"
" sync.aws.force_path_style"
" sync.aws.profile"
" sync.aws.region"
" sync.aws.secret_access_key"
Expand Down
16 changes: 10 additions & 6 deletions src/commands/CmdSync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ int CmdSync::execute(std::string& output) {
Context::getContext().config.get("sync.aws.secret_access_key");
std::string aws_default_credentials =
Context::getContext().config.get("sync.aws.default_credentials");
std::string aws_endpoint_url = Context::getContext().config.get("sync.aws.endpoint_url");
bool aws_force_path_style =
Context::getContext().config.getBoolean("sync.aws.force_path_style");
if (aws_region == "") {
throw std::string("sync.aws.region is required");
}
Expand Down Expand Up @@ -128,14 +131,15 @@ int CmdSync::execute(std::string& output) {
}

if (using_profile) {
replica->sync_to_aws_with_profile(aws_region, aws_bucket, aws_profile, encryption_secret,
avoid_snapshots);
replica->sync_to_aws_with_profile(aws_region, aws_bucket, aws_profile, aws_endpoint_url,
aws_force_path_style, encryption_secret, avoid_snapshots);
} else if (using_creds) {
replica->sync_to_aws_with_access_key(aws_region, aws_bucket, aws_access_key_id,
aws_secret_access_key, encryption_secret,
avoid_snapshots);
replica->sync_to_aws_with_access_key(
aws_region, aws_bucket, aws_access_key_id, aws_secret_access_key, aws_endpoint_url,
aws_force_path_style, encryption_secret, avoid_snapshots);
} else {
replica->sync_to_aws_with_default_creds(aws_region, aws_bucket, encryption_secret,
replica->sync_to_aws_with_default_creds(aws_region, aws_bucket, aws_endpoint_url,
aws_force_path_style, encryption_secret,
avoid_snapshots);
}

Expand Down
24 changes: 18 additions & 6 deletions src/taskchampion-cpp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,22 +182,26 @@
) -> Result<()>;

/// Sync with a server created from `ServerConfig::Aws` using `AwsCredentials::Profile`.
fn sync_to_aws_with_profile(

Check warning on line 185 in src/taskchampion-cpp/src/lib.rs

View workflow job for this annotation

GitHub Actions / Check & Clippy

this function has too many arguments (8/7)
&mut self,
region: String,
bucket: String,
profile_name: String,
endpoint_url: String,
force_path_style: bool,
encryption_secret: &CxxString,
avoid_snapshots: bool,
) -> Result<()>;

/// Sync with a server created from `ServerConfig::Aws` using `AwsCredentials::AccessKey`.
fn sync_to_aws_with_access_key(

Check warning on line 197 in src/taskchampion-cpp/src/lib.rs

View workflow job for this annotation

GitHub Actions / Check & Clippy

this function has too many arguments (9/7)
&mut self,
region: String,
bucket: String,
access_key_id: String,
secret_access_key: String,
endpoint_url: String,
force_path_style: bool,
encryption_secret: &CxxString,
avoid_snapshots: bool,
) -> Result<()>;
Expand All @@ -207,6 +211,8 @@
&mut self,
region: String,
bucket: String,
endpoint_url: String,
force_path_style: bool,
encryption_secret: &CxxString,
avoid_snapshots: bool,
) -> Result<()>;
Expand Down Expand Up @@ -904,11 +910,13 @@
})
}

fn sync_to_aws_with_profile(

Check warning on line 913 in src/taskchampion-cpp/src/lib.rs

View workflow job for this annotation

GitHub Actions / Check & Clippy

this function has too many arguments (8/7)
&mut self,
region: String,
bucket: String,
profile_name: String,
endpoint_url: String,
force_path_style: bool,
encryption_secret: &CxxString,
avoid_snapshots: bool,
) -> Result<(), CppError> {
Expand All @@ -918,8 +926,8 @@
bucket,
credentials: tc::server::AwsCredentials::Profile { profile_name },
encryption_secret: encryption_secret.as_bytes().to_vec(),
endpoint_url: None,
force_path_style: false,
endpoint_url: (!endpoint_url.is_empty()).then_some(endpoint_url),
force_path_style,
}
.into_server()
.await?;
Expand All @@ -927,12 +935,14 @@
})
}

fn sync_to_aws_with_access_key(

Check warning on line 938 in src/taskchampion-cpp/src/lib.rs

View workflow job for this annotation

GitHub Actions / Check & Clippy

this function has too many arguments (9/7)
&mut self,
region: String,
bucket: String,
access_key_id: String,
secret_access_key: String,
endpoint_url: String,
force_path_style: bool,
encryption_secret: &CxxString,
avoid_snapshots: bool,
) -> Result<(), CppError> {
Expand All @@ -945,8 +955,8 @@
secret_access_key,
},
encryption_secret: encryption_secret.as_bytes().to_vec(),
endpoint_url: None,
force_path_style: false,
endpoint_url: (!endpoint_url.is_empty()).then_some(endpoint_url),
force_path_style,
}
.into_server()
.await?;
Expand All @@ -958,6 +968,8 @@
&mut self,
region: String,
bucket: String,
endpoint_url: String,
force_path_style: bool,
encryption_secret: &CxxString,
avoid_snapshots: bool,
) -> Result<(), CppError> {
Expand All @@ -967,8 +979,8 @@
bucket,
credentials: tc::server::AwsCredentials::Default,
encryption_secret: encryption_secret.as_bytes().to_vec(),
endpoint_url: None,
force_path_style: false,
endpoint_url: (!endpoint_url.is_empty()).then_some(endpoint_url),
force_path_style,
}
.into_server()
.await?;
Expand Down
10 changes: 10 additions & 0 deletions test/show.test.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ def test_show_no_unrecognized(self):
"Your .taskrc file contains these unrecognized variables:\n foo", out
)

def test_show_s3_compatible_settings(self):
"""Verify S3-compatible storage settings are recognized"""
self.t.config("sync.aws.endpoint_url", "https://minio.example.test")
self.t.config("sync.aws.force_path_style", "true")
code, out, err = self.t("show sync.aws")
self.assertIn("sync.aws.endpoint_url", out)
self.assertIn("https://minio.example.test", out)
self.assertIn("sync.aws.force_path_style", out)
self.assertIn("true", out)


class TestShowHelperCommand(TestCase):
def setUp(self):
Expand Down
Loading