Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: process bucket prefix like official cli #47

Merged
merged 3 commits into from
May 24, 2023
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ jobs:
run: npm ci
- name: Build
run: npm run build
- name: run test
- name: Run test
run: npm run test
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ await sync('s3://my-source-bucket', 's3://my-target-bucket', {
#### Relocate objects during sync

```javascript
// sync s3://my-source-bucket/a/b/c.txt to s3://my-target-bucket/zzz/c.txt
await sync('s3://my-source-bucket/a/b/c.txt', 's3://my-target-bucket', {
// move objects from source folder a/b/ to target folder zzz/
await sync('s3://my-source-bucket', 's3://my-target-bucket', {
relocations: [ // multiple relocations can be applied
(currentPath) =>
currentPath.startsWith('a/b/')
Expand All @@ -188,12 +188,9 @@ await sync('s3://my-source-bucket/a/b/c.txt', 's3://my-target-bucket', {
],
});

// sync s3://mybucket/flowers/red/rose.png to /path/to/local/dir/rose.png
await sync('s3://mybucket/flowers/red/rose.png', '/path/to/local/dir', {
relocations: [
(currentPath) => currentPath.replace('flowers/red/', '') // folder flowers/red will be flattened during sync
],
});
// aws s3 sync s3://mybucket/flowers/red /path/to/local/dir
// as in cli, folder flowers/red will be flattened during sync
await sync('s3://mybucket/flowers/red', '/path/to/local/dir');
```

Note: relocations are applied after every other options such as filters.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "s3-sync-client",
"version": "4.1.0",
"version": "4.1.1",
"description": "AWS CLI s3 sync for Node.js provides a modern client to perform S3 sync operations between file systems and S3 buckets in the spirit of the official AWS CLI command",
"keywords": [
"aws",
Expand Down
8 changes: 8 additions & 0 deletions src/commands/SyncBucketWithBucketCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ export class SyncBucketWithBucketCommand {
(currentPath) => `${targetPrefix}/${currentPath}`,
...this.relocations,
];
if (sourcePrefix !== '')
this.relocations = [
(currentPath) =>
currentPath.startsWith(`${sourcePrefix}/`)
? currentPath.replace(`${sourcePrefix}/`, '')
: currentPath,
...this.relocations,
];
sourceObjects.forEach((sourceObject) =>
sourceObject.applyFilters(this.filters)
);
Expand Down
8 changes: 8 additions & 0 deletions src/commands/SyncLocalWithBucketCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ export class SyncLocalWithBucketCommand {
new ListBucketObjectsCommand({ bucket, prefix }).execute(client),
new ListLocalObjectsCommand({ directory: this.localDir }).execute(),
]);
if (prefix !== '')
this.relocations = [
(currentPath) =>
currentPath.startsWith(`${prefix}/`)
? currentPath.replace(`${prefix}/`, '')
: currentPath,
...this.relocations,
];
sourceObjects.forEach((sourceObject) =>
sourceObject.applyFilters(this.filters)
);
Expand Down
80 changes: 55 additions & 25 deletions test/S3SyncClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ test('s3 sync client', async (t) => {
await syncClient.send(
new SyncBucketWithBucketCommand({
sourceBucketPrefix: `${BUCKET_2}/def/jkl`,
targetBucketPrefix: BUCKET,
targetBucketPrefix: `${BUCKET}/def/jkl`,
maxConcurrentTransfers: 200,
monitor,
})
Expand All @@ -155,7 +155,7 @@ test('s3 sync client', async (t) => {
await syncClient.send(
new SyncBucketWithBucketCommand({
sourceBucketPrefix: `${BUCKET_2}/def/jkl`,
targetBucketPrefix: BUCKET,
targetBucketPrefix: `${BUCKET}/def/jkl`,
maxConcurrentTransfers: 200,
relocations: [(currentPath) => `relocated/${currentPath}`],
})
Expand All @@ -171,15 +171,19 @@ test('s3 sync client', async (t) => {
});

await b.test('syncs a single dir with folder relocation', async () => {
await syncClient.sync(`s3://${BUCKET_2}/def/jkl`, `s3://${BUCKET}`, {
maxConcurrentTransfers: 200,
relocations: [
(currentPath) =>
currentPath.startsWith('def/jkl')
? currentPath.replace('def/jkl', 'relocated-bis/folder')
: currentPath,
],
});
await syncClient.sync(
`s3://${BUCKET_2}/def/jkl`,
`s3://${BUCKET}/def/jkl`,
{
maxConcurrentTransfers: 200,
relocations: [
(currentPath) =>
currentPath.startsWith('def/jkl')
? currentPath.replace('def/jkl', 'relocated-bis/folder')
: currentPath,
],
}
);
const objects = await syncClient.send(
new ListBucketObjectsCommand({
bucket: BUCKET,
Expand Down Expand Up @@ -209,6 +213,23 @@ test('s3 sync client', async (t) => {
assert(objects.length === 5000);
}
);

// https://github.com/jeanbmar/s3-sync-client/issues/40
await b.test('processes prefix properly', async () => {
fs.rmSync(path.join(SYNC_DIR, 'issue40'), {
recursive: true,
force: true,
});
await syncClient.sync(`s3://${BUCKET_2}/def`, `s3://${BUCKET}/issue40`);
const objects = await syncClient.send(
new ListBucketObjectsCommand({
bucket: BUCKET,
prefix: 'issue40',
})
);
assert(hasObject(objects, 'issue40/def/jkl/xmoj') === false);
assert(hasObject(objects, 'issue40/jkl/xmoj') === true);
});
});

await t.test('syncs bucket with local', async (b) => {
Expand Down Expand Up @@ -395,7 +416,7 @@ test('s3 sync client', async (t) => {
await l.test('syncs a single dir with a few files', async () => {
await syncClient.send(
new SyncLocalWithBucketCommand({
bucketPrefix: `${BUCKET_2}/def/jkl`,
bucketPrefix: `${BUCKET_2}/def`,
localDir: SYNC_DIR,
})
);
Expand All @@ -404,7 +425,7 @@ test('s3 sync client', async (t) => {
directory: SYNC_DIR,
})
);
assert(hasObject(objects, 'def/jkl/xmoj') === true);
assert(hasObject(objects, 'jkl/xmoj') === true);
});

await l.test(
Expand All @@ -415,12 +436,7 @@ test('s3 sync client', async (t) => {
new SyncLocalWithBucketCommand({
bucketPrefix: `${BUCKET_2}/def/jkl`,
localDir: SYNC_DIR,
relocations: [
(currentPath) =>
currentPath.startsWith('def/jkl')
? currentPath.replace('def/jkl', 'issue9')
: currentPath,
],
relocations: [(currentPath) => `issue9/${currentPath}`],
})
);
fs.writeFileSync(
Expand All @@ -432,12 +448,7 @@ test('s3 sync client', async (t) => {
new SyncLocalWithBucketCommand({
bucketPrefix: `${BUCKET_2}/def/jkl`,
localDir: SYNC_DIR,
relocations: [
(currentPath) =>
currentPath.startsWith('def/jkl')
? currentPath.replace('def/jkl', 'issue9')
: currentPath,
],
relocations: [(currentPath) => `issue9/${currentPath}`],
del: true,
})
);
Expand Down Expand Up @@ -554,6 +565,25 @@ test('s3 sync client', async (t) => {
assert(atimeMs < now);
assert(mtimeMs < now);
});

// https://github.com/jeanbmar/s3-sync-client/issues/40
await l.test('processes prefix properly', async () => {
fs.rmSync(path.join(SYNC_DIR, 'issue40'), {
recursive: true,
force: true,
});
await syncClient.sync(
`s3://${BUCKET_2}/def`,
path.join(SYNC_DIR, 'issue40')
);
const objects = await syncClient.send(
new ListLocalObjectsCommand({
directory: path.join(SYNC_DIR, 'issue40'),
})
);
assert(hasObject(objects, 'def/jkl/xmoj') === false);
assert(hasObject(objects, 'jkl/xmoj') === true);
});
});

await t.test('diffs sync objects', async (d) => {
Expand Down