Refactor RealFileSystem to use WorkingDir, and ensure clean shutdown with FlushAll
This commit is contained in:
parent
ac2e0e444d
commit
1324772215
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -11,6 +11,7 @@
|
||||||
*.jar
|
*.jar
|
||||||
./pad
|
./pad
|
||||||
cmd/pad/pad
|
cmd/pad/pad
|
||||||
|
cmd/pad/classes
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
.idea/
|
.idea/
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package st.wow.git.logbook;
|
||||||
|
|
||||||
import java.lang.Runnable;
|
import java.lang.Runnable;
|
||||||
import java.lang.String;
|
import java.lang.String;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -39,23 +40,47 @@ public class Permissions extends Fragment {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onAttach(Context ctx) {
|
@Override
|
||||||
super.onAttach(ctx);
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
Log.d("gio", "onAttach()");
|
Log.d("gio", "onAttach()");
|
||||||
if (ctx instanceof Activity) {
|
|
||||||
Log.d("gio", "It's an Activity!");
|
if (!(context instanceof Activity)) {
|
||||||
|
Log.w("gio", "Context is not an Activity");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (ctx.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ctx.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
Log.d("gio", "Requesting permissions");
|
Activity activity = (Activity) context;
|
||||||
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST);
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
|
if (context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
requestPermissions(
|
||||||
|
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||||
|
PERMISSIONS_REQUEST
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!Environment.isExternalStorageManager()){
|
}
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
|
||||||
Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null);
|
&& !Environment.isExternalStorageManager()) {
|
||||||
intent.setData(uri);
|
Log.d("gio", "Requesting all files access");
|
||||||
|
Intent intent = new Intent(
|
||||||
|
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
|
||||||
|
Uri.parse("package:" + activity.getPackageName())
|
||||||
|
);
|
||||||
|
if (intent.resolveActivity(activity.getPackageManager()) != null) {
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
|
Intent fallback = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
|
||||||
|
if (fallback.resolveActivity(activity.getPackageManager()) != null) {
|
||||||
|
startActivity(fallback);
|
||||||
|
} else {
|
||||||
|
Log.e("gio", "No activity found for all files access settings");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log.d("gio", "Loading gio library");
|
Log.d("gio", "Loading gio library");
|
||||||
System.loadLibrary("gio");
|
System.loadLibrary("gio");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
|
|
||||||
type JNIEnv = C.JNIEnv
|
type JNIEnv = C.JNIEnv
|
||||||
var (
|
var (
|
||||||
startpath="/storage/emulated/0/Documents"
|
startpath="/storage/emulated/0/Notes"
|
||||||
jvm uintptr
|
jvm uintptr
|
||||||
theJVM *C.JavaVM
|
theJVM *C.JavaVM
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gioui.org/app"
|
"gioui.org/app"
|
||||||
|
|
@ -41,12 +40,8 @@ func run(w *app.Window) error {
|
||||||
rootDir := flag.String("root", startpath, "root directory for the filesystem")
|
rootDir := flag.String("root", startpath, "root directory for the filesystem")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
abs, err := filepath.Abs(*rootDir)
|
fs := real.NewRealFileSystem(*rootDir)
|
||||||
if err != nil {
|
log.Printf("using filesystem at %s", fs.WorkingDir)
|
||||||
log.Fatalf("invalid root directory: %v", err)
|
|
||||||
}
|
|
||||||
fs := &real.RealFileSystem{Root: abs}
|
|
||||||
log.Printf("using filesystem at %s", abs)
|
|
||||||
|
|
||||||
logic := editor.NewLogic(fs)
|
logic := editor.NewLogic(fs)
|
||||||
renderer := ui.New(ui.Theme{FontSize: 14}, shaper, logic.State())
|
renderer := ui.New(ui.Theme{FontSize: 14}, shaper, logic.State())
|
||||||
|
|
@ -62,6 +57,7 @@ func run(w *app.Window) error {
|
||||||
for {
|
for {
|
||||||
switch e := w.Event().(type) {
|
switch e := w.Event().(type) {
|
||||||
case app.DestroyEvent:
|
case app.DestroyEvent:
|
||||||
|
logic.Shutdown()
|
||||||
return e.Err
|
return e.Err
|
||||||
case app.ConfigEvent:
|
case app.ConfigEvent:
|
||||||
// ConfigEvent: raw pixel dimensions only.
|
// ConfigEvent: raw pixel dimensions only.
|
||||||
|
|
|
||||||
|
|
@ -413,3 +413,10 @@ func (l *Logic) FlushAll() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown gracefully shuts down the logic goroutine and worker pool.
|
||||||
|
func (l *Logic) Shutdown() {
|
||||||
|
l.FlushAll()
|
||||||
|
l.Done()
|
||||||
|
l.workerPool.Stop()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,24 @@ import (
|
||||||
|
|
||||||
// RealFileSystem implements the pool.FileSystem interface using the real OS filesystem.
|
// RealFileSystem implements the pool.FileSystem interface using the real OS filesystem.
|
||||||
type RealFileSystem struct {
|
type RealFileSystem struct {
|
||||||
Root string
|
WorkingDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRealFileSystem creates a RealFileSystem rooted at the given working directory.
|
||||||
|
// If workingDir is empty, it defaults to "/".
|
||||||
|
func NewRealFileSystem(workingDir string) *RealFileSystem {
|
||||||
|
if workingDir == "" {
|
||||||
|
workingDir = "/"
|
||||||
|
}
|
||||||
|
abs, err := filepath.Abs(workingDir)
|
||||||
|
if err != nil {
|
||||||
|
abs = workingDir
|
||||||
|
}
|
||||||
|
return &RealFileSystem{WorkingDir: abs}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *RealFileSystem) ReadDir(path string) ([]types.DirEntry, error) {
|
func (fs *RealFileSystem) ReadDir(path string) ([]types.DirEntry, error) {
|
||||||
entries, err := os.ReadDir(filepath.Join(fs.Root, path))
|
entries, err := os.ReadDir(filepath.Join(fs.WorkingDir, path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -25,21 +38,21 @@ func (fs *RealFileSystem) ReadDir(path string) ([]types.DirEntry, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *RealFileSystem) DirExists(path string) bool {
|
func (fs *RealFileSystem) DirExists(path string) bool {
|
||||||
info, err := os.Stat(filepath.Join(fs.Root, path))
|
info, err := os.Stat(filepath.Join(fs.WorkingDir, path))
|
||||||
return err == nil && info.IsDir()
|
return err == nil && info.IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *RealFileSystem) FileExists(path string) bool {
|
func (fs *RealFileSystem) FileExists(path string) bool {
|
||||||
info, err := os.Stat(filepath.Join(fs.Root, path))
|
info, err := os.Stat(filepath.Join(fs.WorkingDir, path))
|
||||||
return err == nil && !info.IsDir()
|
return err == nil && !info.IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *RealFileSystem) ReadFile(path string) ([]byte, error) {
|
func (fs *RealFileSystem) ReadFile(path string) ([]byte, error) {
|
||||||
return os.ReadFile(filepath.Join(fs.Root, path))
|
return os.ReadFile(filepath.Join(fs.WorkingDir, path))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *RealFileSystem) ReadFileAt(path string, offset, size int) ([]byte, error) {
|
func (fs *RealFileSystem) ReadFileAt(path string, offset, size int) ([]byte, error) {
|
||||||
fullPath := filepath.Join(fs.Root, path)
|
fullPath := filepath.Join(fs.WorkingDir, path)
|
||||||
f, err := os.Open(fullPath)
|
f, err := os.Open(fullPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -61,7 +74,7 @@ func (fs *RealFileSystem) WriteFile(path string, content []byte) error {
|
||||||
|
|
||||||
func (fs *RealFileSystem) WriteFileAtomic(path string, content []byte) error {
|
func (fs *RealFileSystem) WriteFileAtomic(path string, content []byte) error {
|
||||||
// Atomic write implementation
|
// Atomic write implementation
|
||||||
fullPath := filepath.Join(fs.Root, path)
|
fullPath := filepath.Join(fs.WorkingDir, path)
|
||||||
// Temp file in the same directory as the target to ensure same filesystem rename
|
// Temp file in the same directory as the target to ensure same filesystem rename
|
||||||
tmpPath := filepath.Join(filepath.Dir(fullPath), "."+filepath.Base(path)+".tmp")
|
tmpPath := filepath.Join(filepath.Dir(fullPath), "."+filepath.Base(path)+".tmp")
|
||||||
|
|
||||||
|
|
@ -77,11 +90,11 @@ func (fs *RealFileSystem) WriteFileAtomic(path string, content []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *RealFileSystem) DeleteFile(path string) error {
|
func (fs *RealFileSystem) DeleteFile(path string) error {
|
||||||
return os.Remove(filepath.Join(fs.Root, path))
|
return os.Remove(filepath.Join(fs.WorkingDir, path))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *RealFileSystem) CreateDir(path string) error {
|
func (fs *RealFileSystem) CreateDir(path string) error {
|
||||||
return os.MkdirAll(filepath.Join(fs.Root, path), 0755)
|
return os.MkdirAll(filepath.Join(fs.WorkingDir, path), 0755)
|
||||||
}
|
}
|
||||||
|
|
||||||
// realDirEntry wraps os.DirEntry
|
// realDirEntry wraps os.DirEntry
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user