Add restart koreader function and ensure FlushSettings event can be delivered to all widgets#2772
Conversation
…elivered to all widgets
| function UIManager:restartKOReader() | ||
| self:quit() | ||
| -- This is just a magic number to indicate the restart request for shell scripts. | ||
| KOREADER_EXIT_CODE = 85 |
There was a problem hiding this comment.
Global variables will introduce performance penalty to LUAJIT. A better approach would be setting a return value variable in UIManager and return it in UIManager:run().
| self:exitOrRestart() | ||
| end, | ||
| } | ||
| self.menu_items.restartKOReader = { |
There was a problem hiding this comment.
naming convention nitpick, restartKOReader should be restart_koreader.
|
|
||
| function ReaderMenu:exitOrRestart(callback) | ||
| self:onTapCloseMenu() | ||
| UIManager:scheduleIn(0.1, function() |
There was a problem hiding this comment.
better use UIManager:nextTick() instead magic number 0.1.
There was a problem hiding this comment.
This is a copy-paste from original logic, I was also curious about the scheduleIn(0.1, ...).
If you also prefer to use nextTick, I am happy to do so.
A similar case happens in touchmenu.lua.
There was a problem hiding this comment.
Yup, I specifically wrote nextTick to replace all the scheduleIn(0.1) hacks. There are still multiple scheduleIn(0.1) hacks that haven't been cleaned up yet.
| -- first send close event to widget | ||
| widget:handleEvent(Event:new("CloseWidget")) | ||
| -- Ensure all the widgets can get onFlushSettings event. | ||
| widget:handleEvent(Event:new("FlushSettings")) |
There was a problem hiding this comment.
Flushing setting on every widget close seems like a very expensive change. What's the reason for doing this?
There was a problem hiding this comment.
If we do not do it here, most of the widgets won't receive onFlushSettings event without suspending device, because they will be closed before "FlushSettings" events have been fired in device.
There was a problem hiding this comment.
Good catch. I was under the impression that it's doing broadcast. handleEvent is probably not too much overhead.
Would it be better to do flush settings first before the close event?
There was a problem hiding this comment.
Reasonable. Though currently we do not have conflicts between CloseWidget and FlushSettings.
There was a problem hiding this comment.
Yes, this change won't fix anything in the current code base. I am more worried about bugs introduced by future developers assuming flushsettings event will always happen before close.
| end | ||
|
|
||
| function BatteryStat:restart() | ||
| assert(self.kv_page ~= nil) |
There was a problem hiding this comment.
I think assert is great for development and debugging, but bad for production run. If an error is recoverable, we should not crash the reader. Can we use something similar to dbg:guard to turn this and other asserts off in non-debug mode?
There was a problem hiding this comment.
I think the answer is something like a logger.pcall (or logger.assert or util.assert whatever which uses pcall in the background) because even in debug mode I just exiting may not be the most helpful. Especially if you want to get some debugging output from a less technically inclined user.
On the other hand that might get complicated because then you'd be implementing all kinds of busted-like stuff (is_same, is_true, etc.).
There was a problem hiding this comment.
We can print more context about the assertion before exit to help with the debug, but I think we should exit immediately after the print. Fail loudly will force developer to not ignore the bug.
Usually the assert should be good enough because it points out which line it's failing.
There was a problem hiding this comment.
It's indeed a culture of Google :). And in MS, because of the heritage from client software development, assert is usually disabled in production. But I still find the code quality in Google is much higher than in MS.
Personally, I really like this culture, e.g. no error is acceptable, even it's recoverable.
An unexpected situation means something is wrong: it may be recoverable, but the side effect is a more serious result.
Maybe I can add a dassert() function which triggers only when dbg is enabled.
There was a problem hiding this comment.
C++ and C can achieve this easily with macro system. Unfortunately, Lua doesn't have macro. So I wrote dbg.guard to achieve a similar effect. You can use it to enforce assert in debug mode (see UIManager), in non-debug mode, it will be optimized to a no-op.
There was a problem hiding this comment.
Yes, but I found it a little bit unnatural. Comparing the following two implementations,
function A:f(p1, p2)
end
dbg:guard(A, "f", function(self, p1, p2)
assert(p1 > 0)
end)function A:f(p1, p2)
dbg:dassert(p1 > 0)
endThe second one seems much cleaner, and guard() can only check input parameters, but dassert() can do almost everything.
There was a problem hiding this comment.
Yes, here is the tradeoff, dbg:guard will get optimized to nothing in non-debug mode. But dbg:dassert will still introduce runtime penalties because the boolean statements are still evaluated every time before getting passed to dassert. Keep in mind that LUAJIT really doesn't like branching ;)
Another issue with dassert is it will still crash the program if the boolean statement has a bug. For example, when p1 == nil.
In languages like C++/C, you can define dassert as a macro and have the compiler optimize it to nothing at compile time. Unfortunately, Lua doesn't have macro support.
So yes, there are reasons for why it looks weird :)
If you care about performance and safety, it's better to reimplement all the busted like helper methods like @Frenzie mentioned. i.e. do the following:
dbg:dassert_is_gt(p1, 0)instead of
dbg:dassert(p1 > 0)Then you can set dbg:dassert_is_gt to a noop (empty function) at module load time. The drawback is you will need to write more code ;)
|
|
||
| ./reader.lua "${args}" >>crash.log 2>&1 | ||
| RESULT=$? | ||
| RESULT=85 |
There was a problem hiding this comment.
Is there a reason that in some scripts it's RESULT and in others RETURN_VALUE?
There was a problem hiding this comment.
Because RESULT was here before. Updated.
|
BTW, the patch is failing the shell script formatter check in travis: |
|
I have fixed some of the failures, but others seem strange to me. |
|
The version error should not be a problem (see #2767, unless that's already integrated here) but I have no idea about the others. |
|
@houqp, do you happen to have any ideas about these strange failures? |
|
Not obvious from a quick glance, I will have to run the tests locally to do more debugging, I should be able to have more free time next week. |
|
These four errors trigger without my change. These five errors trigger by widget:handleEvent(Event:new("FlushSettings")). |
Conflicts: frontend/apps/filemanager/filemanager.lua platform/kobo/koreader.sh
|
Good, caught the line which triggers the issue. -- widget:handleEvent("FlushSettings"). So something (ReaderPaging, etc) may do something wrong in onFlushSettings / onSaveSettings. |
|
Added comments in UIManager.lua: widget:handleEvent(Event:new("FlushSettings")) will not take effect to ReaderUI. |
| if SetDefaults.settings_changed then | ||
| UIManager:show(ConfirmBox:new{ | ||
| text = _("You have unsaved default settings. Save them now?\nTap \"Cancel\" to return to KOReader."), | ||
| ok_text = _("Yes"), |
There was a problem hiding this comment.
There was a problem hiding this comment.
Done.
I do believe it's a very good suggestion to be more clear about what will happen once a button is clicked.
| table.insert(kv_pairs, {self.dump_file, ""}) | ||
| UIManager:show(KeyValuePage:new{ | ||
| table.insert(kv_pairs, "----------") | ||
| table.insert(kv_pairs, {_("Should you like to reset the data,"), "", |
There was a problem hiding this comment.
Should like is a rather formal way of saying would like and possibly mostly British. I'd stick with "If you want to reset the data" or "If you would like to reset the data".
| end) | ||
|
|
||
| it("should scroll withtout crash backward on the first page", function() | ||
| it("should scroll without crash backward on the first page", function() |
There was a problem hiding this comment.
If you're correcting these things anyway it should be something more like should scroll backward on the first page without crashing ;-)
| end) | ||
|
|
||
| it("should scroll withtout crash forward on the last page", function() | ||
| it("should scroll without crash forward on the last page", function() |
| SetDefaults:saveSettings() | ||
| self:exitOrRestart(callback) | ||
| end, | ||
| cancel_text = _("No"), |
|
Sorry for the delay, I have been really busy for the last few weeks. I will help take a look into the crengine issue as soon as possible. It's good that those bugs are exposed by this change and we should fix the root cause. I think it's better to avoid hardcoding app name(ReaderUI) into the main UI loop. |
|
Besides the CRE issue, I think some |
Yes! If you found any inconsistent use of |
|
Are you OK with the latest change? |
|
Since this PR touches multiple critical code paths, I suggest we let it sit here for one more week for more testing. I still want to get to the bottom of those TODOs. |
|
Sorry, plan got delayed a little bit. I am testing this tomorrow. |
|
Sorry again, I got side tracked by the nightly build issue tonight :( |
|
:) |
|
update: I am debugging the failing readerlink test locally right now. |
|
@Hzj-jie can you take a look at https://github.com/Hzj-jie/koreader/pull/1 when you have time? |
|
The others look good: the original issue looks silly: we have not tested something we expected to be covered. But I cannot quite understand the change to readerlink tests. I think the UIManager should have zero effect here. |
uimanager: avoid stack check workaround at close
|
@Hzj-jie all the broken tests are caused by the same issue :P Prior to your patch, book settings are not flushed in many of the tests. Once we started to do more book setting flushes, tests start to affect each other and the assumptions in some of the tests doesn't hold anymore. Can you squash and rebase to the latest master so we can make sure everything will work after a squash merge? |
|
It looks like I misunderstood the busted: I thought preparing an entire new environment for each test casr should be covered by testing framework. But busted does not have this functionality. |
|
Nice work 👍 Busted does support patching environments, the problem is we persist states (book settings) to disk in tests and the states are shared between tests. So to create a new environment for each test, we need to mock out the docssetting module in tests to prevent it from reading settings from disk and flushing settings to disk. |
No description provided.