Browse Source

Feat(bundler) dmg bundler (#38)

* feat(cli) init tauri mode

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* feat(cli:init) add force & logging flags, full JSDoc

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* feat(cli:init) remove console.log

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* feat(cli:dev) get rust compile to finish

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* feat(cli:build) get rust compile to finish

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* feat(cli) set template with current working defaults

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* chore(version) bump

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* fix(typo)

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* fix(template): missing name warning

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* fix(bundler): correct repository link

Signed-off-by: Daniel Thompson-Yvetot <denjell@quasar.dev>

* feat(lib|cli) read config from tauriDir

* chore(cli) remove console.log statement

* fix(embedded-server) JS content type

* feat(template): add rust2018 flag

* chore(docs): remove docs

* add bash templates

* setup handlebars

* output both templates

* finish bundle_project logic

* comment and cleanup

* correct path

* fix(bundler): osx not ios

* feat(dmg): get it to work and look ok WIP
- add background image
- link seticon
Tensor-Programming 5 năm trước cách đây
mục cha
commit
f3929c13d9

+ 4 - 0
tools/rust/cargo-tauri-bundle/Readme.md

@@ -134,3 +134,7 @@ stability.
 This program is licensed either under the terms of the
 [Apache Software License](http://www.apache.org/licenses/LICENSE-2.0), or the
 [MIT License](https://opensource.org/licenses/MIT).
+
+-> note, for bundle_dmg we have included a BSD 3 licenced binary `seticon`.
+https://github.com/sveinbjornt/osxiconutils/blob/master/seticon.m
+`tools/rust/cargo-tauri-bundle/src/bundle/templates/seticon`

+ 4 - 0
tools/rust/cargo-tauri-bundle/src/bundle.rs

@@ -1,6 +1,7 @@
 mod category;
 mod common;
 mod deb_bundle;
+mod dmg_bundle;
 mod ios_bundle;
 mod msi_bundle;
 mod osx_bundle;
@@ -18,9 +19,12 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<PathBuf>> {
     paths.append(&mut match package_type {
       PackageType::OsxBundle => osx_bundle::bundle_project(&settings)?,
       PackageType::IosBundle => ios_bundle::bundle_project(&settings)?,
+      // use dmg bundler
+      // PackageType::OsxBundle => dmg_bundle::bundle_project(&settings)?,
       PackageType::WindowsMsi => msi_bundle::bundle_project(&settings)?,
       PackageType::Deb => deb_bundle::bundle_project(&settings)?,
       PackageType::Rpm => rpm_bundle::bundle_project(&settings)?,
+      PackageType::Dmg => dmg_bundle::bundle_project(&settings)?,
     });
   }
   Ok(paths)

+ 73 - 0
tools/rust/cargo-tauri-bundle/src/bundle/dmg_bundle.rs

@@ -0,0 +1,73 @@
+use super::common;
+use super::osx_bundle;
+use crate::Settings;
+
+use handlebars::Handlebars;
+use lazy_static::lazy_static;
+
+use std::collections::BTreeMap;
+use std::fs::write;
+use std::path::PathBuf;
+use std::process::{Command, Stdio};
+
+// Create handlebars template for shell scripts
+lazy_static! {
+  static ref HANDLEBARS: Handlebars = {
+    let mut handlebars = Handlebars::new();
+
+    handlebars
+      .register_template_string("bundle_dmg", include_str!("templates/bundle_dmg"))
+      .unwrap();
+    handlebars
+  };
+}
+
+// create script files to bundle project and execute bundle_script.
+pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
+  // generate the app.app folder
+  osx_bundle::bundle_project(settings)?;
+
+  // get uppercase string of app name
+  let upcase = settings.binary_name().to_uppercase();
+
+  // generate BTreeMap for templates
+  let mut sh_map = BTreeMap::new();
+  sh_map.insert("app_name", settings.binary_name());
+  sh_map.insert("app_name_upcase", &upcase);
+
+  let bundle_temp = HANDLEBARS
+    .render("bundle_dmg", &sh_map)
+    .or_else(|e| Err(e.to_string()))?;
+
+  // get the target path
+  let output_path = settings.project_out_directory();
+
+  // create paths for script
+  let bundle_sh = output_path.join("bundle_dmg.sh");
+
+  common::print_bundling(format!("{:?}", &output_path.join(format!("{}.dmg", &upcase))).as_str())?;
+
+  // write the scripts
+  write(&bundle_sh, bundle_temp).or_else(|e| Err(e.to_string()))?;
+
+  // chmod script for execution
+
+  Command::new("chmod")
+    .arg("777")
+    .arg(&bundle_sh)
+    .current_dir(output_path)
+    .stdout(Stdio::piped())
+    .stderr(Stdio::piped())
+    .spawn()
+    .expect("Failed to chmod script");
+
+    // execute the bundle script
+  Command::new(&bundle_sh)
+    .current_dir(output_path)
+    .stdout(Stdio::piped())
+    .stderr(Stdio::piped())
+    .output()
+    .expect("Failed to execute shell script");
+
+  Ok(vec![bundle_sh])
+}

+ 3 - 0
tools/rust/cargo-tauri-bundle/src/bundle/settings.rs

@@ -17,6 +17,7 @@ pub enum PackageType {
   WindowsMsi,
   Deb,
   Rpm,
+  Dmg,
 }
 
 impl PackageType {
@@ -28,6 +29,7 @@ impl PackageType {
       "msi" => Some(PackageType::WindowsMsi),
       "osx" => Some(PackageType::OsxBundle),
       "rpm" => Some(PackageType::Rpm),
+      "dmg" => Some(PackageType::Dmg),
       _ => None,
     }
   }
@@ -39,6 +41,7 @@ impl PackageType {
       PackageType::WindowsMsi => "msi",
       PackageType::OsxBundle => "osx",
       PackageType::Rpm => "rpm",
+      PackageType::Dmg => "dmg",
     }
   }
 

+ 144 - 0
tools/rust/cargo-tauri-bundle/src/bundle/templates/bundle_dmg

@@ -0,0 +1,144 @@
+#!/usr/bin/env sh
+# using sh because modern MacOS ships with zsh not bash
+# some patterns "lifted" from:
+#  - https://github.com/andreyvit/create-dmg/blob/master/create-dmg
+#  - https://stackoverflow.com/a/97025
+#  - https://github.com/sindresorhus/create-dmg/blob/master/cli.js
+
+set -e
+MACOS_APP_NAME="{{app_name_upcase}}"
+MACOS_APP_DIR="bundle/osx/{{app_name}}.app"
+ICNS_FILE="app.app/Contents/Resources/icon.icns"
+DMG_TEMP_NAME=/tmp/temp.dmg
+MOUNT_DIR="/Volumes/${MACOS_APP_NAME}"
+
+# Create the image
+echo "Creating disk image..."
+test -f "${DMG_TEMP_NAME}" && rm -f "${DMG_TEMP_NAME}"
+test -f "${MACOS_APP_NAME}.dmg" && rm -f "${MACOS_APP_NAME}.dmg"
+
+hdiutil create ${DMG_TEMP_NAME} -srcfolder bundle/osx -volname "${MACOS_APP_NAME}" -ov -format UDRW -size 10000k -fs HFS+ -fsargs "-c c=64,a=16,e=16" -anyowners -nospotlight
+
+# mount it
+echo "Mounting disk image..."
+# try unmount dmg if it was mounted previously (e.g. developer mounted dmg, installed app and forgot to unmount it)
+DEV_NAME=$(hdiutil info | egrep --color=never '^/dev/' | sed 1q | awk '{print $1}')
+test -d "${MOUNT_DIR}" && hdiutil detach "${DEV_NAME}"
+
+device=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_TEMP_NAME}" | \
+         egrep '^/dev/' | sed 1q | awk '{print $1}')
+
+sleep 5
+
+
+bless --folder "${MOUNT_DIR}" -label "${MACOS_APP_NAME}"
+
+test -d "${MOUNT_DIR}/.background" || mkdir "${MOUNT_DIR}/.background"
+cp ../../icons/bg.png "${MOUNT_DIR}"/.background/bg.png
+
+# I couldn't get DeRez and Rez to work. Leaving it here in case its helpful in the future.
+### DeRez -only icns "${MOUNT_DIR}/.VolumeIcon.icns" > "${MOUNT_DIR}/.VolumeIcon.rsrc"
+### Rez -append "${MOUNT_DIR}/.VolumeIcon.rsrc" -o my_app.dmg
+
+# This Works
+cp '../../icons/icon.icns' "${MOUNT_DIR}/.VolumeIcon.icns"
+VERSION=$(sw_vers -productVersion | cut -d'.' -f2)
+
+if [ "$VERSION" -gt 12 ]; then
+  echo "Using SIPS v10.13+"
+  sips --i "${MOUNT_DIR}/.VolumeIcon.icns" # 10.13+
+else
+    echo "Using SIPS v10.12-"
+  sips --addIcon "${MOUNT_DIR}/.VolumeIcon.icns"
+fi
+
+SetFile -c icnC "${MOUNT_DIR}/.VolumeIcon.icns"
+SetFile -a C "${MOUNT_DIR}"
+
+# Doesn't stick after the renaming
+### ./seticon "${MOUNT_DIR}/${ICNS_FILE}" "${DMG_TEMP_NAME}"
+
+# This does not work
+### echo "read 'icns' (-16455) \"${MOUNT_DIR}/.VolumeIcon.icns\";" >> Icon.rsrc
+### Rez -a Icon.rsrc -o FileName.ext
+### DeRez -only icns "${MOUNT_DIR}/.VolumeIcon.icns" > "${MOUNT_DIR}/.Icon.rsrc"
+### Rez -a Icon.rsrc -o "${MOUNT_DIR}/Icon$'\r'"
+### SetFile -c icnC "${MOUNT_DIR}/.Icon.rsrc"
+### SetFile -a C "${MOUNT_DIR}"
+### SetFile -a "${MOUNT_DIR}/Icon$'\r'"
+
+
+# this is from
+# https://stackoverflow.com/questions/8371790/how-to-set-icon-on-file-or-directory-using-cli-on-os-x#8375093
+### iconSource='../../icons/icon.icns'
+### iconDestination="${MOUNT_DIR}"
+### icon=/tmp/$(basename $iconSource)
+### rsrc=/tmp/icon.rsrc
+
+# Create icon from the iconSource
+### cp $iconSource $icon
+
+# Add icon to image file, meaning use itself as the icon
+### sips -i $icon
+
+# Take that icon and put it into a rsrc file
+### DeRez -only icns $icon > $rsrc
+
+# Apply the rsrc file to
+### SetFile -a C "${iconDestination}"
+
+# Create the magical Icon\r file
+### touch "${iconDestination}/Icon$'\r'"
+### Rez -append $rsrc -o "${iconDestination}/Icon?"
+### SetFile -a V "${iconDestination}/Icon$'\r'"
+
+echo '
+   tell application "Finder"
+     tell disk "'${MACOS_APP_NAME}'"
+           open
+           set current view of container window to icon view
+           set toolbar visible of container window to false
+           set statusbar visible of container window to false
+           set the bounds of container window to {400, 100, 885, 430}
+           set theViewOptions to the icon view options of container window
+           set arrangement of theViewOptions to not arranged
+           set icon size of theViewOptions to 110
+           set background picture of theViewOptions to file ".background:'bg.png'"
+           make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
+           set position of item "'app.app'" of container window to {100, 100}
+           set position of item "Applications" of container window to {375, 100}
+           update without registering applications
+           delay 5
+           close
+     end tell
+   end tell
+' | osascript
+chmod -Rf go-w /Volumes/"${MACOS_APP_NAME}"
+
+sync
+sync
+
+hdiutil detach ${device}
+
+# Some variations on format:
+## UDZO – Compressed image (default)
+## UDRO – Read-only image
+## UDBZ – Better compressed image
+## UDRW – Read/Write image
+
+hdiutil convert "${DMG_TEMP_NAME}" -format UDBZ -imagekey zlib-level=9 -o "${MACOS_APP_NAME}"
+
+./seticon ../../icons/icon.icns "${MACOS_APP_NAME}.dmg"
+
+rm -f ${DMG_TEMP_NAME}
+
+# This seems not to work as well at maintaining the icons :(
+zip -r "${MACOS_APP_NAME}.dmg.zip" "${MACOS_APP_NAME}.dmg"
+
+
+# FUTURE WORK
+# SIGNER=$(security find-identity -v -p codesigning)
+# codesign --sign 'Mac Developer' "${DMG_TEMP_NAME}"
+
+# Add a license with Rez
+# http://www.owsiak.org/adding-license-to-a-dmg-file-in-5-minutes-or-less/

BIN
tools/rust/cargo-tauri-bundle/src/bundle/templates/seticon