diff --git a/app_builder/examples/wx_demo/mix.exs b/app_builder/examples/wx_demo/mix.exs index 88ec9fea7..d12373993 100644 --- a/app_builder/examples/wx_demo/mix.exs +++ b/app_builder/examples/wx_demo/mix.exs @@ -38,16 +38,22 @@ defmodule WxDemo.MixProject do name: "WxDemo", url_schemes: ["wxdemo"], document_types: [ - %{ + [ name: "WxDemo", extensions: ["wxdemo"], - macos_role: "Editor" - } + macos: [ + role: "Editor" + ] + ] ], - server: WxDemo, - macos_build_dmg: macos_notarization != nil, - macos_notarization: macos_notarization, - windows_build_installer: true + macos: [ + build_dmg: macos_notarization != nil, + notarization: macos_notarization + ], + windows: [ + server: WxDemo, + build_installer: true + ] ] ] ] diff --git a/app_builder/lib/app_builder.ex b/app_builder/lib/app_builder.ex index 16bc14663..b4aa840f0 100644 --- a/app_builder/lib/app_builder.ex +++ b/app_builder/lib/app_builder.ex @@ -1,25 +1,8 @@ defmodule AppBuilder do def bundle(release) do - os = os() + options = validate_options(release.options[:app]) - allowed_options = [ - :name, - :server, - icon_path: [ - macos: Application.app_dir(:wx, "examples/demo/erlang.png") - ], - url_schemes: [], - document_types: [], - additional_paths: [], - macos_is_agent_app: false, - macos_build_dmg: false, - macos_notarization: nil, - windows_build_installer: true - ] - - options = Keyword.validate!(release.options[:app], allowed_options) - - case os do + case os() do :macos -> AppBuilder.MacOS.bundle(release, options) @@ -34,4 +17,72 @@ defmodule AppBuilder do {:win32, _} -> :windows end end + + defp validate_options(options) do + os = os() + + root_allowed_options = %{ + all: [ + :name, + :icon_path, + url_schemes: [], + document_types: [], + additional_paths: [] + ], + macos: [ + app_type: :regular, + build_dmg: false, + notarization: nil + ], + windows: [ + :server, + build_installer: false + ] + } + + document_type_allowed_options = %{ + all: [ + :name, + :extensions, + :icon_path + ], + macos: [ + :role + ], + windows: [] + } + + options = validate_options(options, root_allowed_options, os) + + Keyword.update!(options, :document_types, fn document_types -> + Enum.map(document_types, fn options -> + validate_options(options, document_type_allowed_options, os) + end) + end) + end + + defp validate_options(options, allowed, os) do + {macos_options, options} = Keyword.pop(options, :macos, []) + {windows_options, options} = Keyword.pop(options, :windows, []) + + options_per_os = %{ + macos: macos_options, + windows: windows_options + } + + options = Keyword.validate!(options, allowed.all) + options_for_os = Map.fetch!(options_per_os, os) + + allowed_without_defaults = + for option <- allowed.all do + case option do + atom when is_atom(atom) -> atom + {atom, _default} when is_atom(atom) -> atom + end + end + + allowed_for_os = allowed_without_defaults ++ Map.fetch!(allowed, os) + os_options = Keyword.validate!(options_for_os, allowed_for_os) + Keyword.merge(options, os_options) + end end diff --git a/app_builder/lib/app_builder/macos.ex b/app_builder/lib/app_builder/macos.ex index 666396fdd..dd87df419 100644 --- a/app_builder/lib/app_builder/macos.ex +++ b/app_builder/lib/app_builder/macos.ex @@ -33,13 +33,15 @@ defmodule AppBuilder.MacOS do launcher_src_path ]) - icon_path = Keyword.fetch!(options, :icon_path) + icon_path = + Keyword.get(options, :icon_path, Application.app_dir(:wx, "examples/demo/erlang.png")) + dest_path = "#{resources_path}/AppIcon.icns" create_icon(icon_path, dest_path) for type <- Keyword.fetch!(options, :document_types) do - if src_path = type[:icon_path] do - dest_path = "#{resources_path}/#{type.name}Icon.icns" + if src_path = Keyword.get(type, :icon_path, icon_path) do + dest_path = "#{resources_path}/#{type[:name]}Icon.icns" create_icon(src_path, dest_path) end end diff --git a/app_builder/lib/app_builder/windows.ex b/app_builder/lib/app_builder/windows.ex index db3396c61..34571faaa 100644 --- a/app_builder/lib/app_builder/windows.ex +++ b/app_builder/lib/app_builder/windows.ex @@ -30,11 +30,15 @@ defmodule AppBuilder.Windows do vcredist_path = ensure_vcredistx64() copy_file(vcredist_path, "#{app_path}/vcredist_x64.exe") - create_icon(options[:icon_path], "#{app_path}/AppIcon.ico") + icon_path = options[:icon_path] + + if icon_path do + create_icon(icon_path, "#{app_path}/AppIcon.ico") + end for type <- Keyword.fetch!(options, :document_types) do - if src_path = type[:icon_path] do - dest_path = "#{app_path}/#{type.name}Icon.ico" + if src_path = Keyword.get(type, :icon_path, icon_path) do + dest_path = "#{app_path}/#{type[:name]}Icon.ico" create_icon(src_path, dest_path) end end diff --git a/app_builder/lib/templates/macos/Info.plist.eex b/app_builder/lib/templates/macos/Info.plist.eex index 7d7d40c1a..c2009f0d3 100644 --- a/app_builder/lib/templates/macos/Info.plist.eex +++ b/app_builder/lib/templates/macos/Info.plist.eex @@ -41,25 +41,25 @@ <%= for type <- types do %> CFBundleTypeName - <%= type.name %> + <%= type[:name] %> CFBundleTypeRole - <%= type.macos_role %> + <%= type[:role] %> CFBundleTypeExtensions - <%= for ext <- type.extensions do %> + <%= for ext <- type[:extensions] do %> <%= ext %> <% end %> <%= if type[:icon_path] do %> CFBundleTypeIconFile - <%= type.name %>Icon + <%= type[:name] %>Icon <% end %> <% end %> <% end %> -<%= if @app_options[:macos_is_agent_app] do %> +<%= if @app_options[:app_type] == :agent do %> LSUIElement <% end %> diff --git a/app_builder/lib/templates/windows/Installer.nsi.eex b/app_builder/lib/templates/windows/Installer.nsi.eex index 6452d6658..30375a471 100644 --- a/app_builder/lib/templates/windows/Installer.nsi.eex +++ b/app_builder/lib/templates/windows/Installer.nsi.eex @@ -23,7 +23,9 @@ RequestExecutionLevel admin ;Pages ;!insertmacro MUI_PAGE_COMPONENTS +<%= if @app_options[:icon_path] do %> !define MUI_ICON "AppIcon.ico" +<% end %> !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES @@ -46,18 +48,22 @@ Section "Install" File /r rel rel File "<%= app_name %>Launcher.vbs" +<%= if @app_options[:icon_path] do %> File "AppIcon.ico" +<% end %> CreateDirectory "$INSTDIR\Logs" WriteUninstaller "$INSTDIR\<%= app_name %>Uninstall.exe" <%= for type <- Keyword.fetch!(@app_options, :document_types) do %> -<%= for ext <- type.extensions do %> - WriteRegStr HKCR ".<%= ext %>" "" "<%= app_name %>.<%= type.name %>" +<%= for ext <- type[:extensions] do %> + WriteRegStr HKCR ".<%= ext %>" "" "<%= app_name %>.<%= type[:name] %>" <% end %> - WriteRegStr HKCR "<%= app_name %>.<%= type.name %>" "" "<%= type.name %>" - WriteRegStr HKCR "<%= app_name %>.<%= type.name %>\DefaultIcon" "" "$INSTDIR\<%= type.name %>Icon.ico" - WriteRegStr HKCR "<%= app_name %>.<%= type.name %>\shell\open\command" "" '$WINDIR\system32\wscript.exe "$INSTDIR\<%= app_name %>Launcher.vbs" "open_file:%1"' + WriteRegStr HKCR "<%= app_name %>.<%= type[:name] %>" "" "<%= type[:name] %>" +<%= if type[:icon_path] || @app_options[:icon_path] do %> + WriteRegStr HKCR "<%= app_name %>.<%= type[:name] %>\DefaultIcon" "" "$INSTDIR\<%= type[:name] %>Icon.ico" +<% end %> + WriteRegStr HKCR "<%= app_name %>.<%= type[:name] %>\shell\open\command" "" '$WINDIR\system32\wscript.exe "$INSTDIR\<%= app_name %>Launcher.vbs" "open_file:%1"' <% end %> <%= for url_scheme <- Keyword.fetch!(@app_options, :url_schemes) do %> @@ -72,7 +78,7 @@ Section "Install" SectionEnd Section "Desktop Shortcut" - CreateShortCut "$DESKTOP\<%= app_name %>.lnk" "$INSTDIR\<%= app_name %>Launcher.vbs" "" "$INSTDIR\AppIcon.ico" + CreateShortCut "$DESKTOP\<%= app_name %>.lnk" "$INSTDIR\<%= app_name %>Launcher.vbs" "" <%= if @app_options[:icon_path] do %> "$INSTDIR\AppIcon.ico" <% end %> SectionEnd Section "Uninstall" diff --git a/mix.exs b/mix.exs index f37c42c97..07d538c31 100644 --- a/mix.exs +++ b/mix.exs @@ -146,31 +146,34 @@ defmodule Livebook.MixProject do ], app: [ name: "Livebook", - icon_path: [ - macos: "rel/app/icon-macos.png", - windows: "rel/app/icon.ico" - ], url_schemes: ["livebook"], document_types: [ - %{ + [ name: "LiveMarkdown", extensions: ["livemd"], - icon_path: [ - macos: "rel/app/icon.png", - windows: "rel/app/icon.ico" + macos: [ + icon_path: "rel/app/icon.png", + role: "Editor" ], - macos_role: "Editor" - } + windows: [ + icon_path: "rel/app/icon.ico" + ] + ] ], additional_paths: [ "rel/erts-#{:erlang.system_info(:version)}/bin", "rel/vendor/elixir/bin" ], - server: LivebookApp, - macos_is_agent_app: true, - macos_build_dmg: macos_notarization != nil, - macos_notarization: macos_notarization, - windows_build_installer: true + macos: [ + icon_path: "rel/app/icon-macos.png", + build_dmg: macos_notarization != nil, + notarization: macos_notarization + ], + windows: [ + server: LivebookApp, + icon_path: "rel/app/icon.ico", + build_installer: true + ] ] ] ]