Skip to content

Commit c0021ca

Browse files
committed
Catch trying to create a directory at/under non-directory
1 parent 36500b5 commit c0021ca

File tree

3 files changed

+37
-28
lines changed

3 files changed

+37
-28
lines changed

src/main/kotlin/com/coder/gateway/CoderSettingsConfigurable.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.coder.gateway
22

33
import com.coder.gateway.sdk.CoderCLIManager
4-
import com.coder.gateway.sdk.canWrite
4+
import com.coder.gateway.sdk.canCreateDirectory
55
import com.coder.gateway.services.CoderSettingsState
66
import com.intellij.openapi.components.service
77
import com.intellij.openapi.options.BoundConfigurable
@@ -45,8 +45,8 @@ class CoderSettingsConfigurable : BoundConfigurable("Coder") {
4545
}
4646

4747
private fun validateBinaryDestination(): ValidationInfoBuilder.(JBTextField) -> ValidationInfo? = {
48-
if (it.text.isNotBlank() && !Path.of(it.text).canWrite()) {
49-
error("Cannot write to this path")
48+
if (it.text.isNotBlank() && !Path.of(it.text).canCreateDirectory()) {
49+
error("Cannot create this directory")
5050
} else {
5151
null
5252
}

src/main/kotlin/com/coder/gateway/sdk/PathExtensions.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ import java.nio.file.Files
44
import java.nio.file.Path
55

66
/**
7-
* Return true if the path can be created.
7+
* Return true if a directory can be created at the specified path.
88
*
9-
* Unlike File.canWrite() or Files.isWritable() the file does not need to exist;
10-
* it only needs a writable parent.
9+
* Unlike File.canWrite() or Files.isWritable() the directory does not need to
10+
* exist; it only needs a writable parent and the target needs to be
11+
* non-existent or a directory (not a regular file).
1112
*/
12-
fun Path.canWrite(): Boolean {
13+
fun Path.canCreateDirectory(): Boolean {
1314
var current: Path? = this.toAbsolutePath()
1415
while (current != null && !Files.exists(current)) {
1516
current = current.parent
1617
}
1718
// On Windows File.canWrite() only checks read-only while Files.isWritable()
1819
// actually checks permissions.
19-
return current != null && Files.isWritable(current)
20+
return current != null && Files.isWritable(current) && Files.isDirectory(current)
2021
}

src/test/groovy/PathExtensionsTest.groovy

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,43 @@ class PathExtensionsTest extends Specification {
1212
@Shared
1313
private Path tmpdir = Path.of(System.getProperty("java.io.tmpdir"))
1414
@Shared
15-
private Path unwritable = tmpdir.resolve("coder-gateway-test/path-extensions/unwritable")
15+
private Path unwritableFile = tmpdir.resolve("coder-gateway-test/path-extensions/unwritable/file")
16+
@Shared
17+
private Path writableFile = tmpdir.resolve("coder-gateway-test/path-extensions/writable-file")
1618

1719
void setupSpec() {
18-
if (unwritable.parent.toFile().exists()) {
19-
unwritable.parent.toFile().setWritable(true)
20-
unwritable.parent.toFile().deleteDir()
20+
if (unwritableFile.parent.toFile().exists()) {
21+
unwritableFile.parent.toFile().setWritable(true)
22+
unwritableFile.parent.toFile().deleteDir()
2123
}
22-
Files.createDirectories(unwritable.parent)
23-
unwritable.toFile().write("text")
24-
unwritable.toFile().setWritable(false)
25-
unwritable.parent.toFile().setWritable(false)
24+
Files.createDirectories(unwritableFile.parent)
25+
unwritableFile.toFile().write("text")
26+
writableFile.toFile().write("text")
27+
unwritableFile.toFile().setWritable(false)
28+
unwritableFile.parent.toFile().setWritable(false)
2629
}
2730

28-
def "canWrite"() {
31+
def "canCreateDirectory"() {
2932
expect:
3033
use(PathExtensionsKt) {
31-
path.canWrite() == expected
34+
path.canCreateDirectory() == expected
3235
}
3336

3437
where:
35-
path | expected
36-
unwritable | false
37-
unwritable.resolve("probably/nonexistent") | false
38-
Path.of("relative to project") | true
39-
tmpdir.resolve("./foo/bar/../..") | true
40-
tmpdir | true
41-
tmpdir.resolve("some/nested/non-existent/path") | true
42-
tmpdir.resolve("with space") | true
43-
CoderCLIManager.getConfigDir() | true
44-
CoderCLIManager.getDataDir() | true
38+
path | expected
39+
unwritableFile | false
40+
unwritableFile.resolve("probably/nonexistent") | false
41+
unwritableFile.parent.resolve("probably/nonexistent") | false
42+
writableFile | false
43+
writableFile.parent | true
44+
writableFile.resolve("nested/under/file") | false
45+
writableFile.parent.resolve("nested/under/dir") | true
46+
Path.of("relative to project") | true
47+
tmpdir.resolve("./foo/bar/../../coder-gateway-test/path-extensions") | true
48+
tmpdir | true
49+
tmpdir.resolve("some/nested/non-existent/path") | true
50+
tmpdir.resolve("with space") | true
51+
CoderCLIManager.getConfigDir() | true
52+
CoderCLIManager.getDataDir() | true
4553
}
4654
}

0 commit comments

Comments
 (0)