-
Notifications
You must be signed in to change notification settings - Fork 14
Refactor runner, adding support for kotlin #129
Changes from 5 commits
9d85c48
bda2a6c
c797c5b
bc649ac
5aa788b
1449a1b
499a4b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ java_library( | |
deps = [ | ||
"//:common", | ||
"@maven//:commons_io_commons_io", | ||
"@maven//:info_picocli_picocli", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a general rule, we should always write PR comments on new dependencies, especially when they come from a new "domain" that isn't already in the dependencies. For example, adding a new Compose sub-library when we already have 20 others is probably OK, but adding In this case, said explanation already exists in the PR description, so this is just a matter of copying it across to comments for faster access. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understood. I'll make sure to do this in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's do it now as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We leverage picocli to parse command line arguments without having to write string parsing ourselves, which is error-prone and likely to be more difficult to maintain and extend. |
||
"@maven//:junit_junit", | ||
"@maven//:org_zeroturnaround_zt_exec", | ||
"@maven//:org_slf4j_slf4j_api" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ | |
import org.zeroturnaround.exec.ProcessExecutor; | ||
import org.zeroturnaround.exec.ProcessResult; | ||
import org.zeroturnaround.exec.StartedProcess; | ||
import picocli.CommandLine; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
|
@@ -36,12 +37,12 @@ | |
import java.util.List; | ||
import java.util.Timer; | ||
import java.util.TimerTask; | ||
import java.util.Optional; | ||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.TimeoutException; | ||
|
||
import static org.junit.Assert.fail; | ||
|
||
public class Util { | ||
|
||
|
@@ -52,16 +53,20 @@ public class Util { | |
private static final int SERVER_ALIVE_POLL_INTERVAL_MILLIS = 500; | ||
private static final int SERVER_ALIVE_POLL_MAX_RETRIES = SERVER_STARTUP_TIMEOUT_MILLIS / SERVER_ALIVE_POLL_INTERVAL_MILLIS; | ||
|
||
public static File getArchivePath(int index) { | ||
public static File getArchivePath(String flag) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't use indices anymore, so we pass the flag that the resource is seeking and use that to find the path. |
||
String[] args = System.getProperty("sun.java.command").split(" "); | ||
if (index >= args.length) { | ||
throw new IllegalArgumentException("Distribution archive at index '" + index + "' is not defined"); | ||
Optional<CLIOptions> maybeOptions = CLIOptions.parseCLIOptions(args); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional options, lovely. (maybe) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a nice pattern and makes the potential for an empty result explicit instead of jumping to null. Someone should make a language that uses a load of these everywhere... |
||
if (!maybeOptions.isPresent()) { | ||
throw new IllegalArgumentException("No archives were passed as arguments"); | ||
} | ||
File file = new File(args[index]); | ||
if (!file.exists()) { | ||
throw new IllegalArgumentException("Distribution archive '" + file.getAbsolutePath() + "' is missing"); | ||
CLIOptions options = maybeOptions.get(); | ||
if (flag.equals("--server")) { | ||
return new File(options.getServerArchive()); | ||
} | ||
return file; | ||
if (flag.equals("--console")) { | ||
return new File(options.getConsoleArchive()); | ||
} | ||
throw new IllegalArgumentException("Unrecognised arguments"); | ||
} | ||
|
||
public static Path unarchive(File archive) throws IOException, TimeoutException, InterruptedException { | ||
|
@@ -199,4 +204,44 @@ public static ProcessExecutor createProcessExecutor(Path directory) { | |
.readOutput(true) | ||
.destroyOnExit(); | ||
} | ||
|
||
@CommandLine.Command(name = "java") | ||
private static class CLIOptions { | ||
@CommandLine.Parameters String mainClass; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The class that is being run during execution, e.g. |
||
@CommandLine.Option( | ||
names = {"--server"}, | ||
description = "Location of the archive containing a server artifact." | ||
) | ||
private String serverArchive; | ||
|
||
@CommandLine.Option( | ||
names = {"--console"}, | ||
description = "Location of the archive containing a console artifact." | ||
) | ||
private String consoleArchive; | ||
|
||
public String getServerArchive() { | ||
return serverArchive; | ||
} | ||
|
||
public String getConsoleArchive() { | ||
return consoleArchive; | ||
} | ||
|
||
public static Optional<CLIOptions> parseCLIOptions(String[] args) { | ||
CommandLine commandLine = new CommandLine(new CLIOptions()); | ||
try { | ||
CommandLine.ParseResult result = commandLine.parseArgs(args); | ||
return Optional.of(result.asCommandLineList().get(0).getCommand()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the parse result succeeded, we get the first command in the commandLineList and return it in an optional. |
||
} catch (CommandLine.ParameterException ex) { | ||
commandLine.getErr().println(ex.getMessage()); | ||
if (!CommandLine.UnmatchedArgumentException.printSuggestions(ex, commandLine.getErr())) { | ||
ex.getCommandLine().usage(commandLine.getErr()); | ||
} | ||
return Optional.empty(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,15 +54,14 @@ protected TypeDBClusterServerRunner createServerRunner(Map<String, String> optio | |
|
||
class Standalone implements TypeDBClusterServerRunner { | ||
|
||
private static final int ARCHIVE_INDEX = 1; | ||
|
||
private static final String FLAG = "--server"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cluster is the server, we don't differentiate between cluster and core because we wouldn't run both at once as they share the same purpose. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This file really had quite a bit of black magic in it, didn't it? We need to dispel it where possible. On line 64 we do distribution = unarchive(getArchivePath(FLAG)); Even after renaming One possible band-aid would be renaming As another perspective: given that there are only ever two kinds of archives, server and console, how about introducing methods named There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, but I went with |
||
protected final Path distribution; | ||
protected final Map<String, String> serverOptions; | ||
private StartedProcess process; | ||
protected ProcessExecutor executor; | ||
|
||
public Standalone(Map<String, String> serverOptions) throws IOException, InterruptedException, TimeoutException { | ||
distribution = unarchive(getArchivePath(ARCHIVE_INDEX)); | ||
distribution = unarchive(getArchivePath(FLAG)); | ||
this.serverOptions = serverOptions; | ||
System.out.println(addresses() + ": " + name() + " constructing runner..."); | ||
Files.createDirectories(ClusterServerOpts.storageData(serverOptions)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,30 +16,68 @@ | |
# | ||
|
||
load("@vaticle_dependencies//builder/java:rules.bzl", "native_dep_for_host_platform") | ||
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_test") | ||
|
||
def typedb_java_test(name, server_mac_artifact, server_linux_artifact, server_windows_artifact, | ||
console_mac_artifact = None, console_linux_artifact = None, console_windows_artifact = None, | ||
native_libraries_deps = [], deps = [], classpath_resources = [], data = [], args = [], **kwargs): | ||
|
||
native_server_artifact_paths, native_server_artifact_labels = native_artifact_paths_and_labels( | ||
server_mac_artifact, server_linux_artifact, server_windows_artifact | ||
) | ||
native_console_artifact_paths, native_console_artifact_labels = [], [] | ||
if console_mac_artifact and console_linux_artifact and console_windows_artifact: | ||
native_console_artifact_paths, native_console_artifact_labels = native_artifact_paths_and_labels( | ||
server_mac_artifact, server_linux_artifact, server_windows_artifact | ||
) | ||
|
||
native_console_artifact_paths, native_console_artifact_labels = native_console_artifact_paths_and_labels( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of removing extraneous code from the top-level function Upon investigation, they do appear to do the same thing - except that If so, I think the thing to improve here is: "check Y exists, then do X" is quite a thin abstraction over "do X", and we should delete the new method, and then, could either:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks much nicer. Done. |
||
console_mac_artifact, console_linux_artifact, console_windows_artifact | ||
) | ||
native_deps = [] | ||
for dep in native_libraries_deps: | ||
native_deps = native_deps + native_dep_for_host_platform(dep) | ||
|
||
native_deps = add_native_libraries_deps(native_libraries_deps) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we would be strict on naming conventions in Rust, so should we be in Starlark. Of course, that conflicts with the parameter name, however... I'm also not comfortable with the fact that (This is not technical debt introduced in this PR, this has been around before - but now that we're working on this file, we should address this issue) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, this was poorly named. We're taking the passed Changing the name As such, I've gone with native_dependencies = get_native_dependencies(native_libraries_deps) I read this as 'we are getting the native dependencies using the specifications of the platform-specific dependencies we need for our target platform'. This is a pretty thorny one, so let me know what you think. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I think we may need to address the heart of this problem, which is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would renaming the variable immediately work as a stop-gap, or should we leave it as is? I've raised an issue for this: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's stick with the imperfect name and merge this PR. Finding a perfect name would be impossible in an imperfect environment. |
||
|
||
native.java_test( | ||
name = name, | ||
deps = depset(deps + ["@vaticle_typedb_common//test:typedb-runner"]).to_list() + native_deps, | ||
classpath_resources = depset(classpath_resources + ["@vaticle_typedb_common//test:logback"]).to_list(), | ||
data = data + select(native_server_artifact_labels) + (select(native_console_artifact_labels) if native_console_artifact_labels else []), | ||
args = select(native_server_artifact_paths) + (select(native_console_artifact_paths) if native_console_artifact_paths else []) + args, | ||
args = ["--server"] + select(native_server_artifact_paths) + ((["--console"] + select(native_console_artifact_paths)) if native_console_artifact_paths else []) + args, | ||
**kwargs | ||
) | ||
|
||
def typedb_kt_test(name, server_mac_artifact, server_linux_artifact, server_windows_artifact, | ||
console_mac_artifact = None, console_linux_artifact = None, console_windows_artifact = None, | ||
native_libraries_deps = [], deps = [], data = [], args = [], **kwargs): | ||
|
||
native_server_artifact_paths, native_server_artifact_labels = native_artifact_paths_and_labels( | ||
server_mac_artifact, server_linux_artifact, server_windows_artifact | ||
) | ||
|
||
native_console_artifact_paths, native_console_artifact_labels = native_console_artifact_paths_and_labels( | ||
console_mac_artifact, console_linux_artifact, console_windows_artifact | ||
) | ||
|
||
native_deps = add_native_libraries_deps(native_libraries_deps) | ||
|
||
kt_jvm_test( | ||
name = name, | ||
deps = depset(deps + ["@vaticle_typedb_common//test:typedb-runner"]).to_list() + native_deps, | ||
data = data + select(native_server_artifact_labels) + (select(native_console_artifact_labels) if native_console_artifact_labels else []), | ||
args = ["--server"] + select(native_server_artifact_paths) + ((["--console"] + select(native_console_artifact_paths)) if native_console_artifact_paths else []) + args, | ||
**kwargs | ||
) | ||
|
||
def add_native_libraries_deps(native_libraries_deps): | ||
native_deps = [] | ||
for dep in native_libraries_deps: | ||
native_deps = native_deps + native_dep_for_host_platform(dep) | ||
return native_deps | ||
|
||
|
||
def native_console_artifact_paths_and_labels(console_mac_artifact, console_linux_artifact, console_windows_artifact): | ||
native_console_artifact_paths, native_console_artifact_labels = [], [] | ||
if console_mac_artifact and console_linux_artifact and console_windows_artifact: | ||
native_console_artifact_paths, native_console_artifact_labels = native_artifact_paths_and_labels( | ||
console_mac_artifact, console_linux_artifact, console_windows_artifact | ||
) | ||
return native_console_artifact_paths, native_console_artifact_labels | ||
|
||
def native_artifact_paths_and_labels(mac_artifact, linux_artifact, windows_artifact): | ||
native_artifacts = { | ||
"@vaticle_dependencies//util/platform:is_mac": mac_artifact, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously, the CI for this repo is insufficient to verify correctness. Have we tested these changes? If so, how/where?
In general, I would say it's worth including this information in the PR description and/or comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have! All of typedb-client-java's tests run successfully with this version of typedb-common. Would it make sense to just say that this is the case or to also post the test output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need - that last comment "All of typedb-client-java's tests run successfully with this version of typedb-common" is enough by itself!