Skip to content

Commit d01307d

Browse files
authored
lot of work (#300)
1 parent 0aab10b commit d01307d

63 files changed

Lines changed: 2343 additions & 541 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,3 @@ bin/
5151
/*fake*
5252
/.env
5353
/.direnv
54-
/.bob

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/java/com/dtsx/astra/cli/AstraCli.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import com.dtsx.astra.cli.commands.streaming.StreamingCmd;
1111
import com.dtsx.astra.cli.commands.token.TokenCmd;
1212
import com.dtsx.astra.cli.commands.user.UserCmd;
13+
import com.dtsx.astra.cli.commands.dotenv.DotEnvCmd;
1314
import com.dtsx.astra.cli.core.CliContext;
15+
import com.dtsx.astra.cli.commands.dotenv.DotEnvCmd;
1416
import com.dtsx.astra.cli.core.TypeConverters;
1517
import com.dtsx.astra.cli.core.config.AstraConfig;
1618
import com.dtsx.astra.cli.core.config.AstraHome;
@@ -69,6 +71,7 @@
6971
SetupCmd.class,
7072
ConfigCmd.class,
7173
DbCmd.class,
74+
DotEnvCmd.class,
7275
PcuCmd.class,
7376
OrgCmd.class,
7477
RoleCmd.class,

src/main/java/com/dtsx/astra/cli/commands/db/DbCreateDotEnvCmd.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.dtsx.astra.cli.core.output.Hint;
1111
import com.dtsx.astra.cli.core.output.formats.OutputAll;
1212
import com.dtsx.astra.cli.operations.db.DbCreateDotEnvOperation;
13+
1314
import lombok.Getter;
1415
import lombok.RequiredArgsConstructor;
1516
import lombok.val;
@@ -34,7 +35,8 @@
3435

3536
@Command(
3637
name = "create-dotenv",
37-
description = "Create a env file to help you connect to your Astra DB instance."
38+
description = "Create a env file to help you connect to your Astra DB instance.",
39+
hidden = true
3840
)
3941
@Example(
4042
comment = "Create a fully-populated .env file, updating the existing one if it exists",
@@ -129,6 +131,9 @@ enum Preset {
129131

130132
@Override
131133
protected final OutputAll execute(Supplier<CreateDotEnvResult> result) {
134+
ctx.log().warn("@'!astra db create-dotenv!@ is deprecated");
135+
ctx.log().warn("Use the new commands under @'!astra dotenv!@ instead");
136+
132137
return switch (result.get()) {
133138
case CreatedDotEnvContent(var content) -> OutputAll.response(
134139
content.render(ctx.colors()),
@@ -166,12 +171,7 @@ case NothingToUpdate(var outputFile) -> OutputAll.response("""
166171
new Hint("View the env file", "cat " + outputFile)
167172
));
168173

169-
case FailedToDownloadSCB(var reason) -> throw new AstraCliException(DOWNLOAD_ISSUE, """
170-
@|bold, red Error: Failed to download the secure connect bundle.|@
171-
172-
Cause:
173-
%s
174-
""".formatted(reason));
174+
175175
};
176176
}
177177

src/main/java/com/dtsx/astra/cli/commands/db/DbDownloadScbCmd.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.dtsx.astra.cli.core.output.Hint;
88
import com.dtsx.astra.cli.core.output.formats.OutputAll;
99
import com.dtsx.astra.cli.operations.db.DbDownloadScbOperation;
10+
1011
import lombok.val;
1112
import picocli.CommandLine.Command;
1213
import picocli.CommandLine.Option;
@@ -73,7 +74,7 @@ protected final OutputAll execute(Supplier<DownloadScbResult> result) {
7374
case ScbDownloaded(var path) -> handleScbDownloaded(path);
7475
case ScbDownloadedAndMoved(var path) -> handleScbDownloaded(path);
7576
case ScbDownloadedAndMoveFailed fail -> throwScbDownloadedAndMoveFailed(fail);
76-
case ScbDownloadFailed (var error) -> throwScbDownloadFailed(error);
77+
7778
case ScbDestinationAlreadyExists() -> throwScbDestinationAlreadyExists();
7879
case ScbInvalidDestination(var reason) -> throwScbInvalidDestination(reason);
7980
};
@@ -125,14 +126,7 @@ private <T> T throwScbDownloadedAndMoveFailed(ScbDownloadedAndMoveFailed fail) {
125126
));
126127
}
127128

128-
private <T> T throwScbDownloadFailed(String error) {
129-
throw new AstraCliException(DOWNLOAD_ISSUE, trimIndent("""
130-
@|bold,red Error: Failed to download secure connect bundle.|@
131129

132-
Cause:
133-
%s
134-
""").formatted(error));
135-
}
136130

137131
private <T> T throwScbDestinationAlreadyExists() {
138132
throw new AstraCliException(FILE_ISSUE, trimIndent("""

src/main/java/com/dtsx/astra/cli/commands/db/cqlsh/AbstractCqlshExecCmd.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.dtsx.astra.cli.gateways.downloads.DownloadsGateway;
1212
import com.dtsx.astra.cli.gateways.pcu.vendored.domain.PcuGroupStatusType;
1313
import com.dtsx.astra.cli.operations.Operation;
14+
1415
import com.dtsx.astra.cli.operations.db.cqlsh.AbstractCqlshExeOperation.*;
1516
import com.dtsx.astra.sdk.db.domain.DatabaseStatusType;
1617
import lombok.val;
@@ -71,8 +72,8 @@ protected Operation<CqlshExecResult> mkOperation() {
7172
protected final OutputHuman executeHuman(Supplier<CqlshExecResult> result) {
7273
return switch (result.get()) {
7374
case CqlshInstallFailed(var msg) -> throwCqlshInstallationFailed(msg);
74-
case ScbDownloadFailed(var msg) -> throwScbInstallationFailed(msg);
7575
case InvalidDbStatus(var status) -> throwInvalidDbStatus(status);
76+
7677
case Executed(var exitCode) -> AstraCli.exit(exitCode);
7778
case ExecutedWithOutput _ -> throw new CongratsYouFoundABugException("Should not be able to get to `executeHuman` with `ExecutedWithOutput` when output is `HUMAN`");
7879
};
@@ -86,8 +87,8 @@ protected final OutputAll execute(Supplier<CqlshExecResult> result) {
8687

8788
return switch (result.get()) {
8889
case CqlshInstallFailed(var msg) -> throwCqlshInstallationFailed(msg);
89-
case ScbDownloadFailed(var msg) -> throwScbInstallationFailed(msg);
9090
case InvalidDbStatus(var status) -> throwInvalidDbStatus(status);
91+
9192
case Executed _ -> throw new CongratsYouFoundABugException("Should not be able to get to `execute` with `Executed` when output is `" + ctx.outputType() + "`");
9293
case ExecutedWithOutput res -> handleExecutedWithOutput(res);
9394
};
@@ -104,15 +105,6 @@ public static <T> T throwCqlshInstallationFailed(String error) {
104105
));
105106
}
106107

107-
private <T> T throwScbInstallationFailed(String error) {
108-
throw new AstraCliException(FILE_ISSUE, """
109-
@|bold,red Failed to download secure connect bundle: %s|@
110-
111-
Please ensure you have a stable network connection and sufficient permissions, then try again.
112-
""".formatted(error), List.of(
113-
new Hint("Retry download:", "${cli.name} db cqlsh version")
114-
));
115-
}
116108

117109
private <T> T throwInvalidDbStatus(DatabaseStatusType status) {
118110
throw new AstraCliException(STATUS_ISSUE, """
@@ -124,6 +116,7 @@ private <T> T throwInvalidDbStatus(DatabaseStatusType status) {
124116
));
125117
}
126118

119+
127120
private OutputAll handleExecutedWithOutput(ExecutedWithOutput res) {
128121
val msg = "Cqlsh executed with exit code %d, with %d lines in stdout and %d lines in stderr."
129122
.formatted(res.exitCode(), res.stdout().size(), res.stderr().size());

src/main/java/com/dtsx/astra/cli/commands/db/dsbulk/AbstractDsbulkExecCmd.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
import com.dtsx.astra.cli.operations.db.dsbulk.AbstractDsbulkExeOperation.DsbulkExecResult;
1111
import com.dtsx.astra.cli.operations.db.dsbulk.AbstractDsbulkExeOperation.DsbulkInstallFailed;
1212
import com.dtsx.astra.cli.operations.db.dsbulk.AbstractDsbulkExeOperation.Executed;
13-
import com.dtsx.astra.cli.operations.db.dsbulk.AbstractDsbulkExeOperation.ScbDownloadFailed;
13+
14+
1415
import org.jetbrains.annotations.MustBeInvokedByOverriders;
1516

1617
import java.util.List;
@@ -33,7 +34,7 @@ protected void prelude() {
3334
protected final OutputHuman executeHuman(Supplier<DsbulkExecResult> result) {
3435
return switch (result.get()) {
3536
case DsbulkInstallFailed(var msg) -> throwDsbulkInstallationFailed(msg);
36-
case ScbDownloadFailed(var msg) -> throwDsbulkInstallationFailed(msg);
37+
3738
case Executed(var exitCode) -> AstraCli.exit(exitCode);
3839
};
3940
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package com.dtsx.astra.cli.commands.dotenv;
2+
3+
import com.dtsx.astra.cli.commands.db.AbstractDbCmd;
4+
import com.dtsx.astra.cli.core.CliConstants.$Db;
5+
import com.dtsx.astra.cli.core.CliConstants.$Keyspace;
6+
import com.dtsx.astra.cli.core.CliConstants.$Regions;
7+
import com.dtsx.astra.cli.core.completions.impls.DbNamesCompletion;
8+
import com.dtsx.astra.cli.core.exceptions.AstraCliException;
9+
import com.dtsx.astra.cli.core.models.DbRef;
10+
import com.dtsx.astra.cli.core.models.KeyspaceRef;
11+
import com.dtsx.astra.cli.core.models.RegionName;
12+
import com.dtsx.astra.cli.core.output.ExitCode;
13+
import com.dtsx.astra.cli.core.output.prompters.specific.DbRefPrompter;
14+
import com.dtsx.astra.cli.operations.dotenv.DotEnvOperation;
15+
import com.dtsx.astra.cli.operations.dotenv.DotEnvOperation.DotEnvRequest;
16+
import com.dtsx.astra.cli.operations.dotenv.DotEnvOperation.DotEnvResult;
17+
import com.dtsx.astra.cli.operations.dotenv.EnvKey;
18+
import lombok.val;
19+
import org.jetbrains.annotations.Nullable;
20+
import picocli.CommandLine.Option;
21+
22+
import java.nio.file.Path;
23+
import java.util.*;
24+
import java.util.function.Function;
25+
import java.util.stream.Collectors;
26+
27+
public abstract class AbstractDotEnvGenCmd extends AbstractDbCmd<DotEnvResult> {
28+
@Option(
29+
names = { "--file", "-f" },
30+
description = "The target .env file to update.",
31+
paramLabel = "FILE"
32+
)
33+
protected Optional<Path> $file;
34+
35+
@Option(
36+
names = { "--keys", "-k" },
37+
description = "Comma-separated EnvKey names to filter the resolved binding set.",
38+
mapFallbackValue = "",
39+
split = ","
40+
)
41+
protected Map<EnvKey, String> $keys = Map.of();
42+
43+
@Option(
44+
names = { "--overwrite" },
45+
description = "Always overwrite non-empty values.",
46+
negatable = true
47+
)
48+
protected Optional<Boolean> $overwrite;
49+
50+
@Option(
51+
names = { "--db" },
52+
description = "Database to bind to.",
53+
completionCandidates = DbNamesCompletion.class,
54+
paramLabel = $Db.LABEL
55+
)
56+
protected @Nullable DbRef $dbRef;
57+
58+
@Option(
59+
names = { $Keyspace.LONG },
60+
description = "The keyspace to use.",
61+
paramLabel = $Keyspace.LABEL
62+
)
63+
protected Optional<String> $keyspace;
64+
65+
@Option(
66+
names = { $Regions.LONG },
67+
description = "The region to use.",
68+
paramLabel = $Regions.LABEL
69+
)
70+
protected Optional<RegionName> $region;
71+
72+
protected abstract boolean isPrint();
73+
74+
@Override
75+
protected DotEnvOperation mkOperation() {
76+
val ksRef = $keyspace.map(ks -> KeyspaceRef.parse($dbRef, ks).fold(
77+
err -> {
78+
throw new AstraCliException(ExitCode.VALIDATION_ISSUE, "keyspace " + err);
79+
},
80+
Function.identity()
81+
));
82+
83+
val downloadsGateway = ctx.gateways().mkDownloadsGateway();
84+
val orgGateway = ctx.gateways().mkOrgGateway(profile().token(), profile().env());
85+
86+
return new DotEnvOperation(ctx, dbGateway, orgGateway, downloadsGateway, new DotEnvRequest(
87+
profile(),
88+
$dbRef,
89+
ksRef,
90+
$region,
91+
$file,
92+
isPrint(),
93+
$keys,
94+
$overwrite,
95+
this::askForKeys,
96+
this::askForDbRef,
97+
this::askIfShouldOverwrite
98+
));
99+
}
100+
101+
private DbRef askForDbRef() {
102+
return DbRefPrompter.prompt(ctx, dbGateway, "Select database to bind to", f -> f.fallbackFlag("--db").fix(originalArgs(), "--db"));
103+
}
104+
105+
private Set<EnvKey> askForKeys() {
106+
val allKeys = Arrays.asList(EnvKey.values());
107+
108+
val selected = new HashSet<>(
109+
ctx.console().select("Select the keys you want to generate in your .env file")
110+
.multiOptions(allKeys.toArray(new EnvKey[0]))
111+
.requireAnswer()
112+
.mapper(EnvKey::name)
113+
.fallbackFlag("--keys")
114+
.fix(originalArgs(), "--keys ASTRA_ORG_TOKEN")
115+
.clearAfterSelection()
116+
);
117+
118+
if (selected.isEmpty()) {
119+
throw new AstraCliException(ExitCode.VALIDATION_ISSUE, "No keys selected");
120+
}
121+
122+
return selected;
123+
}
124+
125+
private boolean askIfShouldOverwrite(Set<String> duplicates) {
126+
var duplicatesStr = duplicates.stream()
127+
.limit(4)
128+
.map(k -> "- " + ctx.highlight(k))
129+
.collect(Collectors.joining("\n"));
130+
131+
if (duplicates.size() > 4) {
132+
duplicatesStr += "\n- and %s more...".formatted(ctx.colors().PURPLE_300.use(String.valueOf(duplicates.size() - 5)));
133+
}
134+
135+
val msg = """
136+
Pre-existing keys with values found in the .env file:
137+
%s
138+
139+
Do you want to overwrite them?
140+
""".formatted(duplicatesStr);
141+
142+
return ctx.console().confirm(msg)
143+
.defaultNo()
144+
.fallbackFlag("--overwrite")
145+
.fix(originalArgs(), "--overwrite")
146+
.dontClearAfterSelection();
147+
}
148+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.dtsx.astra.cli.commands.dotenv;
2+
3+
import com.dtsx.astra.cli.core.mixins.HelpMixin;
4+
import picocli.CommandLine.Command;
5+
import picocli.CommandLine.Mixin;
6+
7+
@Command(
8+
name = "dotenv",
9+
description = "Easily create and update your .env files",
10+
subcommands = {
11+
DotEnvWriteCmd.class,
12+
DotEnvPrintCmd.class,
13+
DotEnvListKeysCmd.class,
14+
}
15+
)
16+
public class DotEnvCmd {
17+
@Mixin
18+
public HelpMixin help;
19+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.dtsx.astra.cli.commands.dotenv;
2+
3+
import com.dtsx.astra.cli.commands.AbstractCmd;
4+
import com.dtsx.astra.cli.core.output.formats.OutputAll;
5+
import com.dtsx.astra.cli.core.output.table.ShellTable;
6+
import com.dtsx.astra.cli.operations.Operation;
7+
import com.dtsx.astra.cli.operations.dotenv.EnvKey;
8+
import lombok.val;
9+
import picocli.CommandLine.Command;
10+
11+
import java.util.ArrayList;
12+
import java.util.Map;
13+
import java.util.function.Supplier;
14+
15+
@Command(
16+
name = "list-keys",
17+
description = "List all available Astra keys (no values resolved)."
18+
)
19+
public class DotEnvListKeysCmd extends AbstractCmd<Void> {
20+
@Override
21+
protected Operation<Void> mkOperation() {
22+
return () -> null;
23+
}
24+
25+
@Override
26+
protected OutputAll execute(Supplier<Void> val) {
27+
val data = new ArrayList<Map<String, String>>();
28+
29+
for (val key : EnvKey.values()) {
30+
data.add(Map.of("Key", key.name()));
31+
}
32+
33+
return new ShellTable(data).withColumns("Key");
34+
}
35+
}

0 commit comments

Comments
 (0)