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
122 changes: 122 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ tigris mk <path> [flags]
| `-a, --access` | Access level (only applies when creating a bucket) (default: private) |
| `--public` | Shorthand for --access public (only applies when creating a bucket) |
| `-s, --enable-snapshots` | Enable snapshots for the bucket (only applies when creating a bucket) (default: false) |
| `--allow-object-acl` | Allow per-object ACLs on the bucket (only applies when creating a bucket) (default: false) |
| `--enable-directory-listing` | Enable directory listing, relevant for public buckets (only applies when creating a bucket) (default: false) |
| `-t, --default-tier` | Default storage tier (only applies when creating a bucket) (default: STANDARD) |
| `-l, --locations` | Location for the bucket (only applies when creating a bucket) (default: global) |
| `-fork, --fork-of` | Create this bucket as a fork (copy-on-write clone) of the named source bucket |
Expand All @@ -231,6 +233,8 @@ tigris mk <path> [flags]
```bash
tigris mk my-bucket
tigris mk my-bucket --access public --region iad
tigris mk my-bucket --allow-object-acl
tigris mk my-bucket --public --enable-directory-listing
tigris mk my-bucket/images/
tigris mk t3://my-bucket
tigris mk my-fork --fork-of my-bucket
Expand Down Expand Up @@ -308,10 +312,12 @@ tigris cp <src> <dest> [flags]
| Flag | Description |
|------|-------------|
| `-r, --recursive` | Copy directories recursively |
| `-a, --access` | Access level for uploaded objects (only applies to local-to-remote uploads) |

**Examples:**
```bash
tigris cp ./file.txt t3://my-bucket/file.txt
tigris cp ./logo.png t3://my-bucket/logo.png --access public
tigris cp t3://my-bucket/file.txt ./local-copy.txt
tigris cp t3://my-bucket/src/ t3://my-bucket/dest/ -r
tigris cp ./images/ t3://my-bucket/images/ -r
Expand Down Expand Up @@ -494,6 +500,8 @@ tigris buckets create [name] [flags]
| `-a, --access` | Access level (default: private) |
| `--public` | Shorthand for --access public |
| `-s, --enable-snapshots` | Enable snapshots for the bucket (default: false) |
| `--allow-object-acl` | Allow per-object ACLs on the bucket (default: false) |
| `--enable-directory-listing` | Enable directory listing, relevant for public buckets (default: false) |
| `-t, --default-tier` | Choose the default tier for the bucket (default: STANDARD) |
| `-l, --locations` | Location for the bucket (default: global) |
| `-fork, --fork-of` | Create this bucket as a fork (copy-on-write clone) of the named source bucket |
Expand All @@ -504,6 +512,8 @@ tigris buckets create [name] [flags]
tigris buckets create my-bucket
tigris buckets create my-bucket --access public --locations iad
tigris buckets create my-bucket --enable-snapshots --default-tier STANDARD_IA
tigris buckets create my-bucket --allow-object-acl
tigris buckets create my-bucket --public --enable-directory-listing
tigris buckets create my-fork --fork-of my-bucket
tigris buckets create my-fork --fork-of my-bucket --source-snapshot 1765889000501544464
```
Expand Down Expand Up @@ -864,6 +874,8 @@ Low-level object operations for listing, downloading, uploading, and deleting in
| `tigris objects set` (s) | (Deprecated) Update settings on an existing object such as access level. Use `tigris objects set-access` for ACL changes and `tigris mv` to rename |
| `tigris objects set-access` (sa) | Set the access level (public or private) on an existing object |
| `tigris objects info` (i) | Show metadata for an object (content type, size, modified date) |
| `tigris objects restore` (rs) | Restore an archived object (e.g. one in the GLACIER tier) into an actively-readable copy for a number of days |
| `tigris objects restore-info` (ri) | Show the restore state of an archived object (archived, in-progress, or restored) |

#### `tigris objects list` (l)

Expand Down Expand Up @@ -1042,6 +1054,46 @@ tigris objects info my-bucket report.pdf --format json
tigris objects info my-bucket report.pdf --version-id abc123
```

#### `tigris objects restore` (rs)

Restore an archived object (e.g. one in the GLACIER tier) into an actively-readable copy for a number of days

```
tigris objects restore <bucket> [key] [flags]
```

| Flag | Description |
|------|-------------|
| `-d, --days` | How many days the restored copy stays available before reverting to its archived tier (default: 1) |
| `--version-id` | Restore a specific object version (requires bucket versioning). Omit to restore the current version |
| `--format` | Output format (default: table) |

**Examples:**
```bash
tigris objects restore my-bucket archived.bin
tigris objects restore my-bucket archived.bin --days 3
tigris objects restore t3://my-bucket/archived.bin --days 7
```

#### `tigris objects restore-info` (ri)

Show the restore state of an archived object (archived, in-progress, or restored)

```
tigris objects restore-info <bucket> [key] [flags]
```

| Flag | Description |
|------|-------------|
| `--version-id` | Inspect a specific object version (requires bucket versioning). Omit to read the current version |
| `--format` | Output format (default: table) |

**Examples:**
```bash
tigris objects restore-info my-bucket archived.bin
tigris objects restore-info t3://my-bucket/archived.bin --format json
```

### `tigris access-keys` (keys)

Create, list, inspect, delete, and assign roles to access keys. Access keys are credentials used for programmatic API access
Expand Down Expand Up @@ -1224,6 +1276,7 @@ Identity and Access Management - manage policies, users, and permissions
|---------|-------------|
| `tigris iam policies` (p) | Manage IAM policies. Policies define permissions for access keys |
| `tigris iam users` (u) | Manage organization users and invitations |
| `tigris iam teams` (t) | Manage organization teams |

#### `tigris iam policies` (p)

Expand Down Expand Up @@ -1497,6 +1550,75 @@ tigris iam users remove user@example.com --yes
tigris iam users remove user@example.com,user@example.net --yes
```

#### `tigris iam teams` (t)

Manage organization teams

| Command | Description |
|---------|-------------|
| `tigris iam teams list` (l) | List all teams in the organization |
| `tigris iam teams create` (c) | Create a new team in the organization |
| `tigris iam teams edit` (e) | Update a team's name, description, or members. Members are replaced with the provided list |

##### `tigris iam teams list` (l)

List all teams in the organization

```
tigris iam teams list [flags]
```

| Flag | Description |
|------|-------------|
| `--format` | Output format (default: table) |

**Examples:**
```bash
tigris iam teams list
tigris iam teams list --format json
```

##### `tigris iam teams create` (c)

Create a new team in the organization

```
tigris iam teams create <name> [flags]
```

| Flag | Description |
|------|-------------|
| `-d, --description` | Description for the team |
| `-m, --members` | Member email address(es) to add (comma-separated for multiple) |

**Examples:**
```bash
tigris iam teams create engineering
tigris iam teams create engineering --description 'Engineering team'
tigris iam teams create engineering --members a@example.com,b@example.com
```

##### `tigris iam teams edit` (e)

Update a team's name, description, or members. Members are replaced with the provided list

```
tigris iam teams edit <id> [flags]
```

| Flag | Description |
|------|-------------|
| `-n, --name` | New name for the team |
| `-d, --description` | New description for the team |
| `-m, --members` | Replace the team's members with these email address(es) (comma-separated for multiple) |

**Examples:**
```bash
tigris iam teams edit team_id --name platform
tigris iam teams edit team_id --description 'Platform team'
tigris iam teams edit team_id --members a@example.com,b@example.com
```

## License

MIT
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@
"dependencies": {
"@aws-sdk/credential-providers": "^3.1038.0",
"@smithy/shared-ini-file-loader": "^4.4.9",
"@tigrisdata/iam": "^2.1.1",
"@tigrisdata/storage": "^3.15.0",
"@tigrisdata/iam": "^2.2.0",
"@tigrisdata/storage": "^3.16.0",
"commander": "^14.0.3",
"enquirer": "^2.4.1",
"jose": "^6.2.3",
Expand Down
10 changes: 10 additions & 0 deletions src/lib/buckets/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ export default async function create(options: Record<string, unknown>) {
's',
'S',
]);
const allowObjectAcl = getOption<boolean>(options, [
'allow-object-acl',
'allowObjectAcl',
]);
const enableDirectoryListing = getOption<boolean>(options, [
'enable-directory-listing',
'enableDirectoryListing',
]);
let defaultTier = getOption<string>(options, ['default-tier', 't', 'T']);
const locations = getOption<string>(options, ['locations', 'l', 'L']);
const forkOf = getOption<string>(options, ['fork-of', 'forkOf', 'fork']);
Expand Down Expand Up @@ -120,6 +128,8 @@ export default async function create(options: Record<string, unknown>) {
const { error } = await createBucket(name, {
defaultTier: (defaultTier ?? 'STANDARD') as StorageClass,
enableSnapshot: enableSnapshots === true,
allowObjectAcl: allowObjectAcl === true,
enableDirectoryListing: enableDirectoryListing === true,
access: (access ?? 'private') as 'public' | 'private',
locations: parsedLocations ?? parseLocations(locations ?? 'global'),
...(forkOf ? { sourceBucketName: forkOf } : {}),
Expand Down
49 changes: 43 additions & 6 deletions src/lib/cp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ async function uploadFile(
bucket: string,
key: string,
config: Awaited<ReturnType<typeof getStorageConfig>>,
showProgress = false
showProgress = false,
access?: 'public' | 'private'
): Promise<{ error?: string }> {
let fileSize: number | undefined;
try {
Expand All @@ -119,6 +120,7 @@ async function uploadFile(
const { error: putError } = await put(key, body, {
...calculateUploadParams(fileSize),
...(contentType ? { contentType } : {}),
...(access ? { access } : {}),
onUploadProgress: showProgress
? ({ loaded }) => {
if (fileSize !== undefined && fileSize > 0) {
Expand Down Expand Up @@ -253,7 +255,8 @@ async function copyLocalToRemote(
src: string,
destParsed: ParsedPath,
config: Awaited<ReturnType<typeof getStorageConfig>>,
recursive: boolean
recursive: boolean,
access?: 'public' | 'private'
) {
const localPath = resolveLocalPath(src);
const isWildcard = src.includes('*');
Expand Down Expand Up @@ -282,7 +285,14 @@ async function copyLocalToRemote(
? `${destParsed.path.replace(/\/$/, '')}/${relPath}`
: relPath;

const result = await uploadFile(file, destParsed.bucket, destKey, config);
const result = await uploadFile(
file,
destParsed.bucket,
destKey,
config,
false,
access
);
if (result.error) {
console.error(`Failed to upload ${file}: ${result.error}`);
return false;
Expand Down Expand Up @@ -352,7 +362,14 @@ async function copyLocalToRemote(
].filter(Boolean);
const destKey = parts.join('/');

const result = await uploadFile(file, destParsed.bucket, destKey, config);
const result = await uploadFile(
file,
destParsed.bucket,
destKey,
config,
false,
access
);
if (result.error) {
console.error(`Failed to upload ${file}: ${result.error}`);
return false;
Expand Down Expand Up @@ -405,7 +422,8 @@ async function copyLocalToRemote(
destParsed.bucket,
destKey,
config,
!_jsonMode
!_jsonMode,
access
);
if (result.error) {
exitWithError(result.error);
Expand Down Expand Up @@ -824,10 +842,29 @@ export default async function cp(options: Record<string, unknown>) {
}

const recursive = !!getOption<boolean>(options, ['recursive', 'r']);
const accessArg = getOption<string>(options, ['access', 'a', 'A']);
const format = getFormat(options);
_jsonMode = format === 'json';

let access: 'public' | 'private' | undefined;
if (accessArg === undefined) {
access = undefined;
} else if (accessArg === 'public' || accessArg === 'private') {
access = accessArg;
} else {
exitWithError('Access level must be either "public" or "private"');
}

const direction = detectDirection(src, dest);

// --access only affects the object being written, which only happens on
// upload. copy() can't carry access and a downloaded file has none.
if (access !== undefined && direction !== 'local-to-remote') {
exitWithError(
'--access only applies to local-to-remote uploads. Use "tigris objects set-access" to change access on existing objects.'
);
}

const config = await getStorageConfig({ withCredentialProvider: true });

switch (direction) {
Expand All @@ -836,7 +873,7 @@ export default async function cp(options: Record<string, unknown>) {
if (!destParsed.bucket) {
exitWithError('Invalid destination path');
}
await copyLocalToRemote(src, destParsed, config, recursive);
await copyLocalToRemote(src, destParsed, config, recursive, access);
break;
}
case 'remote-to-local': {
Expand Down
Loading