zui 0.0.5 → 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.
@@ -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) || destination.start_with?("#{entry_path}#{File::SEPARATOR}")
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
- ruby_command=${ZUI_RUBY:-ruby}
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
- ruby_command=${ZUI_RUBY:-ruby}
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>#{VERSION}</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
- File.write(File.join(directory, "zui-bundle.json"), JSON.pretty_generate(
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