Skip to content

Commit

Permalink
feat(Windows): integrate WinSparkle autoupdate framework (onivim#2497)
Browse files Browse the repository at this point in the history
* Vendor: vendor WinSparkle 0.7.0

* [Broken] Sparkle: bind to WinSparkle

* Sparkle: integrate WinSparkle

* Release.js: prettier

* Release.js: ENV fix for shell on Windows

* Setup Template: remove skipifsilent

* Sparkle: separate Sparkle and WinSparkle

* Release.js: return output from winShell

* WinSparkle: hookup close callback

* Release.js: prettier

* WinSparkle: move Windows-specific includes under ifdef

* WinSparkle: remove unused variable

* Revert whitespace changes

* WinSparkle: copy URL string from OCaml

* ThirdPartyLicenses: add Sparkle and WinSparkle

* WinSparkle: use CAML alloc functions to move string

* WinSparkle: use more up-to-date OCaml FFI functions

Co-authored-by: Bryan Phelps <[email protected]>
Co-authored-by: Bryan Phelps <[email protected]>
  • Loading branch information
3 people authored Nov 10, 2020
1 parent 1c28993 commit fed99ec
Show file tree
Hide file tree
Showing 25 changed files with 1,157 additions and 8 deletions.
36 changes: 34 additions & 2 deletions scripts/release.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ const extensionsSourceDirectory = path.join(process.cwd(), "extensions")
const eulaFile = path.join(process.cwd(), "Outrun-Labs-EULA-v1.1.md")
const thirdPartyFile = path.join(process.cwd(), "ThirdPartyLicenses.txt")
const sparkleFramework = path.join(rootDirectory, "vendor", "Sparkle-1.23.0", "Sparkle.framework")
const winSparkleDLL = path.join(
rootDirectory,
"vendor",
"WinSparkle-0.7.0",
"x64",
"Release",
"WinSparkle.dll",
)

const copy = (source, dest) => {
console.log(`Copying from ${source} to ${dest}`)
Expand All @@ -45,6 +53,16 @@ const shell = (cmd) => {
return out.toString("utf8")
}

const winShell = (cmd) => {
let oldEnv = process.env
process.env = {
PATH: process.env.PATH,
}
const res = shell(cmd)
process.env = oldEnv
return res
}

const getRipgrepPath = () => {
const rg = "ripgrep-v0.10.0"

Expand Down Expand Up @@ -123,14 +141,14 @@ if (process.platform == "linux") {

const numCommits = shell("git rev-list --count origin/master").replace(/(\r\n|\n|\r)/gm, "")
const semvers = package.version.split(".")
const cfBundleVersion = `${semvers[0]}.${semvers[1]}.${numCommits}`
const bundleVersion = `${semvers[0]}.${semvers[1]}.${numCommits}`

const plistContents = {
CFBundleName: "Onivim2",
CFBundleDisplayName: "Onivim 2",
CFBundleIdentifier: "com.outrunlabs.onivim2",
CFBundleIconFile: "Onivim2",
CFBundleVersion: cfBundleVersion,
CFBundleVersion: bundleVersion,
CFBundleShortVersionString: `${package.version}`,
CFBundlePackageType: "APPL",
CFBundleSignature: "????",
Expand Down Expand Up @@ -314,6 +332,20 @@ if (process.platform == "linux") {
getRlsPath(),
path.join(platformReleaseDirectory, process.platform == "win32" ? "rls.exe" : "rls"),
)
if (process.platform == "win32") {
const numCommits = winShell(
'"C:\\Program Files\\Git\\cmd\\git.exe" rev-list --count origin/master',
).replace(/(\r\n|\n|\r)/gm, "")
const semvers = package.version.split(".")
const bundleVersion = `${semvers[0]}.${semvers[1]}.${numCommits}`

const oni2Ini = `
[Application]
Version = ${bundleVersion}
`
fs.writeFileSync(path.join(platformReleaseDirectory, "Oni2.ini"), oni2Ini)
copy(winSparkleDLL, path.join(platformReleaseDirectory, "WinSparkle.dll"))
}
const imageSourceDirectory = path.join(rootDirectory, "assets", "images")
const iconFile = path.join(imageSourceDirectory, "oni2.ico")
fs.copySync(iconFile, path.join(platformReleaseDirectory, "oni2.ico"))
Expand Down
2 changes: 1 addition & 1 deletion scripts/windows/setup.template.iss
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Name: "addToRightClickMenu"; Description: "Add {{AppName}} to the right click me
Name: "{group}\{{AppName}}"; Filename: "{app}\{{AppExecutableName}}"

[Run]
Filename: "{app}\{{AppExecutableName}}"; Flags: postinstall skipifsilent nowait
Filename: "{app}\{{AppExecutableName}}"; Flags: postinstall nowait

[Code]
function NeedsAddPath(Param: string): boolean;
Expand Down
3 changes: 3 additions & 0 deletions src/bin_editor/Oni2_editor.re
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ switch (eff) {
Log.debug("Init");

Vim.init();
Oni2_Sparkle.init();

let initialWorkingDirectory = initWorkingDirectory();
let window =
Expand Down Expand Up @@ -339,6 +340,8 @@ switch (eff) {
App.quit(~askNicely=true, app);
};

Callback.register("oni2_close", close);

let restore = () => {
Window.restore(window);
};
Expand Down
2 changes: 1 addition & 1 deletion src/bin_editor/dune
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
(libraries bigarray Revery.zed luv lwt lwt.unix oniguruma Oni2.cli Oni2.core
Oni2.model Oni2.service.extensions Oni2.service.net Oni2.store
Oni2.syntax_client Oni2.syntax_server Oni2.ui reason-sdl2 reason-harfbuzz
fp dir.lib)
Oni2.sparkle fp dir.lib)
(preprocess
(pps lwt_ppx brisk-reconciler.ppx)))
6 changes: 5 additions & 1 deletion src/oni2-sparkle/Oni2_Sparkle.re
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"config.h";

%ifdef
USE_SPARKLE;
ENABLE_AUTOUPDATE;

external init: unit => unit = "oni2_SparkleInit";

module Updater = {
type t;
Expand All @@ -29,6 +31,8 @@ module Debug = {

[%%else];

let init = () => ();

module Updater = {
type t = unit;

Expand Down
2 changes: 2 additions & 0 deletions src/oni2-sparkle/Oni2_Sparkle.rei
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
let init: unit => unit;

module Updater: {
type t;

Expand Down
36 changes: 35 additions & 1 deletion src/oni2-sparkle/config/discover.re
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ open Configurator.C_define;

let projectRoot = Sys.getenv("ONI2_ROOT");
let sparkleDir = projectRoot ++ "/vendor/Sparkle-1.23.0/";
let winSparkleDir = projectRoot ++ "/vendor/WinSparkle-0.7.0/";

let ccopt = s => ["-ccopt", s];
let cclib = s => ["-cclib", s];
Expand Down Expand Up @@ -38,6 +39,17 @@ let useSparkle =
| _ => false
};

let useWinSparkle =
switch (os) {
| Windows =>
switch (Sys.getenv_opt("ONI2_BUILD_MODE")) {
| Some("Release") => true
| Some(_)
| None => false
}
| _ => false
};

let flags =
switch (os) {
| Mac =>
Expand All @@ -51,18 +63,40 @@ let flags =
@ ccopt("-F " ++ sparkleDir)
: []
)
| Windows =>
[]
@ (
useWinSparkle
? []
@ ccopt("-L " ++ winSparkleDir ++ "/x64/Release/")
@ cclib("-lwinsparkle")
@ cclib("-lkernel32")
@ cclib("-lshlwapi")
: []
)
| _ => []
};

let cFlags =
switch (os) {
| Mac => ["-F", sparkleDir, "-x", "objective-c"]
| Windows => ["-I", winSparkleDir ++ "/include/"]
| _ => []
};

let generateHeaderFile = conf => {
let enableAutoUpdate =
useWinSparkle || useSparkle ? Value.Int(1) : Value.Switch(false);
let useSparkle = useSparkle ? Value.Int(1) : Value.Switch(false);
gen_header_file(conf, [("USE_SPARKLE", useSparkle)]);
let useWinSparkle = useWinSparkle ? Value.Int(1) : Value.Switch(false);
gen_header_file(
conf,
[
("USE_SPARKLE", useSparkle),
("USE_WIN_SPARKLE", useWinSparkle),
("ENABLE_AUTOUPDATE", enableAutoUpdate),
],
);
};

Configurator.main(~name="discover", t => {
Expand Down
2 changes: 1 addition & 1 deletion src/oni2-sparkle/dune
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
(pps ppx_optcomp))
(foreign_stubs
(language c)
(names utils sparkle)
(names utils sparkle winsparkle)
(flags
(:include c_flags.sexp)))
(library_flags
Expand Down
10 changes: 9 additions & 1 deletion src/oni2-sparkle/stubs/sparkle.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
#include "config.h"

#ifdef USE_SPARKLE
#include <caml/alloc.h>
#include <caml/callback.h>
#include <caml/memory.h>
#include <caml/mlvalues.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef USE_SPARKLE
#import <Sparkle/Sparkle.h>

#include "utils.h"

CAMLprim value oni2_SparkleInit() {
CAMLparam0();

CAMLreturn(Val_unit);
}

CAMLprim value oni2_SparkleGetSharedInstance() {
CAMLparam0();
CAMLlocal1(vUpdater);
Expand Down
126 changes: 126 additions & 0 deletions src/oni2-sparkle/stubs/winsparkle.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "config.h"

#include <caml/alloc.h>
#include <caml/callback.h>
#include <caml/memory.h>
#include <caml/mlvalues.h>
#include <caml/threads.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef USE_WIN_SPARKLE

#include <windows.h>
#include <shlwapi.h>

#include "winsparkle.h"

void oni2_WinSparkleCloseCallback() {
static const value *closeCallback;
if (closeCallback == NULL) {
closeCallback = caml_named_value("oni2_close");
}

if (closeCallback != NULL) {
caml_c_thread_register();
caml_acquire_runtime_system();
caml_callback(*closeCallback, Val_unit);
caml_release_runtime_system();
}
}

CAMLprim value oni2_SparkleInit() {
CAMLparam0();

char iniPath[MAX_PATH];

GetModuleFileName(NULL, iniPath, MAX_PATH);
PathRemoveFileSpec(iniPath);

strcat(iniPath, "\\Oni2.ini");
char version[16];
wchar_t versionWide[16];


GetPrivateProfileString("Application", "Version", "", version, 16, iniPath);

mbstowcs(versionWide, version, 16);

win_sparkle_set_app_details(L"Outrun Labs LLC", L"Onivim 2", versionWide);
win_sparkle_set_shutdown_request_callback(oni2_WinSparkleCloseCallback);
win_sparkle_init();

CAMLreturn(Val_unit);
}

// On WinSparkle, there is no instance -- the library just uses global variables.
// So here we just return a basic `unit`
CAMLprim value oni2_SparkleGetSharedInstance() {
CAMLparam0();

CAMLreturn(Val_unit);
}

// This function doesn't make too much sense since we lose the OOP aspect on
// Windows, so it's basically a noop.
CAMLprim value oni2_SparkleDebugToString(value vData) {
CAMLparam1(vData);
CAMLlocal1(vStr);

vStr = caml_copy_string("Unimplemented");

CAMLreturn(vStr);
}

// Again, this function doesn't make much sense on Windows, so it's a noop.
CAMLprim value oni2_SparkleDebugLog(value vData) {
CAMLparam1(vData);

CAMLreturn(Val_unit);
}

CAMLprim value oni2_SparkleSetFeedURL(value vUpdater, value vUrlStr) {
CAMLparam2(vUpdater, vUrlStr);

char *urlStr = caml_stat_strdup(String_val(vUrlStr));

win_sparkle_set_appcast_url(urlStr);

CAMLreturn(Val_unit);
}

CAMLprim value oni2_SparkleGetFeedURL(value vUpdater) {
CAMLparam1(vUpdater);
CAMLlocal1(vStr);

vStr = caml_copy_string("Unimplemented");

CAMLreturn(vStr);
}

CAMLprim value oni2_SparkleSetAutomaticallyChecksForUpdates(value vUpdater, value vChecks) {
CAMLparam2(vUpdater, vChecks);

win_sparkle_set_automatic_check_for_updates(Bool_val(vChecks));

CAMLreturn(Val_unit);
}

CAMLprim value oni2_SparkleGetAutomaticallyChecksForUpdates(value vUpdater) {
CAMLparam1(vUpdater);

int checks = win_sparkle_get_automatic_check_for_updates();

CAMLreturn(Val_bool(checks));
}

CAMLprim value oni2_SparkleCheckForUpdates(value vUpdater) {
CAMLparam1(vUpdater);

win_sparkle_check_update_with_ui();

CAMLreturn(Val_unit);
}

#endif
12 changes: 12 additions & 0 deletions vendor/WinSparkle-0.7.0/AUTHORS
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Maintainer:

Vaclav Slavik <[email protected]>


Contributors:

Kohan Ikin <[email protected]>
Christian L. Jacobsen <[email protected]>
Littleboy <[email protected]>
Vasco Veloso
Jonas Emanuel Mueller <[email protected]>
25 changes: 25 additions & 0 deletions vendor/WinSparkle-0.7.0/COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright (c) 2009-2020 Vaclav Slavik

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.




This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit (http://www.openssl.org/).
Loading

0 comments on commit fed99ec

Please sign in to comment.