pedjak / gradle-dockerized-test-plugin

Running tests inside a docker image
Apache License 2.0
21 stars 19 forks source link

Windows Support #13

Open gschrader opened 6 years ago

gschrader commented 6 years ago

I hate to ask but how much does this plugin support Windows? I've worked around a few things but I've now hit an issue with the gradle-worker-classpath file that gradle creates in the temp directory which is passed to the java command in the container, it contains paths such as C:\\Users\\username\\.gradle\\caches\\4.8\\workerMain\\gradle-worker.jar which of course doesn't align with what is mapped in the container.

gschrader commented 6 years ago

I hacked a bit more to update the paths in that file and now get java.lang.ClassNotFoundException: org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker. I'm trying to follow along in the gradle code, it seems like the classpath is passed to the java process via stdin, I'm trying to figure out where that occurs now.

gschrader commented 6 years ago

I got it to work by changing the getTestWorkerImplementationClasspath method to:

    List<URL> getTestWorkerImplementationClasspath() {
        List<URL> urls = CollectionUtils.flattenCollections(URL.class,
                moduleRegistry.getModule("gradle-core-api").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-core").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-logging").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-messaging").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-base-services").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-cli").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-native").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-testing-base").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-testing-jvm").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getModule("gradle-process-services").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getExternalModule("slf4j-api").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getExternalModule("jul-to-slf4j").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getExternalModule("native-platform").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getExternalModule("kryo").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getExternalModule("commons-lang").getImplementationClasspath().getAsURLs(),
                moduleRegistry.getExternalModule("junit").getImplementationClasspath().getAsURLs(),
                ForkingTestClassProcessor.class.getProtectionDomain().getCodeSource().getLocation()
        );
        if (SystemUtils.IS_OS_WINDOWS) {
            urls = urls.stream()
                    .map(url -> url.toExternalForm().replaceAll("\\\\", "/").replaceAll("C:", "/C").replaceAll("//", "/").replaceAll(";", ":"))
                    .map(spec -> {
                        try {
                            return new URL(spec);
                        } catch (MalformedURLException e) {
                            return null;
                        }
                    })
                    .collect(Collectors.toList());
        }
        return urls;
    }

I also had to add the c: drive as a volume:

       volumes = ["c:":"/C"]`

This is so the .gradle dir under the home directory is available. Other drives would have to be mapped if the gradle root directory was on another drive.

Then finally, my beforeContainerCreate is this:

        beforeContainerCreate = { cmd ->
            def file = new File(cmd.cmd[1].substring(1))

            file.text = fixPath(file.text)

            cmd.withWorkingDir(fixPath(project.rootDir.absolutePath))
            cmd.withEnv([])
            cmd.withCmd(cmd.cmd.collect{fixPath(it)})
        }

with fixPath being:

private String fixPath(String path) {
    path.replaceAll("\\\\", "/").replaceAll("C:", "/C").replaceAll("//", "/").replaceAll(";", ":")
}

This is all sorts of ugly code so I'm not sure if there's a better way to do this or if there is any interest in adding support.

pedjak commented 5 years ago

could you submit PR?

gschrader commented 5 years ago

I ended up not using this as the plugin didn't seem to be maintained (i.e. Gradle v5). I could maybe revisit it if it is alive again.