zui 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ControlNode.qml +2 -909
- data/Desktop.qml +3 -0
- data/README.md +383 -66
- data/Service.qml +14 -2
- data/lib/zui/cli.rb +34 -2
- data/lib/zui/dist_config.rb +180 -0
- data/lib/zui/dist_packager.rb +361 -0
- data/lib/zui/distribution.rb +74 -12
- data/lib/zui/generator.rb +38 -0
- data/lib/zui/tree_shaker.rb +527 -0
- data/lib/zui.rb +4 -1
- metadata +4 -1
data/lib/zui/distribution.rb
CHANGED
|
@@ -2,20 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
require "fileutils"
|
|
4
4
|
require "json"
|
|
5
|
+
require "rbconfig"
|
|
5
6
|
|
|
6
7
|
module Zui
|
|
7
8
|
class Distribution
|
|
8
|
-
attr_reader :platform
|
|
9
|
+
attr_reader :platform, :tree_shake_report
|
|
9
10
|
|
|
10
|
-
def initialize(client: nil, platform: Platform.current, framework_root: FRAMEWORK_ROOT
|
|
11
|
+
def initialize(client: nil, platform: Platform.current, framework_root: FRAMEWORK_ROOT,
|
|
12
|
+
ruby: RbConfig.ruby, tree_shake: true, release_config: nil)
|
|
11
13
|
@platform = platform.assert_supported!
|
|
12
14
|
@client = client || Client.new(platform: @platform)
|
|
13
15
|
@framework_root = framework_root
|
|
16
|
+
@ruby = File.expand_path(ruby)
|
|
17
|
+
@tree_shake = tree_shake == true
|
|
18
|
+
@tree_shake_report = nil
|
|
19
|
+
@release_config = release_config
|
|
14
20
|
end
|
|
15
21
|
|
|
16
22
|
def bundle(source, name: nil, destination: nil)
|
|
17
23
|
created = false
|
|
18
24
|
project = File.expand_path(source)
|
|
25
|
+
@project = project
|
|
19
26
|
raise ArgumentError, "project directory not found: #{project}" unless File.directory?(project)
|
|
20
27
|
raise ArgumentError, "main.rb not found: #{project}" unless File.file?(File.join(project, "main.rb"))
|
|
21
28
|
unless @client.configured?
|
|
@@ -46,6 +53,7 @@ module Zui
|
|
|
46
53
|
install_application(project, File.join(destination, "app"))
|
|
47
54
|
install_runtime(File.join(destination, "runtime"))
|
|
48
55
|
@client.copy_to(File.join(destination, "runtime", "native"))
|
|
56
|
+
shake_bundle(project, File.join(destination, "runtime"))
|
|
49
57
|
write_linux_launcher(destination, app_name)
|
|
50
58
|
desktop_name = "#{slug(app_name)}.desktop"
|
|
51
59
|
File.write(File.join(destination, "share", "applications", desktop_name), <<~DESKTOP)
|
|
@@ -67,9 +75,11 @@ module Zui
|
|
|
67
75
|
install_application(project, File.join(resources, "app"))
|
|
68
76
|
install_runtime(File.join(resources, "runtime"))
|
|
69
77
|
@client.copy_to(File.join(resources, "runtime", "native"))
|
|
78
|
+
shake_bundle(project, File.join(resources, "runtime"))
|
|
79
|
+
icon_name = install_macos_release_icon(resources)
|
|
70
80
|
File.write(File.join(macos, "run"), macos_launcher(app_name))
|
|
71
81
|
FileUtils.chmod(0o755, File.join(macos, "run"))
|
|
72
|
-
File.write(File.join(contents, "Info.plist"), info_plist(app_name))
|
|
82
|
+
File.write(File.join(contents, "Info.plist"), info_plist(app_name, icon_name:))
|
|
73
83
|
write_manifest(resources, app_name)
|
|
74
84
|
end
|
|
75
85
|
|
|
@@ -79,6 +89,8 @@ module Zui
|
|
|
79
89
|
install_application(project, File.join(destination, "app"))
|
|
80
90
|
install_runtime(File.join(destination, "runtime"))
|
|
81
91
|
@client.copy_to(File.join(destination, "runtime", "native"))
|
|
92
|
+
shake_bundle(project, File.join(destination, "runtime"))
|
|
93
|
+
install_windows_release_icon(destination)
|
|
82
94
|
File.write(File.join(destination, "run.rb"), windows_ruby_launcher(app_name))
|
|
83
95
|
File.write(File.join(destination, "run.cmd"), windows_command_launcher)
|
|
84
96
|
write_manifest(destination, app_name)
|
|
@@ -87,7 +99,8 @@ module Zui
|
|
|
87
99
|
def install_application(source, destination)
|
|
88
100
|
entries = Dir.children(source).reject do |entry|
|
|
89
101
|
entry_path = File.join(source, entry)
|
|
90
|
-
%w[.git dist].include?(entry) ||
|
|
102
|
+
%w[.git dist config.rb].include?(entry) ||
|
|
103
|
+
destination.start_with?("#{entry_path}#{File::SEPARATOR}")
|
|
91
104
|
end
|
|
92
105
|
FileUtils.cp_r(entries.map { |entry| File.join(source, entry) }, destination) unless entries.empty?
|
|
93
106
|
end
|
|
@@ -110,7 +123,7 @@ module Zui
|
|
|
110
123
|
bundle_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
111
124
|
native_dir="$bundle_dir/runtime/native"
|
|
112
125
|
#{posix_client_environment}
|
|
113
|
-
|
|
126
|
+
#{posix_ruby_command}
|
|
114
127
|
exec "$native_dir/#{@client.executable_relative_path}" \
|
|
115
128
|
--qml-root "$bundle_dir/runtime/qml" \
|
|
116
129
|
--project "$bundle_dir/app" \
|
|
@@ -130,7 +143,7 @@ module Zui
|
|
|
130
143
|
resources="$contents/Resources"
|
|
131
144
|
native_dir="$resources/runtime/native"
|
|
132
145
|
#{posix_client_environment}
|
|
133
|
-
|
|
146
|
+
#{posix_ruby_command}
|
|
134
147
|
exec "$native_dir/#{@client.executable_relative_path}" \
|
|
135
148
|
--qml-root "$resources/runtime/qml" \
|
|
136
149
|
--project "$resources/app" \
|
|
@@ -177,8 +190,10 @@ module Zui
|
|
|
177
190
|
CMD
|
|
178
191
|
end
|
|
179
192
|
|
|
180
|
-
def info_plist(app_name)
|
|
181
|
-
identifier = "dev.zui.#{slug(app_name).tr("-", ".")}"
|
|
193
|
+
def info_plist(app_name, icon_name: nil)
|
|
194
|
+
identifier = @release_config&.identifier || "dev.zui.#{slug(app_name).tr("-", ".")}"
|
|
195
|
+
application_version = @release_config&.version || VERSION
|
|
196
|
+
icon_entry = icon_name ? "<key>CFBundleIconFile</key><string>#{xml_escape(icon_name)}</string>" : ""
|
|
182
197
|
<<~PLIST
|
|
183
198
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
184
199
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -187,18 +202,50 @@ module Zui
|
|
|
187
202
|
<key>CFBundleIdentifier</key><string>#{identifier}</string>
|
|
188
203
|
<key>CFBundleName</key><string>#{xml_escape(app_name)}</string>
|
|
189
204
|
<key>CFBundlePackageType</key><string>APPL</string>
|
|
190
|
-
<key>CFBundleShortVersionString</key><string>#{
|
|
205
|
+
<key>CFBundleShortVersionString</key><string>#{xml_escape(application_version)}</string>
|
|
206
|
+
<key>CFBundleVersion</key><string>#{xml_escape(application_version)}</string>
|
|
207
|
+
#{icon_entry}
|
|
191
208
|
<key>NSHighResolutionCapable</key><true/>
|
|
192
209
|
</dict></plist>
|
|
193
210
|
PLIST
|
|
194
211
|
end
|
|
195
212
|
|
|
196
213
|
def write_manifest(directory, app_name)
|
|
197
|
-
|
|
214
|
+
manifest = {
|
|
198
215
|
"format" => 1, "framework" => "zui", "version" => VERSION,
|
|
199
216
|
"platform" => platform.os.to_s, "architecture" => platform.arch.to_s,
|
|
200
|
-
"name" => app_name, "client_version" => @client.manifest.fetch("client_version")
|
|
201
|
-
|
|
217
|
+
"name" => app_name, "client_version" => @client.manifest.fetch("client_version"),
|
|
218
|
+
"tree_shaken" => !@tree_shake_report.nil?
|
|
219
|
+
}
|
|
220
|
+
manifest["tree_shake"] = @tree_shake_report.to_h if @tree_shake_report
|
|
221
|
+
if @release_config
|
|
222
|
+
manifest["identifier"] = @release_config.identifier
|
|
223
|
+
manifest["application_version"] = @release_config.version
|
|
224
|
+
end
|
|
225
|
+
File.write(File.join(directory, "zui-bundle.json"), JSON.pretty_generate(manifest))
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def install_macos_release_icon(resources)
|
|
229
|
+
return nil unless @release_config
|
|
230
|
+
|
|
231
|
+
source = @release_config.icon_path(@project, platform)
|
|
232
|
+
name = "Application.icns"
|
|
233
|
+
FileUtils.cp(source, File.join(resources, name))
|
|
234
|
+
name
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def install_windows_release_icon(destination)
|
|
238
|
+
return unless @release_config
|
|
239
|
+
|
|
240
|
+
FileUtils.cp(@release_config.icon_path(@project, platform), File.join(destination, "app.ico"))
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def shake_bundle(project, runtime)
|
|
244
|
+
return unless @tree_shake
|
|
245
|
+
|
|
246
|
+
@tree_shake_report = TreeShaker.new(
|
|
247
|
+
project:, framework: File.join(runtime, "qml"), native: File.join(runtime, "native"), platform:
|
|
248
|
+
).shake!
|
|
202
249
|
end
|
|
203
250
|
|
|
204
251
|
def default_destination(project, app_name)
|
|
@@ -222,6 +269,21 @@ module Zui
|
|
|
222
269
|
end.join("\n")
|
|
223
270
|
end
|
|
224
271
|
|
|
272
|
+
def posix_ruby_command
|
|
273
|
+
<<~SH.chomp
|
|
274
|
+
ruby_command=${ZUI_RUBY:-}
|
|
275
|
+
if [ -z "$ruby_command" ]; then
|
|
276
|
+
packaged_ruby=#{shell_quote(@ruby)}
|
|
277
|
+
if [ -x "$packaged_ruby" ]; then
|
|
278
|
+
ruby_command=$packaged_ruby
|
|
279
|
+
else
|
|
280
|
+
ruby_command=$(command -v ruby || true)
|
|
281
|
+
[ -n "$ruby_command" ] || ruby_command=ruby
|
|
282
|
+
fi
|
|
283
|
+
fi
|
|
284
|
+
SH
|
|
285
|
+
end
|
|
286
|
+
|
|
225
287
|
def windows_client_environment = @client.environment_entries
|
|
226
288
|
|
|
227
289
|
def windows_environment_builder
|
data/lib/zui/generator.rb
CHANGED
|
@@ -15,6 +15,9 @@ module Zui
|
|
|
15
15
|
FileUtils.mkdir_p(File.join(@path, "components"))
|
|
16
16
|
File.write(File.join(@path, "main.rb"), main_program)
|
|
17
17
|
File.write(File.join(@path, "components", "welcome.rb"), welcome_component)
|
|
18
|
+
File.write(File.join(@path, "config.rb"), distribution_config)
|
|
19
|
+
FileUtils.mkdir_p(File.join(@path, "assets"))
|
|
20
|
+
File.write(File.join(@path, "assets", "README.md"), icon_readme)
|
|
18
21
|
File.write(File.join(@path, "README.md"), readme)
|
|
19
22
|
@path
|
|
20
23
|
rescue StandardError
|
|
@@ -72,14 +75,49 @@ module Zui
|
|
|
72
75
|
zui doctor --fix # once for each Zui version
|
|
73
76
|
zui run main.rb
|
|
74
77
|
zui bundle
|
|
78
|
+
zui bundle --dist # after adding the icons declared in config.rb
|
|
75
79
|
```
|
|
76
80
|
MARKDOWN
|
|
77
81
|
end
|
|
78
82
|
|
|
83
|
+
def distribution_config
|
|
84
|
+
<<~RUBY
|
|
85
|
+
# frozen_string_literal: true
|
|
86
|
+
|
|
87
|
+
Zui::Dist.configure do
|
|
88
|
+
name #{@name.dump}
|
|
89
|
+
identifier #{"com.example.#{slug_name}".dump}
|
|
90
|
+
version "0.1.0"
|
|
91
|
+
publisher "Your Name <you@example.com>"
|
|
92
|
+
description #{"A native #{@name} desktop application.".dump}
|
|
93
|
+
license "Proprietary"
|
|
94
|
+
icon linux: "assets/icon.png",
|
|
95
|
+
macos: "assets/icon.icns",
|
|
96
|
+
windows: "assets/icon.ico"
|
|
97
|
+
categories "Utility"
|
|
98
|
+
end
|
|
99
|
+
RUBY
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def icon_readme
|
|
103
|
+
<<~MARKDOWN
|
|
104
|
+
Add the release icons referenced by `config.rb` here:
|
|
105
|
+
|
|
106
|
+
- `icon.png` for Linux
|
|
107
|
+
- `icon.icns` for macOS
|
|
108
|
+
- `icon.ico` for Windows
|
|
109
|
+
MARKDOWN
|
|
110
|
+
end
|
|
111
|
+
|
|
79
112
|
def constant_name
|
|
80
113
|
value = @name.scan(/[a-z0-9]+/i).map { |part| part[0].upcase + part[1..].to_s }.join
|
|
81
114
|
value = "Application#{value}" if value.match?(/\A\d/)
|
|
82
115
|
value.empty? ? "ZuiApplication" : value
|
|
83
116
|
end
|
|
117
|
+
|
|
118
|
+
def slug_name
|
|
119
|
+
value = @name.downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A-|-\z/, "")
|
|
120
|
+
value.match?(/\A\d/) ? "app-#{value}" : value
|
|
121
|
+
end
|
|
84
122
|
end
|
|
85
123
|
end
|