Skip to content

Commit

Permalink
Place Git workdirs in private storage
Browse files Browse the repository at this point in the history
and remove all Git settings related to the workdir location.

The directory containing the workdir is named using the repo ID. This
should allow changing the URL of an existing repo.

I thought for a while about a feature to copy/export the directory to
public storage for troubleshooting purposes, but I came to the
conclusion that it should not be necessary. If the user is worried about
losing local state, they can always export the relevant notebooks as
text files, and re-import them later. If the repo is somehow broken, it
is best to delete it and add a new one, re-linking the notebooks (and
deleting the local copies, if necessary). If there are tenacious bugs,
they should be ironed out on a virtual device with full root access.

This resolves #21.
  • Loading branch information
amberin committed Oct 12, 2023
1 parent 9efb7b1 commit b14b751
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ public String getEmail() {
public String repositoryFilepath() {
return repoPreferences.getStringValueWithGlobalDefault(
R.string.pref_key_git_repository_filepath,
AppPreferences.repositoryStoragePathForUri(
repoPreferences.getContext(), remoteUri()));
AppPreferences.gitRepoStoragePathForRepoId(
repoPreferences.getContext(),
repoPreferences.getRepoId()));
}

@Override
Expand Down
24 changes: 2 additions & 22 deletions app/src/main/java/com/orgzly/android/prefs/AppPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -916,31 +916,11 @@ public static boolean gitIsEnabled(Context context) {
context.getResources().getString(R.string.pref_key_git_is_enabled),
context.getResources().getBoolean(R.bool.pref_default_git_is_enabled));
}

public static String defaultRepositoryStorageDirectory(Context context) {
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
return getStringFromSelector(
context, R.string.pref_key_git_default_repository_directory, path.toString());
}

public static String repositoryStoragePathForUri(Context context, Uri repoUri) {
String directoryFilename = repoUri.toString();
try {
directoryFilename = new URIish(directoryFilename).getPath();
} catch (URISyntaxException e) {
directoryFilename = directoryFilename.replaceAll("/[^A-Za-z0-9 ]/", "");
}
Uri baseUri = Uri.parse(defaultRepositoryStorageDirectory(context));
return baseUri.buildUpon().appendPath(directoryFilename).build().getPath();
}

private static String getStringFromSelector(Context context, int selector, String def) {
return getStateSharedPreferences(context).getString(getSelector(context, selector), def);
public static String gitRepoStoragePathForRepoId(Context context, Long repoId) {
return new File(context.getCacheDir(), "gitrepo" + repoId).getAbsolutePath();
}

private static String getSelector(Context context, int selector) {
return context.getResources().getString(selector);
}

/*
* Last used version.
Expand Down
10 changes: 2 additions & 8 deletions app/src/main/java/com/orgzly/android/repos/GitRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,8 @@ private static Git verifyExistingRepo(File directoryFile) throws IOException {
*/
private static Git cloneRepo(Uri repoUri, File directoryFile, GitTransportSetter transportSetter,
ProgressMonitor pm) throws IOException {
if (!directoryFile.exists()) {
throw new IOException(String.format("The directory %s does not exist", directoryFile.toString()), new FileNotFoundException());
}

// Using list() can be resource intensive if there's many files, but since we just call it
// at the time of cloning once we should be fine for now
if (directoryFile.list().length != 0) {
throw new IOException(String.format("The directory must be empty"), new DirectoryNotEmpty(directoryFile));
if (!directoryFile.mkdir()) {
throw new IOException(String.format("Failed to create Git workdir %s", directoryFile));
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.orgzly.android.ui.SingleLiveEvent
import com.orgzly.android.usecase.RepoCreate
import com.orgzly.android.usecase.RepoUpdate
import com.orgzly.android.usecase.UseCase
import com.orgzly.android.usecase.UseCaseResult
import com.orgzly.android.usecase.UseCaseRunner

open class RepoViewModel(private val dataRepository: DataRepository, open var repoId: Long) : CommonViewModel() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import android.net.Uri
import android.os.AsyncTask
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.text.TextUtils
import android.view.ContextMenu
Expand All @@ -31,18 +30,15 @@ import com.orgzly.android.prefs.RepoPreferences
import com.orgzly.android.repos.GitRepo
import com.orgzly.android.repos.RepoType
import com.orgzly.android.ui.CommonActivity
import com.orgzly.android.ui.repo.BrowserActivity
import com.orgzly.android.ui.repo.RepoViewModel
import com.orgzly.android.ui.repo.RepoViewModelFactory
import com.orgzly.android.ui.showSnackbar
import com.orgzly.android.util.AppPermissions
import com.orgzly.android.util.MiscUtils
import com.orgzly.databinding.ActivityRepoGitBinding
import org.eclipse.jgit.errors.TransportException
import org.eclipse.jgit.errors.NoRemoteRepositoryException
import org.eclipse.jgit.errors.NotSupportedException
import org.eclipse.jgit.lib.ProgressMonitor
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException

Expand All @@ -65,10 +61,6 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
setContentView(binding.root)

fields = arrayOf(
Field(
binding.activityRepoGitDirectory,
binding.activityRepoGitDirectoryLayout,
R.string.pref_key_git_repository_filepath),
Field(
binding.activityRepoGitHttpsUsername,
binding.activityRepoGitHttpsUsernameLayout,
Expand Down Expand Up @@ -100,10 +92,6 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
MiscUtils.clearErrorOnTextChange(it.editText, it.layout)
}

binding.activityRepoGitDirectoryBrowse.setOnClickListener {
startLocalFileBrowser(binding.activityRepoGitDirectory, ACTIVITY_REQUEST_CODE_FOR_DIRECTORY_SELECTION)
}

val repoId = intent.getLongExtra(ARG_REPO_ID, 0)

val factory = RepoViewModelFactory.getInstance(dataRepository, repoId)
Expand All @@ -118,7 +106,6 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
}
} else {
/* Set default values for new repo being added. */
createDefaultRepoFolder()
binding.activityRepoGitAuthor.setText("Orgzly")
binding.activityRepoGitBranch.setText(R.string.git_default_branch)
val userDeviceName: String = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
Expand All @@ -131,9 +118,7 @@ class GitRepoActivity : CommonActivity(), GitPreferences {

viewModel.finishEvent.observeSingle(this, Observer {
saveToPreferences(viewModel.repoId)

// TODO: Check permission on start
runWithPermission(AppPermissions.Usage.LOCAL_REPO, Runnable { finish() })
finish()
})

viewModel.alreadyExistsEvent.observeSingle(this, Observer {
Expand Down Expand Up @@ -203,23 +188,6 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
}
}

// TODO: Since we can create multiple syncs, this folder might be re-used, do we want to create
// a new one if this directory is already used up?
private fun createDefaultRepoFolder() {
if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
return
}
val externalPath = Environment.getExternalStorageDirectory().path
val orgzlyGitPath = File("$externalPath/orgzly-git/")
var success = false
try {
success = orgzlyGitPath.mkdirs()
} catch(error: SecurityException) {}
if (success || (orgzlyGitPath.exists() && orgzlyGitPath.list().size == 0)) {
binding.activityRepoGitDirectory.setText(orgzlyGitPath.path)
}
}

private fun setFromPreferences() {
val prefs = RepoPreferences.fromId(this, viewModel.repoId, dataRepository)
for (field in fields) {
Expand Down Expand Up @@ -271,13 +239,9 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
if (repoId != 0L) {
save()
} else {
val targetDirectory = File(binding.activityRepoGitDirectory.text.toString())
if (targetDirectory.list()!!.isNotEmpty()) {
binding.activityRepoGitDirectoryLayout.error = getString(R.string.git_clone_error_target_not_empty)
} else {
// TODO: If this fails we should notify the user in a nice way and mark the git repo field as bad
RepoCloneTask(this).execute()
}
save() // Create the new repo in the database, so that viewModel knows its repoId.
// TODO: If this fails we should notify the user in a nice way and mark the git repo field as bad
RepoCloneTask(this).execute()
}
}
}
Expand Down Expand Up @@ -339,11 +303,6 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
hasEmptyFields = true
}

val targetDirectory = File(binding.activityRepoGitDirectory.text.toString())
if (!targetDirectory.exists()) {
binding.activityRepoGitDirectoryLayout.error = getString(R.string.git_clone_error_invalid_target_dir)
}

for (field in fields) {
if (field.layout.visibility == View.GONE || field.allowEmpty) {
continue;
Expand Down Expand Up @@ -398,12 +357,7 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
}

override fun repositoryFilepath(): String {
val v = binding.activityRepoGitDirectory.text.toString()
return if (v.isNotEmpty()) {
v
} else {
AppPreferences.repositoryStoragePathForUri(this, remoteUri())
}
return AppPreferences.gitRepoStoragePathForRepoId(this, viewModel.repoId)
}

override fun remoteName(): String {
Expand All @@ -420,34 +374,6 @@ class GitRepoActivity : CommonActivity(), GitPreferences {
return Uri.parse(remoteUriString)
}

private fun startLocalFileBrowser(editText: EditText, requestCode: Int, isFileSelectable: Boolean = false) {
val intent = Intent(Intent.ACTION_VIEW).setClass(this, BrowserActivity::class.java)

if (!TextUtils.isEmpty(editText.text)) {
val uri = editText.text.toString()
val path = Uri.parse(uri).path
intent.putExtra(BrowserActivity.ARG_STARTING_DIRECTORY, path)
}

if (isFileSelectable) {
intent.putExtra(BrowserActivity.ARG_IS_FILE_SELECTABLE, true)
}

startActivityForResult(intent, requestCode)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)

when (requestCode) {
ACTIVITY_REQUEST_CODE_FOR_DIRECTORY_SELECTION ->
if (resultCode == Activity.RESULT_OK && data != null) {
val uri = data.data
binding.activityRepoGitDirectory.setText(uri?.path)
}
}
}

internal inner class CloneProgressUpdate(var amount: Int, var setMax: Boolean)

internal inner class RepoCloneTask(var fragment: GitRepoActivity) : AsyncTask<Void, CloneProgressUpdate, IOException>(), ProgressMonitor {
Expand Down Expand Up @@ -517,8 +443,6 @@ class GitRepoActivity : CommonActivity(), GitPreferences {

private const val ARG_REPO_ID = "repo_id"

const val ACTIVITY_REQUEST_CODE_FOR_DIRECTORY_SELECTION = 0

@JvmStatic
@JvmOverloads
fun start(activity: Activity, repoId: Long = 0) {
Expand Down
32 changes: 0 additions & 32 deletions app/src/main/res/layout/activity_repo_git.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,38 +37,6 @@

</com.google.android.material.textfield.TextInputLayout>

<!-- Directory -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/space_between_content_areas"
android:orientation="horizontal">

<Button
android:id="@+id/activity_repo_git_directory_browse"
style="@style/Button.Repo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screen_edge"
android:text="@string/browse" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/activity_repo_git_directory_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/activity_repo_git_directory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/git_directory_hint"
android:inputType="text" />

</com.google.android.material.textfield.TextInputLayout>

</LinearLayout>

<LinearLayout
android:id="@+id/activity_repo_git_https_auth_info"
android:layout_width="match_parent"
Expand Down

0 comments on commit b14b751

Please sign in to comment.