Skip to content

Add restart koreader function and ensure FlushSettings event can be delivered to all widgets#2772

Merged
houqp merged 29 commits into
koreader:masterfrom
Hzj-jie:master
May 16, 2017
Merged

Add restart koreader function and ensure FlushSettings event can be delivered to all widgets#2772
houqp merged 29 commits into
koreader:masterfrom
Hzj-jie:master

Conversation

@Hzj-jie

@Hzj-jie Hzj-jie commented Apr 16, 2017

Copy link
Copy Markdown
Contributor

No description provided.

Comment thread frontend/ui/uimanager.lua Outdated
function UIManager:restartKOReader()
self:quit()
-- This is just a magic number to indicate the restart request for shell scripts.
KOREADER_EXIT_CODE = 85

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

self:exitOrRestart()
end,
}
self.menu_items.restartKOReader = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming convention nitpick, restartKOReader should be restart_koreader.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


function ReaderMenu:exitOrRestart(callback)
self:onTapCloseMenu()
UIManager:scheduleIn(0.1, function()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better use UIManager:nextTick() instead magic number 0.1.

@Hzj-jie Hzj-jie Apr 17, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread frontend/ui/uimanager.lua
-- first send close event to widget
widget:handleEvent(Event:new("CloseWidget"))
-- Ensure all the widgets can get onFlushSettings event.
widget:handleEvent(Event:new("FlushSettings"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flushing setting on every widget close seems like a very expensive change. What's the reason for doing this?

@Hzj-jie Hzj-jie Apr 17, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reasonable. Though currently we do not have conflicts between CloseWidget and FlushSettings.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread plugins/batterystat.koplugin/main.lua Outdated
end

function BatteryStat:restart()
assert(self.kv_page ~= nil)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@Frenzie Frenzie Apr 16, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, true.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
end

The second one seems much cleaner, and guard() can only check input parameters, but dassert() can do almost everything.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ;)

Comment thread platform/kobo/koreader.sh Outdated

./reader.lua "${args}" >>crash.log 2>&1
RESULT=$?
RESULT=85

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that in some scripts it's RESULT and in others RETURN_VALUE?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because RESULT was here before. Updated.

@houqp

houqp commented Apr 17, 2017

Copy link
Copy Markdown
Member

BTW, the patch is failing the shell script formatter check in travis:

Warning: kodev does not abide by coding style
333,334c333
<         while [ $RESULT -eq 85 ]
<         do
---
>         while [ $RESULT -eq 85 ]; do

@Hzj-jie

Hzj-jie commented Apr 17, 2017

Copy link
Copy Markdown
Contributor Author

I have fixed some of the failures, but others seem strange to me.

@Frenzie

Frenzie commented Apr 18, 2017

Copy link
Copy Markdown
Member

The version error should not be a problem (see #2767, unless that's already integrated here) but I have no idea about the others.

@Hzj-jie

Hzj-jie commented Apr 20, 2017

Copy link
Copy Markdown
Contributor Author

@houqp, do you happen to have any ideas about these strange failures?

@houqp

houqp commented Apr 21, 2017

Copy link
Copy Markdown
Member

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.

@Hzj-jie

Hzj-jie commented Apr 22, 2017

Copy link
Copy Markdown
Contributor Author

These four errors trigger without my change.

Failure → ./spec/front/unit/readerlink_spec.lua @ 14
ReaderLink module should jump to links in epub
./spec/front/unit/readerlink_spec.lua:20: Expected objects to be the same.
Passed in:
(number) 4
Expected:
(number) 36

stack traceback:
	./spec/front/unit/readerlink_spec.lua:20: in function <./spec/front/unit/readerlink_spec.lua:14>


Failure → ./spec/front/unit/readerlink_spec.lua @ 51
ReaderLink module should be able to go back after link jump in epub
./spec/front/unit/readerlink_spec.lua:57: Expected objects to be the same.
Passed in:
(number) 4
Expected:
(number) 36

stack traceback:
	./spec/front/unit/readerlink_spec.lua:57: in function <./spec/front/unit/readerlink_spec.lua:51>


Error → ./spec/front/unit/readerpaging_spec.lua @ 74
Readerpaging module Scroll mode should scroll withtout crash backward on the first page
frontend/apps/reader/modules/readerpaging.lua:15: attempt to index local 'page_state' (a nil value)

stack traceback:
	frontend/apps/reader/modules/readerpaging.lua:15: in function 'copyPageState'
	frontend/apps/reader/modules/readerpaging.lua:685: in function 'onScrollPanRel'
	./spec/front/unit/readerpaging_spec.lua:79: in function <./spec/front/unit/readerpaging_spec.lua:74>


Error → ./spec/front/unit/readerpaging_spec.lua @ 82
Readerpaging module Scroll mode should scroll withtout crash forward on the last page
frontend/apps/reader/modules/readerpaging.lua:15: attempt to index local 'page_state' (a nil value)

stack traceback:
	frontend/apps/reader/modules/readerpaging.lua:15: in function 'copyPageState'
	frontend/apps/reader/modules/readerpaging.lua:681: in function 'onScrollPanRel'
	./spec/front/unit/readerpaging_spec.lua:89: in function <./spec/front/unit/readerpaging_spec.lua:82>

These five errors trigger by widget:handleEvent(Event:new("FlushSettings")).

Failure → ./spec/front/unit/readerpaging_spec.lua @ 54
Readerpaging module Scroll mode should emit EndOfBook event at the end
./spec/front/unit/readerpaging_spec.lua:69: Expected to be truthy, but value was:
(boolean) false

stack traceback:
	./spec/front/unit/readerpaging_spec.lua:69: in function <./spec/front/unit/readerpaging_spec.lua:54>


Failure → ./spec/front/unit/readertoc_spec.lua @ 78
Readertoc module collasible TOC should collapse the secondary toc nodes by default
./spec/front/unit/readertoc_spec.lua:80: Expected objects to be the same.
Passed in:
(number) 13
Expected:
(number) 7

stack traceback:
	./spec/front/unit/readertoc_spec.lua:80: in function <./spec/front/unit/readertoc_spec.lua:78>


Failure → ./spec/front/unit/readertoc_spec.lua @ 82
Readertoc module collasible TOC should not expand toc nodes that have no child nodes
./spec/front/unit/readertoc_spec.lua:84: Expected objects to be the same.
Passed in:
(number) 13
Expected:
(number) 7

stack traceback:
	./spec/front/unit/readertoc_spec.lua:84: in function <./spec/front/unit/readertoc_spec.lua:82>


Error → ./spec/front/unit/readerhighlight_spec.lua @ 239
Readerhighlight module highlight for PDF documents in scroll mode for scanned page without text layer should highlight text
frontend/document/koptinterface.lua:750: attempt to get length of local 'boxes' (a nil value)

stack traceback:
	frontend/document/koptinterface.lua:750: in function 'getWordFromBoxes'
	frontend/document/koptinterface.lua:977: in function 'getTextFromPositions'
	frontend/apps/reader/modules/readerhighlight.lua:280: in function 'onHoldPan'
	./spec/front/unit/readerhighlight_spec.lua:27: in function 'highlight_text'
	./spec/front/unit/readerhighlight_spec.lua:240: in function <./spec/front/unit/readerhighlight_spec.lua:239>


Error → ./spec/front/unit/readerhighlight_spec.lua @ 243
Readerhighlight module highlight for PDF documents in scroll mode for scanned page without text layer should response on tap gesture
frontend/document/koptinterface.lua:750: attempt to get length of local 'boxes' (a nil value)

stack traceback:
	frontend/document/koptinterface.lua:750: in function 'getWordFromBoxes'
	frontend/document/koptinterface.lua:977: in function 'getTextFromPositions'
	frontend/apps/reader/modules/readerhighlight.lua:280: in function 'onHoldPan'
	./spec/front/unit/readerhighlight_spec.lua:51: in function 'tap_highlight_text'
	./spec/front/unit/readerhighlight_spec.lua:244: in function <./spec/front/unit/readerhighlight_spec.lua:243>

@Hzj-jie

Hzj-jie commented Apr 30, 2017

Copy link
Copy Markdown
Contributor Author

Good, caught the line which triggers the issue. -- widget:handleEvent("FlushSettings"). So something (ReaderPaging, etc) may do something wrong in onFlushSettings / onSaveSettings.

@Hzj-jie

Hzj-jie commented May 1, 2017

Copy link
Copy Markdown
Contributor Author

Added comments in UIManager.lua: widget:handleEvent(Event:new("FlushSettings")) will not take effect to ReaderUI.
-- Once the ReaderUI is closed, UIManager:quit() and FlushSettings will eventually be called.
-- So we do not bother FlushSettings again.
-- Meanwhile, calling FlushSettings on ReaderUI also trigger several test failures
-- (https://goo.gl/Rkg6k8). Some initial investigations show the in CREngine
-- ldomDocument::createXPointer() (https://goo.gl/vz6zrc) may impact its internal states.

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"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, 1c25d0f

So the dialog should look like this:

Cancel Don't save Save

@Hzj-jie Hzj-jie May 1, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
I do believe it's a very good suggestion to be more clear about what will happen once a button is clicked.

Comment thread plugins/batterystat.koplugin/main.lua Outdated
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,"), "",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment thread spec/unit/readerpaging_spec.lua Outdated
end)

it("should scroll withtout crash backward on the first page", function()
it("should scroll without crash backward on the first page", function()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're correcting these things anyway it should be something more like should scroll backward on the first page without crashing ;-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment thread spec/unit/readerpaging_spec.lua Outdated
end)

it("should scroll withtout crash forward on the last page", function()
it("should scroll without crash forward on the last page", function()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

SetDefaults:saveSettings()
self:exitOrRestart(callback)
end,
cancel_text = _("No"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't save

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@houqp

houqp commented May 1, 2017

Copy link
Copy Markdown
Member

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.

@Hzj-jie

Hzj-jie commented May 2, 2017

Copy link
Copy Markdown
Contributor Author

Besides the CRE issue, I think some on* methods should be renamed to remove on, they are conflict with EventListener. IMO, in principle, on* should only be called by EventListener.

@houqp

houqp commented May 2, 2017

Copy link
Copy Markdown
Member

Besides the CRE issue, I think some on* methods should be renamed to remove on, they are conflict with EventListener. IMO, in principle, on* should only be called by EventListener.

Yes! If you found any inconsistent use of on prefix, feel free to correct them :)

@Hzj-jie

Hzj-jie commented May 2, 2017

Copy link
Copy Markdown
Contributor Author

Are you OK with the latest change?

@houqp

houqp commented May 2, 2017

Copy link
Copy Markdown
Member

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.

@houqp

houqp commented May 7, 2017

Copy link
Copy Markdown
Member

Sorry, plan got delayed a little bit. I am testing this tomorrow.

@houqp

houqp commented May 8, 2017

Copy link
Copy Markdown
Member

Sorry again, I got side tracked by the nightly build issue tonight :(

@Hzj-jie

Hzj-jie commented May 10, 2017

Copy link
Copy Markdown
Contributor Author

:)

@houqp

houqp commented May 10, 2017

Copy link
Copy Markdown
Member

update: I am debugging the failing readerlink test locally right now.

@houqp

houqp commented May 11, 2017

Copy link
Copy Markdown
Member

@Hzj-jie can you take a look at https://github.com/Hzj-jie/koreader/pull/1 when you have time?

@Hzj-jie

Hzj-jie commented May 12, 2017

Copy link
Copy Markdown
Contributor Author

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.

Hzj-jie and others added 2 commits May 12, 2017 08:31
uimanager: avoid stack check workaround at close
@houqp

houqp commented May 14, 2017

Copy link
Copy Markdown
Member

@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?

@Hzj-jie

Hzj-jie commented May 15, 2017

Copy link
Copy Markdown
Contributor Author

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.

@houqp houqp merged commit 30378eb into koreader:master May 16, 2017
@houqp

houqp commented May 16, 2017

Copy link
Copy Markdown
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants