feat: UI compact layout + unlock support + ResticBinary init at startup
This commit is contained in:
@@ -13,6 +13,8 @@ import androidx.viewpager2.widget.ViewPager2
|
||||
import com.example.androidbackupgui.databinding.ActivityMainBinding
|
||||
import com.example.androidbackupgui.root.RootShell
|
||||
import com.example.androidbackupgui.backup.LogUtil
|
||||
import com.example.androidbackupgui.backup.ResticBinary
|
||||
import com.example.androidbackupgui.backup.ResticWrapper
|
||||
import com.example.androidbackupgui.ui.BackupFragment
|
||||
import com.example.androidbackupgui.ui.ConfigFragment
|
||||
import com.example.androidbackupgui.ui.RestoreFragment
|
||||
@@ -39,6 +41,9 @@ class MainActivity : AppCompatActivity() {
|
||||
// Configure libsu with global mount namespace support
|
||||
RootShell.configure()
|
||||
|
||||
// Initialize restic binary path
|
||||
ResticBinary.prepare(this)?.let { ResticWrapper.binaryPath = it }
|
||||
|
||||
// Request root access on startup
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
|
||||
@@ -61,6 +61,36 @@ class ResticMaintenance(
|
||||
}
|
||||
}
|
||||
|
||||
// ── Unlock ──────────────────────────────────────────
|
||||
|
||||
suspend fun unlock(
|
||||
repoPath: String,
|
||||
password: String,
|
||||
backend: String = "local",
|
||||
backendUrl: String = "",
|
||||
backendUser: String = "",
|
||||
backendPass: String = "",
|
||||
backendShare: String = "",
|
||||
): AppResult<String> =
|
||||
withContext(Dispatchers.IO) {
|
||||
if (backend == "local") {
|
||||
val env = envResolver.buildLocalEnv(repoPath, password, cacheDir)
|
||||
val result = runner.runRestic(env, "unlock")
|
||||
if (result.exitCode == 0) AppResult.Success(result.stdout)
|
||||
else err(AppError.Restic("restic unlock 失败", result.exitCode, result.stderr))
|
||||
} else {
|
||||
bridgeRunner.withBridge(
|
||||
backend, backendUrl, backendUser, backendPass, backendShare,
|
||||
backendDomain, repoPath, File(cacheDir)
|
||||
) { bridgeUrl, authToken ->
|
||||
val env = envResolver.buildBridgeEnv(password, bridgeUrl, cacheDir, authToken)
|
||||
val result = runner.runRestic(env, "unlock")
|
||||
if (result.exitCode == 0) AppResult.Success(result.stdout)
|
||||
else err(AppError.Restic("restic unlock 失败", result.exitCode, result.stderr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Check ──────────────────────────────────────────
|
||||
|
||||
suspend fun check(
|
||||
|
||||
@@ -359,6 +359,20 @@ object ResticWrapper {
|
||||
backend, backendUrl, backendUser, backendPass, backendShare
|
||||
)
|
||||
|
||||
suspend fun unlock(
|
||||
repoPath: String,
|
||||
password: String,
|
||||
backend: String = "local",
|
||||
backendUrl: String = "",
|
||||
backendUser: String = "",
|
||||
backendPass: String = "",
|
||||
backendShare: String = "",
|
||||
): AppResult<String> =
|
||||
maintenance.unlock(
|
||||
repoPath, password,
|
||||
backend, backendUrl, backendUser, backendPass, backendShare,
|
||||
)
|
||||
|
||||
// ── Public URL helper ──────────────────────────────
|
||||
|
||||
/** Build a display-friendly repository URL for UI. */
|
||||
|
||||
@@ -97,8 +97,8 @@ class BackupFragment : Fragment() {
|
||||
val names = userList.map { (id, name) -> "$name (ID: $id)" }
|
||||
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
binding.userSelector.adapter = adapter
|
||||
binding.userSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
binding.backupUserSelector.adapter = adapter
|
||||
binding.backupUserSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
selectedUserId = userList.getOrNull(position)?.first ?: 0
|
||||
}
|
||||
@@ -401,7 +401,7 @@ class BackupFragment : Fragment() {
|
||||
|
||||
private fun updateOutputPathDisplay() {
|
||||
val path = config.outputPath.ifEmpty { requireContext().filesDir.absolutePath }
|
||||
binding.outputPathLabel.text = path
|
||||
binding.outputPathLabel.text = "目录: $path"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -67,6 +67,9 @@ class ConfigFragment : Fragment() {
|
||||
binding.initResticButton.setOnClickListener { initResticRepo() }
|
||||
binding.resticStatsButton.setOnClickListener { showResticStats() }
|
||||
binding.resticPruneButton.setOnClickListener { pruneResticSnapshots() }
|
||||
binding.resticUnlockButton.setOnClickListener {
|
||||
vm.unlockResticRepo(readResticForm())
|
||||
}
|
||||
|
||||
// Initial async status check
|
||||
refreshResticStatus()
|
||||
@@ -140,6 +143,8 @@ class ConfigFragment : Fragment() {
|
||||
binding.resticStatsButton.visibility = if (statsButtonVisible) View.VISIBLE else View.GONE
|
||||
binding.resticPruneButton.isEnabled = pruneButtonEnabled
|
||||
binding.resticPruneButton.visibility = if (pruneButtonVisible) View.VISIBLE else View.GONE
|
||||
binding.resticUnlockButton.isEnabled = unlockButtonEnabled
|
||||
binding.resticUnlockButton.visibility = if (unlockButtonVisible) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,9 @@ data class ResticStatus(
|
||||
val statsButtonVisible: Boolean = false,
|
||||
val statsButtonEnabled: Boolean = true,
|
||||
val pruneButtonVisible: Boolean = false,
|
||||
val pruneButtonEnabled: Boolean = true
|
||||
val pruneButtonEnabled: Boolean = true,
|
||||
val unlockButtonVisible: Boolean = false,
|
||||
val unlockButtonEnabled: Boolean = true
|
||||
)
|
||||
|
||||
/** Restic credential/form snapshot passed from Fragment on every user interaction. */
|
||||
@@ -245,16 +247,39 @@ class ConfigViewModel(application: Application) : AndroidViewModel(application)
|
||||
_uiState.update { it.copy(resticStatus = ResticStatus(
|
||||
message = "仓库就绪,${snapshots.size} 个快照",
|
||||
snapshotCount = snapshots.size,
|
||||
initButtonVisible = false, statsButtonVisible = true, pruneButtonVisible = true
|
||||
initButtonVisible = false, statsButtonVisible = true, pruneButtonVisible = true,
|
||||
unlockButtonVisible = true
|
||||
))}
|
||||
} else {
|
||||
val errMsg = snapshotsResult.errorOrNull()?.message ?: ""
|
||||
val hasLock = errMsg.contains("lock", ignoreCase = true) || errMsg.contains("already locked", ignoreCase = true)
|
||||
_uiState.update { it.copy(resticStatus = ResticStatus(
|
||||
message = "仓库未初始化或认证失败",
|
||||
initButtonVisible = true, statsButtonVisible = false, pruneButtonVisible = false
|
||||
message = if (hasLock) "仓库被锁定,请先解锁" else "仓库未初始化或认证失败",
|
||||
initButtonVisible = !hasLock, statsButtonVisible = false, pruneButtonVisible = false,
|
||||
unlockButtonVisible = hasLock
|
||||
))}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun unlockResticRepo(form: ResticForm) {
|
||||
_uiState.update { it.copy(resticStatus = it.resticStatus.copy(
|
||||
message = "正在解锁仓库…", unlockButtonEnabled = false
|
||||
))}
|
||||
viewModelScope.launch {
|
||||
ResticWrapper.backendDomain = form.backendDomain
|
||||
val result = ResticWrapper.unlock(form.repo, form.password,
|
||||
backend = form.backend, backendUrl = form.backendUrl,
|
||||
backendUser = form.backendUser, backendPass = form.backendPass,
|
||||
backendShare = form.backendShare,
|
||||
)
|
||||
_uiState.update { it.copy(resticStatus = it.resticStatus.copy(
|
||||
message = if (result.isSuccess) "解锁完成" else "解锁失败: ${result.errorOrNull()?.message}",
|
||||
unlockButtonEnabled = true
|
||||
))}
|
||||
refreshResticStatus(form)
|
||||
}
|
||||
}
|
||||
|
||||
fun showResticStats(form: ResticForm) {
|
||||
_uiState.update { it.copy(resticStatus = it.resticStatus.copy(
|
||||
message = "正在读取统计…", statsButtonEnabled = false
|
||||
@@ -303,6 +328,15 @@ class ConfigViewModel(application: Application) : AndroidViewModel(application)
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
_operationEvents.emit(OperationEvent.PruneStarted)
|
||||
|
||||
// Remove stale locks before forget/prune
|
||||
ResticWrapper.backendDomain = form.backendDomain
|
||||
ResticWrapper.unlock(form.repo, form.password,
|
||||
backend = form.backend, backendUrl = form.backendUrl,
|
||||
backendUser = form.backendUser, backendPass = form.backendPass,
|
||||
backendShare = form.backendShare,
|
||||
)
|
||||
|
||||
val forgetResult = ResticWrapper.forget(form.repo, form.password,
|
||||
keepDaily = 7, keepWeekly = 4, keepMonthly = 3,
|
||||
backend = form.backend, backendUrl = form.backendUrl,
|
||||
|
||||
@@ -83,8 +83,8 @@ class RestoreFragment : Fragment() {
|
||||
val names = userList.map { (id, name) -> "$name (ID: $id)" }
|
||||
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
binding.userSelector.adapter = adapter
|
||||
binding.userSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
binding.restoreUserSelector.adapter = adapter
|
||||
binding.restoreUserSelector.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
selectedUserId = userList.getOrNull(position)?.first ?: 0
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
android:padding="@dimen/fragment_horizontal_padding"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<!-- Title + user selector -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -18,38 +19,33 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="应用备份"
|
||||
android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/scanButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="扫描应用"
|
||||
style="@style/Widget.Material3.Button.TonalButton" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="用户: "
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/userSelector"
|
||||
android:layout_width="0dp"
|
||||
android:id="@+id/backupUserSelector"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
android:minWidth="80dp"
|
||||
android:spinnerMode="dropdown" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/scanButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="扫描"
|
||||
style="@style/Widget.Material3.Button.TonalButton" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Output path + sort toolbar -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -57,13 +53,6 @@
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="输出目录: "
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/outputPathLabel"
|
||||
android:layout_width="0dp"
|
||||
@@ -71,7 +60,7 @@
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="middle"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@@ -80,9 +69,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="修改" />
|
||||
android:text="修改"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Sort/filter row -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -133,10 +124,11 @@
|
||||
style="@style/Widget.Material3.Button.TonalButton" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- System apps toggle + status -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
@@ -144,46 +136,49 @@
|
||||
android:id="@+id/showSystemSwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="显示系统应用"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||
android:text="系统应用"
|
||||
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||
android:checked="false" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:text="点击扫描"
|
||||
android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:indicatorColor="?attr/colorPrimary"
|
||||
app:trackColor="?attr/colorSurfaceVariant" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
android:text="点击扫描以载入应用列表"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/appList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="8dp" />
|
||||
android:paddingBottom="4dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/backupButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:enabled="false"
|
||||
android:text="开始备份选中应用"
|
||||
style="@style/Widget.Material3.Button" />
|
||||
|
||||
@@ -173,7 +173,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleSelection="true"
|
||||
app:selectionRequired="true">
|
||||
app:selectionRequired="true"
|
||||
app:checkedButton="@id/resticBackendLocal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resticBackendLocal"
|
||||
@@ -267,6 +268,7 @@
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="密码"
|
||||
android:visibility="gone"
|
||||
app:endIconMode="password_toggle"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/resticBackendPassEdit"
|
||||
@@ -308,10 +310,12 @@
|
||||
|
||||
<!-- Repo encryption password (always shown) -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/resticPasswordLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="仓库加密密码 (请妥善保管,遗失即无法恢复)"
|
||||
app:endIconMode="password_toggle"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/resticPasswordEdit"
|
||||
@@ -360,6 +364,14 @@
|
||||
android:text="清理"
|
||||
android:visibility="gone"
|
||||
style="@style/Widget.Material3.Button.TextButton" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resticUnlockButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="解锁"
|
||||
android:visibility="gone"
|
||||
style="@style/Widget.Material3.Button.TextButton" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/userSelector"
|
||||
android:id="@+id/restoreUserSelector"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
77
gradlew.bat
vendored
Normal file
77
gradlew.bat
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %OS%==Windows_NT setlocal
|
||||
|
||||
:omega
|
||||
Reference in New Issue
Block a user