Refactor RealFileSystem to use WorkingDir, and ensure clean shutdown with FlushAll

This commit is contained in:
Greg Pomerantz 2026-06-05 11:42:39 -04:00
parent ac2e0e444d
commit 1324772215
6 changed files with 78 additions and 36 deletions

1
.gitignore vendored
View File

@ -11,6 +11,7 @@
*.jar
./pad
cmd/pad/pad
cmd/pad/classes
# IDE
.idea/

View File

@ -2,6 +2,7 @@ package st.wow.git.logbook;
import java.lang.Runnable;
import java.lang.String;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.content.Context;
@ -39,25 +40,49 @@ public class Permissions extends Fragment {
});
}
@Override public void onAttach(Context ctx) {
super.onAttach(ctx);
Log.d("gio", "onAttach()");
if (ctx instanceof Activity) {
Log.d("gio", "It's an Activity!");
}
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");
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST);
}
if (!Environment.isExternalStorageManager()){
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
Log.d("gio", "Loading gio library");
System.loadLibrary("gio");
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d("gio", "onAttach()");
if (!(context instanceof Activity)) {
Log.w("gio", "Context is not an Activity");
return;
}
Activity activity = (Activity) context;
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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& !Environment.isExternalStorageManager()) {
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);
} 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");
System.loadLibrary("gio");
}
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {

View File

@ -24,7 +24,7 @@ import (
type JNIEnv = C.JNIEnv
var (
startpath="/storage/emulated/0/Documents"
startpath="/storage/emulated/0/Notes"
jvm uintptr
theJVM *C.JavaVM
)

View File

@ -4,7 +4,6 @@ import (
"flag"
"log"
"os"
"path/filepath"
"sync"
"gioui.org/app"
@ -41,12 +40,8 @@ func run(w *app.Window) error {
rootDir := flag.String("root", startpath, "root directory for the filesystem")
flag.Parse()
abs, err := filepath.Abs(*rootDir)
if err != nil {
log.Fatalf("invalid root directory: %v", err)
}
fs := &real.RealFileSystem{Root: abs}
log.Printf("using filesystem at %s", abs)
fs := real.NewRealFileSystem(*rootDir)
log.Printf("using filesystem at %s", fs.WorkingDir)
logic := editor.NewLogic(fs)
renderer := ui.New(ui.Theme{FontSize: 14}, shaper, logic.State())
@ -62,6 +57,7 @@ func run(w *app.Window) error {
for {
switch e := w.Event().(type) {
case app.DestroyEvent:
logic.Shutdown()
return e.Err
case app.ConfigEvent:
// ConfigEvent: raw pixel dimensions only.

View File

@ -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()
}

View File

@ -9,11 +9,24 @@ import (
// RealFileSystem implements the pool.FileSystem interface using the real OS filesystem.
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) {
entries, err := os.ReadDir(filepath.Join(fs.Root, path))
entries, err := os.ReadDir(filepath.Join(fs.WorkingDir, path))
if err != nil {
return nil, err
}
@ -25,21 +38,21 @@ func (fs *RealFileSystem) ReadDir(path string) ([]types.DirEntry, error) {
}
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()
}
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()
}
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) {
fullPath := filepath.Join(fs.Root, path)
fullPath := filepath.Join(fs.WorkingDir, path)
f, err := os.Open(fullPath)
if err != nil {
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 {
// 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
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 {
return os.Remove(filepath.Join(fs.Root, path))
return os.Remove(filepath.Join(fs.WorkingDir, path))
}
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