diff --git a/lib/core/security/ssl_certificate_support.dart b/lib/core/security/ssl_certificate_support.dart index f4169753..887f7133 100644 --- a/lib/core/security/ssl_certificate_support.dart +++ b/lib/core/security/ssl_certificate_support.dart @@ -234,8 +234,9 @@ Future _isProcessAlive(int owner) async { return result.exitCode != 0 || '${result.stdout}'.contains('$owner'); } return (await Process.run('kill', ['-0', '$owner'])).exitCode == 0; - } catch (_) { + } catch (e) { // Cannot tell: leave the directory alone. + logIgnored('ssl_certificate_support', e); return true; } } diff --git a/lib/core/storage/folders_storage.dart b/lib/core/storage/folders_storage.dart index c8b4a565..c6701571 100644 --- a/lib/core/storage/folders_storage.dart +++ b/lib/core/storage/folders_storage.dart @@ -4,6 +4,8 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:querya_desktop/core/storage/app_data_root.dart'; +import 'package:querya_desktop/core/util/querya_log.dart'; + import 'local_db.dart'; const _legacyFileName = 'folders.json'; @@ -31,6 +33,7 @@ class FoldersStorage { // Not marked loaded: the next call reads again instead of caching an // empty list for the rest of the session. debugPrint('FoldersStorage.load: $e'); + QueryaLog.instance.error('FoldersStorage', 'load failed', error: e); _folders = []; } return folders; @@ -62,6 +65,7 @@ class FoldersStorage { await file.delete(); } catch (e) { debugPrint('FoldersStorage._migrateFromLegacyIfNeeded: $e'); + QueryaLog.instance.error('FoldersStorage', 'legacy folders.json migration failed', error: e); } } diff --git a/lib/core/util/querya_log.dart b/lib/core/util/querya_log.dart index acb6102e..98c0ed90 100644 --- a/lib/core/util/querya_log.dart +++ b/lib/core/util/querya_log.dart @@ -133,7 +133,17 @@ class QueryaLog { Future _append(String line) async { final dir = _directory!; final bytes = utf8.encode(line); - if (_size > 0 && _size + bytes.length > maxBytes) await _rotate(dir); + if (_size > 0 && _size + bytes.length > maxBytes) { + try { + await _rotate(dir); + } catch (e) { + // A file that cannot be renamed (open in a viewer, wrong permissions) + // must not stop the log: keep writing to the current file and try + // again after another maxBytes. + debugPrint('QueryaLog: could not rotate: $e'); + _size = 0; + } + } await _file(dir, 0).writeAsBytes(bytes, mode: FileMode.append); _size += bytes.length; } diff --git a/lib/features/workspace/generic_sql_workspace.dart b/lib/features/workspace/generic_sql_workspace.dart index 07d99d1b..bc863cd7 100644 --- a/lib/features/workspace/generic_sql_workspace.dart +++ b/lib/features/workspace/generic_sql_workspace.dart @@ -637,6 +637,10 @@ class GenericSqlWorkspaceState extends material.State { } } + // The tab may have been closed while the settings read or the dialog was + // pending. + if (!mounted) return; + // Only now: cancelling the destructive dialog above must keep the edits. if (session.stagingBuffer != null && session.stagingBuffer!.isDirty) { session.stagingBuffer?.dispose(); diff --git a/test/core/util/querya_log_test.dart b/test/core/util/querya_log_test.dart index 92ce2433..1c7867a7 100644 --- a/test/core/util/querya_log_test.dart +++ b/test/core/util/querya_log_test.dart @@ -108,6 +108,21 @@ void main() { expect(await read(QueryaLog.fileName), contains('kept')); }); + test('a rotation that fails does not stop the log', () async { + final log = QueryaLog(maxBytes: 100, maxFiles: 2); + await log.init(root); + // A directory where the rotated file must go makes the rename fail. + await Directory(p.join(root.path, 'querya.1.log')).create(); + await File(p.join(root.path, 'querya.1.log', 'x')).writeAsString('x'); + for (var i = 0; i < 10; i++) { + log.info('t', 'line number $i ${'x' * 20}'); + } + log.info('t', 'the last line'); + await log.flush(); + + expect(await read(QueryaLog.fileName), contains('the last line')); + }); + test('logIgnored writes to the shared log', () async { await QueryaLog.instance.init(root); logIgnored('Somewhere.close', StateError('already closed'));