Skip to content

Commit d634863

Browse files
authored
Deprecate Resource.Builder.isExecutable in favor of defining a mode (#105)
1 parent dfd600a commit d634863

10 files changed

Lines changed: 92 additions & 14 deletions

File tree

library/common-core/api/common-core.api

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ public final class io/matthewnelson/kmp/tor/common/core/PlatformResource$Builder
111111
public final class io/matthewnelson/kmp/tor/common/core/Resource {
112112
public final field alias Ljava/lang/String;
113113
public final field isExecutable Z
114+
public final field mode Ljava/lang/String;
114115
public final field platform Lio/matthewnelson/kmp/tor/common/core/PlatformResource;
115-
public synthetic fun <init> (Ljava/lang/String;ZLio/matthewnelson/kmp/tor/common/core/PlatformResource;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
116+
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/matthewnelson/kmp/tor/common/core/PlatformResource;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
116117
public fun equals (Ljava/lang/Object;)Z
117118
public fun hashCode ()I
118119
public fun toString ()Ljava/lang/String;
@@ -121,6 +122,7 @@ public final class io/matthewnelson/kmp/tor/common/core/Resource {
121122
public final class io/matthewnelson/kmp/tor/common/core/Resource$Builder {
122123
public final field alias Ljava/lang/String;
123124
public field isExecutable Z
125+
public final fun mode (Ljava/lang/String;)Lio/matthewnelson/kmp/tor/common/core/Resource$Builder;
124126
public final fun platform (Lkotlin/jvm/functions/Function1;)Lio/matthewnelson/kmp/tor/common/core/Resource$Builder;
125127
}
126128

library/common-core/api/common-core.klib.api

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ final class io.matthewnelson.kmp.tor.common.core/Resource { // io.matthewnelson.
4040
final fun <get-alias>(): kotlin/String // io.matthewnelson.kmp.tor.common.core/Resource.alias.<get-alias>|<get-alias>(){}[0]
4141
final val isExecutable // io.matthewnelson.kmp.tor.common.core/Resource.isExecutable|{}isExecutable[0]
4242
final fun <get-isExecutable>(): kotlin/Boolean // io.matthewnelson.kmp.tor.common.core/Resource.isExecutable.<get-isExecutable>|<get-isExecutable>(){}[0]
43+
final val mode // io.matthewnelson.kmp.tor.common.core/Resource.mode|{}mode[0]
44+
final fun <get-mode>(): kotlin/String // io.matthewnelson.kmp.tor.common.core/Resource.mode.<get-mode>|<get-mode>(){}[0]
4345
final val platform // io.matthewnelson.kmp.tor.common.core/Resource.platform|{}platform[0]
4446
final fun <get-platform>(): io.matthewnelson.kmp.tor.common.core/PlatformResource // io.matthewnelson.kmp.tor.common.core/Resource.platform.<get-platform>|<get-platform>(){}[0]
4547

@@ -55,6 +57,7 @@ final class io.matthewnelson.kmp.tor.common.core/Resource { // io.matthewnelson.
5557
final fun <get-isExecutable>(): kotlin/Boolean // io.matthewnelson.kmp.tor.common.core/Resource.Builder.isExecutable.<get-isExecutable>|<get-isExecutable>(){}[0]
5658
final fun <set-isExecutable>(kotlin/Boolean) // io.matthewnelson.kmp.tor.common.core/Resource.Builder.isExecutable.<set-isExecutable>|<set-isExecutable>(kotlin.Boolean){}[0]
5759

60+
final fun mode(kotlin/String?): io.matthewnelson.kmp.tor.common.core/Resource.Builder // io.matthewnelson.kmp.tor.common.core/Resource.Builder.mode|mode(kotlin.String?){}[0]
5861
final fun platform(kotlin/Function1<io.matthewnelson.kmp.tor.common.core/PlatformResource.Builder, kotlin/Unit>): io.matthewnelson.kmp.tor.common.core/Resource.Builder // io.matthewnelson.kmp.tor.common.core/Resource.Builder.platform|platform(kotlin.Function1<io.matthewnelson.kmp.tor.common.core.PlatformResource.Builder,kotlin.Unit>){}[0]
5962
}
6063

library/common-core/src/commonMain/kotlin/io/matthewnelson/kmp/tor/common/core/Resource.kt

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import io.matthewnelson.immutable.collections.toImmutableSet
2020
import io.matthewnelson.kmp.file.File
2121
import io.matthewnelson.kmp.file.IOException
2222
import io.matthewnelson.kmp.file.canonicalFile2
23+
import io.matthewnelson.kmp.file.chmod2
2324
import io.matthewnelson.kmp.file.delete2
2425
import io.matthewnelson.kmp.file.mkdirs2
2526
import io.matthewnelson.kmp.file.wrapIOException
@@ -36,11 +37,18 @@ public class Resource private constructor(
3637
@JvmField
3738
public val alias: String,
3839
@JvmField
39-
public val isExecutable: Boolean,
40+
public val mode: String,
4041
@JvmField
4142
public val platform: PlatformResource,
4243
) {
4344

45+
@JvmField
46+
@Deprecated("Use mode")
47+
public val isExecutable: Boolean = when (mode.first()) {
48+
'7', '5', '3', '1' -> true
49+
else -> false
50+
}
51+
4452
@InternalKmpTorApi
4553
public class Config private constructor(
4654
@JvmField
@@ -205,11 +213,38 @@ public class Resource private constructor(
205213
public val alias: String
206214
) {
207215

216+
private var _mode: String? = null
217+
208218
@JvmField
219+
@Deprecated("Use mode")
209220
public var isExecutable: Boolean = false
210221

211222
private var platform: PlatformResource? = null
212223

224+
/**
225+
* Set the file permissions for the newly extracted resource.
226+
*
227+
* @see [File.chmod2]
228+
*
229+
* @throws [IllegalArgumentException] If [value] is inappropriate.
230+
* */
231+
@KmpTorDsl
232+
public fun mode(
233+
value: String?,
234+
): Builder {
235+
if (value == null) {
236+
_mode = value
237+
return this
238+
}
239+
240+
require(value.length == 3) { "Invalid mode.length[${value.length}]. Must be 3 digits[0-7] (e.g. 764)" }
241+
value.forEach { c ->
242+
require(c in '0'..'7') { "Invalid mode[$value]. Must be 3 digits[0-7] (e.g. 764)" }
243+
}
244+
_mode = value
245+
return this
246+
}
247+
213248
@KmpTorDsl
214249
public fun platform(
215250
block: PlatformResource.Builder.() -> Unit
@@ -221,8 +256,13 @@ public class Resource private constructor(
221256
@JvmSynthetic
222257
internal fun build(): Resource? {
223258
val p = platform ?: return null
259+
var m = _mode
260+
if (m == null) {
261+
@Suppress("DEPRECATION")
262+
m = if (isExecutable) "500" else "400"
263+
}
224264

225-
return Resource(alias, isExecutable, p)
265+
return Resource(alias, m, p)
226266
}
227267
}
228268

@@ -232,8 +272,8 @@ public class Resource private constructor(
232272
appendLine("Resource: [")
233273
appendIndent("alias: ")
234274
appendLine(alias)
235-
appendIndent("isExecutable: ")
236-
appendLine(isExecutable)
275+
appendIndent("mode: ")
276+
appendLine(mode)
237277
appendIndent("platform: [")
238278
appendLine()
239279

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2025 Matthew Nelson
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
package io.matthewnelson.kmp.tor.common.core
17+
18+
import io.matthewnelson.kmp.tor.common.api.InternalKmpTorApi
19+
import kotlin.test.Test
20+
import kotlin.test.assertFailsWith
21+
22+
@OptIn(InternalKmpTorApi::class)
23+
class CommonResourceUnitTest {
24+
25+
@Test
26+
fun givenMode_whenInappropriate_thenThrowsIllegalArgumentException() {
27+
val b = Resource.Builder("alias")
28+
29+
assertFailsWith<IllegalArgumentException> { b.mode("") }
30+
assertFailsWith<IllegalArgumentException> { b.mode("800") }
31+
assertFailsWith<IllegalArgumentException> { b.mode("2000") }
32+
}
33+
}

library/common-core/src/jsWasmJsMain/kotlin/io/matthewnelson/kmp/tor/common/core/internal/JsWasmJsPlatform.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ internal actual fun Resource.extractTo(destinationDir: File, onlyIfDoesNotExist:
5757
}
5858
}
5959

60-
val excl = OpenExcl.MustCreate.of(mode = if (isExecutable) "500" else "400")
60+
val excl = OpenExcl.MustCreate.of(mode = mode)
6161
try {
6262
destination.write(excl, buffer)
6363
} catch (e: IOException) {

library/common-core/src/jsWasmJsTest/kotlin/io/matthewnelson/kmp/tor/common/core/JsResourceUnitTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class JsResourceUnitTest {
3434
val alias = "hello_gzip"
3535
val config = Resource.Config.create {
3636
resource(alias) {
37-
isExecutable = false
37+
mode("400")
3838
platform {
3939
moduleName = "kmp-tor-core-test-resources"
4040
resourcePath = "/io/matthewnelson/kmp/tor/core/resource/hello_world.gz"
@@ -64,7 +64,7 @@ class JsResourceUnitTest {
6464
val alias = "hello"
6565
val config = Resource.Config.create {
6666
resource(alias) {
67-
isExecutable = false
67+
mode("400")
6868
platform {
6969
moduleName = "kmp-tor-core-test-resources"
7070
resourcePath = "/io/matthewnelson/kmp/tor/core/resource/hello_world"

library/common-core/src/jvmMain/kotlin/io/matthewnelson/kmp/tor/common/core/internal/-JvmPlatform.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ internal actual fun Resource.extractTo(destinationDir: File, onlyIfDoesNotExist:
6060
}
6161
}
6262

63-
val excl = OpenExcl.MustCreate.of(mode = if (isExecutable) "500" else "400")
63+
val excl = OpenExcl.MustCreate.of(mode = mode)
6464

6565
try {
6666
resourceStream.use { iStream ->

library/common-core/src/jvmTest/kotlin/io/matthewnelson/kmp/tor/common/core/JvmResourceUnitTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class JvmResourceUnitTest {
3333
val alias = "hello_gzip"
3434
val config = Resource.Config.create {
3535
resource(alias) {
36-
isExecutable = false
36+
mode("400")
3737
platform {
3838
resourceClass = JvmResourceUnitTest::class.java
3939
resourcePath = "/io/matthewnelson/kmp/tor/common/core/hello_world.gz"
@@ -63,7 +63,7 @@ class JvmResourceUnitTest {
6363
val alias = "hello"
6464
val config = Resource.Config.create {
6565
resource(alias) {
66-
isExecutable = false
66+
mode("400")
6767
platform {
6868
resourceClass = JvmResourceUnitTest::class.java
6969
resourcePath = "/io/matthewnelson/kmp/tor/common/core/hello_world"

library/common-core/src/nativeMain/kotlin/io/matthewnelson/kmp/tor/common/core/internal/NativePlatform.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ internal actual fun Resource.extractTo(destinationDir: File, onlyIfDoesNotExist:
6262
dest.delete2(ignoreReadOnly = true)
6363
destFinal?.delete2(ignoreReadOnly = true)
6464

65-
val excl = OpenExcl.MustCreate.of(mode = if (isExecutable) "500" else "400")
65+
val excl = OpenExcl.MustCreate.of(mode = mode)
6666
try {
6767
dest.openWrite(excl = if (destFinal == null) excl else null).use { s ->
6868
platform.nativeResource.read { buf, len ->

library/common-core/src/nativeTest/kotlin/io/matthewnelson/kmp/tor/common/core/NativeResourceUnitTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class NativeResourceUnitTest {
5050

5151
val config = Resource.Config.create {
5252
resource(alias) {
53-
isExecutable = false
53+
mode("400")
5454
platform { nativeResource = resource_LoremIpsum_gz }
5555
}
5656
}
@@ -81,7 +81,7 @@ class NativeResourceUnitTest {
8181

8282
val config = Resource.Config.create {
8383
resource(alias) {
84-
isExecutable = false
84+
mode("400")
8585
platform { nativeResource = resource_lorem_ipsum }
8686
}
8787
}

0 commit comments

Comments
 (0)