Skip to content

Commit dc5e7b2

Browse files
committed
kotasync: add command line script + rules to build an AppImage
1 parent 324b3d2 commit dc5e7b2

File tree

9 files changed

+359
-2
lines changed

9 files changed

+359
-2
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ $(CMAKE_DIR)/meson_%.ini: $(KOR_BASE)/Makefile.defs | $(CMAKE_DIR)/
8080
$(call write_file,$@,$(meson_$*))
8181

8282
# Forward unknown targets to the CMake build system.
83-
LEFTOVERS = $(filter-out $(PHONY) $(SOUND),$(MAKECMDGOALS))
83+
LEFTOVERS = $(filter-out $(PHONY) $(SOUND),$(MAKECMDGOALS) $(NINJA_GOALS))
8484
.PHONY: $(LEFTOVERS)
8585
$(BASE_PREFIX)all $(LEFTOVERS): skeleton $(BUILD_ENTRYPOINT)
8686
$(and $(DRY_RUN),$(wildcard $(BUILD_ENTRYPOINT)),+)cd $(CMAKE_DIR) && $(strip $(NINJA) $(NINJAFLAGS) $(patsubst $(BASE_PREFIX)all,all,$@))

Makefile.defs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,7 @@ set(MESON_TOOLCHAINS --native-file=$(abspath $(MESON_HOST_TOOLCHAIN)) $(if $(fil
976976
set(MESON_FILE_ARG $(if $(filter-out $(MESON_HOST_TOOLCHAIN),$(MESON_CROSS_TOOLCHAIN)),--cross-file,--native-file))
977977

978978
# Miscellaneous.
979+
set(KOTASYNC $(KOTASYNC))
979980
set(MONOLIBTIC $(MONOLIBTIC))
980981
set(USE_LJ_WPACLIENT $(USE_LJ_WPACLIENT))
981982
set(USE_SDL $(SDL))

kotasync/AppRun

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/sh
2+
3+
if [ -z "${APPDIR}" ]; then
4+
APPDIR="$(dirname "$(realpath "$0")")"
5+
fi
6+
7+
export LUA_PATH="${APPDIR}/usr/share/lua/?.lua;${APPDIR}/usr/share/lua/?/init.lua"
8+
export LUA_CPATH="${APPDIR}/usr/share/lua/?.so"
9+
export KOTASYNC_USE_XZ_LIB=1
10+
11+
exec "${APPDIR}/usr/bin/luajit" -l kotasync kotasync "$@"
12+
13+
# vim: sw=4

kotasync/Makefile

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
KODEBUG ?=
2+
KOR_BASE ?= ..
3+
4+
APPIMAGE = 1
5+
KOTASYNC = 1
6+
VERSION = 1.0.0
7+
8+
include $(KOR_BASE)/Makefile.defs
9+
10+
APPDIR = $(OUTPUT_DIR)/AppDir
11+
12+
LINUXDEPLOY = linuxdeploy-$(APPIMAGE_ARCH).AppImage
13+
LINUXDEPLOY_URL = https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/$(LINUXDEPLOY)
14+
15+
NINJA_GOALS = dkjson\ koreader-lfs\ luasec\ xxhash\ xz\ zstd
16+
17+
all: appimage
18+
19+
clean: base-clean
20+
21+
define LUA_FILES
22+
23+
common/dkjson.lua
24+
common/ltn12.lua
25+
common/mime.lua
26+
common/mime/mcore.so
27+
common/socket.lua
28+
common/socket/ftp.lua
29+
common/socket/headers.lua
30+
common/socket/http.lua
31+
common/socket/score.so
32+
common/socket/smtp.lua
33+
common/socket/tp.lua
34+
common/socket/url.lua
35+
common/ssl.lua
36+
common/ssl.so
37+
common/ssl/https.lua
38+
39+
ffi/downloader.lua
40+
ffi/hashoir.lua
41+
ffi/kotasync.lua
42+
ffi/loadlib.lua
43+
ffi/posix_h.lua
44+
ffi/posix_types_64b_h.lua
45+
ffi/posix_types_def_h.lua
46+
ffi/posix_types_x64_h.lua
47+
ffi/posix_types_x86_h.lua
48+
ffi/util.lua
49+
ffi/xxhash_h.lua
50+
ffi/xz_h.lua
51+
ffi/zstd.lua
52+
ffi/zstd_h.lua
53+
54+
kotasync.lua
55+
56+
libs/libkoreader-lfs.so
57+
58+
endef
59+
60+
define make_appimage
61+
LINUXDEPLOY_OUTPUT_VERSION='$(VERSION)'
62+
./$(LINUXDEPLOY) --appimage-extract-and-run
63+
--appdir $(APPDIR)
64+
--custom-apprun AppRun
65+
--desktop-file kotasync.desktop
66+
--executable $(OUTPUT_DIR)/luajit
67+
--icon-file kotasync.png
68+
--library $(OUTPUT_DIR)/libs/libcrypto.so.[0-9][0-9]
69+
--library $(OUTPUT_DIR)/libs/liblzma.so.[0-9]
70+
--library $(OUTPUT_DIR)/libs/libssl.so.[0-9][0-9]
71+
--library $(OUTPUT_DIR)/libs/libxxhash.so.[0-9]
72+
--library $(OUTPUT_DIR)/libs/libzstd.so.[0-9]
73+
--library $(OUTPUT_DIR)/libs/libzstd.so.[0-9]
74+
--output appimage
75+
endef
76+
77+
define newline
78+
79+
80+
endef
81+
82+
$(LINUXDEPLOY):
83+
$(CURL) $(LINUXDEPLOY_URL)
84+
chmod a+x ./$(LINUXDEPLOY)
85+
86+
appdir: $(NINJA_GOALS)
87+
rm -rf $(APPDIR)
88+
$(foreach f,$(LUA_FILES), install -Dv $(wildcard $f $(OUTPUT_DIR)/$f) $(APPDIR)/usr/share/lua/$(f:common/%=%)$(newline))
89+
chrpath -c -r '$$ORIGIN/../../../lib' $(APPDIR)/usr/share/lua/*.so
90+
chrpath -c -r '$$ORIGIN/../../lib' $(APPDIR)/usr/share/lua/*.so
91+
92+
appimage: appdir $(LINUXDEPLOY)
93+
$(strip $(make_appimage))
94+
95+
PHONY = all appdir appimage clean
96+
SOUND = $(LINUXDEPLOY)
97+
98+
.NOTPARALLEL:
99+
.PHONY: $(PHONY)
100+
101+
include $(KOR_BASE)/Makefile

kotasync/kotasync.desktop

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[Desktop Entry]
2+
Version = 1.5
3+
Type = Application
4+
NoDisplay = true
5+
Name = kotasync
6+
Icon = kotasync
7+
Exec = kotasync
8+
Categories = Development

kotasync/kotasync.lua

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
#!./luajit
2+
3+
local lfs
4+
local util
5+
local kotasync
6+
7+
local function naturalsize(size)
8+
local chunk, unit = 1, 'B '
9+
if size >= 1000*1000*1000 then
10+
chunk, unit = 1000*1000*1000, 'GB'
11+
elseif size >= 1000*1000 then
12+
chunk, unit = 1000*1000, 'MB'
13+
elseif size >= 1000 then
14+
chunk, unit = 1000, 'KB'
15+
end
16+
local fmt = chunk > 1 and "%.1f" or "%u"
17+
return string.format(fmt.." %s", size / chunk, unit)
18+
end
19+
20+
local function make(tar_xz_path, kotasync_path, tar_xz_manifest, older_tar_xz_or_kotasync_path)
21+
local tar_xz = kotasync.TarXz:new():open(tar_xz_path, tar_xz_manifest)
22+
if older_tar_xz_or_kotasync_path then
23+
tar_xz:reorder(older_tar_xz_or_kotasync_path)
24+
end
25+
local files = {}
26+
local manifest_by_path = tar_xz.by_path
27+
if tar_xz_manifest then
28+
manifest_by_path = {}
29+
for __, f in ipairs(tar_xz.manifest) do
30+
assert(not manifest_by_path[f])
31+
manifest_by_path[f] = true
32+
end
33+
end
34+
for e in tar_xz:each() do
35+
-- Ignore directories.
36+
if e.size ~= 0 and manifest_by_path[e.path] then
37+
table.insert(files, e)
38+
end
39+
end
40+
if tar_xz_manifest and #files ~= #tar_xz.manifest then
41+
error("mismatched manifest / archive contents")
42+
end
43+
local manifest = {
44+
filename = tar_xz_path:match("([^/]+)$"),
45+
files = files,
46+
xz_check = tonumber(tar_xz.header_stream_flags.check),
47+
}
48+
tar_xz:close()
49+
if not kotasync_path then
50+
assert(tar_xz_path:match("[.]tar.xz$"))
51+
kotasync_path = tar_xz_path:sub(1, -7).."kotasync"
52+
end
53+
kotasync.save_manifest(kotasync_path, manifest)
54+
end
55+
56+
local function sync(state_dir, manifest_url, seed)
57+
local updater = kotasync.Updater:new(state_dir)
58+
if seed and lfs.attributes(seed, "mode") == "file" then
59+
-- If the seed is a kotasync file, we need to load it
60+
-- now, as it may get overwritten by `fetch_manifest`.
61+
local by_path = {}
62+
for i, e in ipairs(kotasync.load_manifest(seed).files) do
63+
by_path[e.path] = e
64+
end
65+
seed = by_path
66+
end
67+
updater:fetch_manifest(manifest_url)
68+
local total_files = #updater.manifest.files
69+
local last_update = 0
70+
local delay = false --190000
71+
local update_frequency = 0.2
72+
local stats = updater:prepare_update(seed, function(count)
73+
local new_update = util.getTimestamp()
74+
if count ~= total_files and new_update - last_update < update_frequency then
75+
return true
76+
end
77+
last_update = new_update
78+
io.stderr:write(string.format("\ranalyzing: %4u/%4u", count, total_files))
79+
if delay then
80+
util.usleep(delay)
81+
end
82+
return true
83+
end)
84+
io.stderr:write(string.format("\r%99s\r", ""))
85+
assert(total_files == stats.total_files)
86+
if stats.missing_files == 0 then
87+
print('nothing to update!')
88+
return
89+
end
90+
print(string.format("missing : %u/%u files", stats.missing_files, total_files))
91+
print(string.format("reusing : %7s (%10u)", naturalsize(stats.reused_size), stats.reused_size))
92+
print(string.format("fetching: %7s (%10u)", naturalsize(stats.download_size), stats.download_size))
93+
io.stdout:flush()
94+
local pbar_indicators = {" ", "", "", "", "", "", "", "", ""}
95+
local pbar_size = 16
96+
local pbar_chunk = (stats.download_size + pbar_size - 1) / pbar_size
97+
local prev_path = ""
98+
local old_progress
99+
last_update = 0
100+
local ok, err = pcall(updater.download_update, updater, function(size, count, path)
101+
local new_update = util.getTimestamp()
102+
if size ~= stats.download_size and new_update - last_update < update_frequency then
103+
return true
104+
end
105+
last_update = new_update
106+
local padding = math.max(#prev_path, #path)
107+
local progress = math.floor(size / pbar_chunk)
108+
local pbar = pbar_indicators[#pbar_indicators]:rep(progress)..pbar_indicators[1 + math.floor(size % pbar_chunk * #pbar_indicators / pbar_chunk)]..(" "):rep(pbar_size - progress - 1)
109+
local new_progress = string.format("\rdownloading: %8s %4u/%4u %s %-"..padding.."s", size, count, stats.missing_files, pbar, path)
110+
if new_progress ~= old_progress then
111+
old_progress = new_progress
112+
io.stderr:write(new_progress)
113+
end
114+
prev_path = path
115+
if delay then
116+
util.usleep(delay)
117+
end
118+
return true
119+
end)
120+
io.stderr:write(string.format("\r%99s\r", ""))
121+
if not ok then
122+
io.stderr:write(string.format("ERROR: %s", err))
123+
return 1
124+
end
125+
end
126+
127+
local help = [[
128+
USAGE: kotasync make [-h] [--manifest TAR_XZ_MANIFEST] [--reorder OLDER_TAR_XZ_OR_KOTASYNC_FILE] TAR_XZ_FILE [KOTASYNC_FILE]
129+
kotasync sync [-h] STATE_DIR KOTASYNC_URL [SEED_DIR_OR_KOTASYNC_FILE]
130+
131+
options:
132+
-h, --help show this help message and exit
133+
134+
MAKE:
135+
136+
TAR_XZ_FILE source tar.xz file
137+
KOTASYNC_FILE destination kotasync file
138+
139+
-m, --manifest TAR_XZ_MANIFEST
140+
archive entry to use as base for manifest
141+
142+
-r, --reorder OLDER_TAR_XZ_OR_KOTASYNC_FILE
143+
will repack the new tar.xz with this order:
144+
┌────────────────────┬──────────────────┬─────────────┐
145+
│ new/modified files │ unmodified files │ folders │
146+
│ (new order) │ (old order) │ (new order) │
147+
└────────────────────┴──────────────────┴─────────────┘
148+
SYNC:
149+
150+
STATE_DIR destination for the kotasync and update files
151+
KOTASYNC_URL URL of kotasync file
152+
SEED_DIR_OR_KOTASYNC_FILE
153+
optional seed directory / kotasync file
154+
]]
155+
156+
local function main()
157+
local command
158+
local options = {}
159+
local arguments = {}
160+
while #arg > 0 do
161+
local a = table.remove(arg, 1)
162+
-- print(i, a)
163+
if a:match("^-(.+)$") then
164+
-- print('option', a)
165+
if a == "-h" or a == "--help" then
166+
io.stdout:write(help)
167+
return
168+
elseif command == "make" and (a == "-m" or a == "--manifest") then
169+
if #arg == 0 then
170+
io.stderr:write(string.format("ERROR: option --manifest: expected one argument\n"))
171+
return 2
172+
end
173+
options.manifest = table.remove(arg, 1)
174+
elseif command == "make" and (a == "-r" or a == "--reorder") then
175+
if #arg == 0 then
176+
io.stderr:write(string.format("ERROR: option --reorder: expected one argument\n"))
177+
return 2
178+
end
179+
options.reorder = table.remove(arg, 1)
180+
else
181+
io.stderr:write(string.format("ERROR: unrecognized option: %s\n", a))
182+
return 2
183+
end
184+
elseif command then
185+
table.insert(arguments, a)
186+
else
187+
command = a
188+
end
189+
end
190+
local fn
191+
if command == "make" then
192+
if #arguments < 1 then
193+
io.stderr:write("ERROR: not enough arguments\n")
194+
return 2
195+
end
196+
if #arguments > 2 then
197+
io.stderr:write("ERROR: too many arguments\n")
198+
return 2
199+
end
200+
fn = function() make(arguments[1], arguments[2], options.manifest, options.reorder) end
201+
elseif command == "sync" then
202+
if #arguments < 2 then
203+
io.stderr:write("ERROR: not enough arguments\n")
204+
return 2
205+
end
206+
if #arguments > 3 then
207+
io.stderr:write("ERROR: too many arguments\n")
208+
return 2
209+
end
210+
fn = function() sync(arguments[1], arguments[2], arguments[3]) end
211+
elseif not command then
212+
io.stderr:write(help)
213+
return 2
214+
else
215+
io.stderr:write(string.format("ERROR: unrecognized command: %s\n", command))
216+
return 2
217+
end
218+
require("ffi/loadlib")
219+
lfs = require("libs/libkoreader-lfs")
220+
util = require("ffi/util")
221+
kotasync = require("ffi/kotasync")
222+
local ok, err = xpcall(fn, debug.traceback)
223+
if not ok then
224+
io.stderr:write(string.format("ERROR: %s\n", err))
225+
return 3
226+
end
227+
end
228+
229+
os.exit(main())

kotasync/kotasync.png

340 Bytes
Loading

thirdparty/cmake_modules/koreader_thirdparty_libs.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ else()
167167
set(LUAJIT_LIB)
168168
endif()
169169
get_target_property(LUAJIT_INC luajit::luajit INTERFACE_INCLUDE_DIRECTORIES)
170+
declare_dependency(luajit::luajit_static INCLUDES luajit-2.1 STATIC luajit-5.1 LIBRARIES dl m)
170171

171172
# luasec
172173
if(MONOLIBTIC)

thirdparty/xz/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ list(JOIN FILTERS $<SEMICOLON> FILTERS)
1313

1414
list(APPEND CMAKE_ARGS
1515
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
16-
-DBUILD_SHARED_LIBS=FALSE
16+
-DBUILD_SHARED_LIBS=$<IF:$<BOOL:${KOTASYNC}>,TRUE,FALSE>
1717
# Project options.
1818
-DXZ_DOC=FALSE
1919
# We can't disable the encoder completely,
@@ -42,6 +42,10 @@ list(APPEND BUILD_CMD COMMAND ninja)
4242

4343
list(APPEND INSTALL_CMD COMMAND ${CMAKE_COMMAND} --install .)
4444

45+
if(KOTASYNC)
46+
append_shared_lib_install_commands(INSTALL_CMD lzma VERSION 5)
47+
endif()
48+
4549
external_project(
4650
DOWNLOAD URL cf5e1feb023d22c6bdaa30e84ef3abe3
4751
https://github.com/tukaani-project/xz/releases/download/v5.8.1/xz-5.8.1.tar.xz

0 commit comments

Comments
 (0)