Skip to content

Commit bbcfd6a

Browse files
committed
Identify installer vs zip installation and run installer if required
1 parent b5ab6ff commit bbcfd6a

2 files changed

Lines changed: 77 additions & 139 deletions

File tree

Source/AutoUpdater.cpp

Lines changed: 74 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424

2525
#include "AutoUpdater.h"
2626
#include "CoreServices.h"
27+
#ifdef _WIN32
28+
#include <windows.h>
29+
#include <shellapi.h>
30+
#endif
2731

2832
//==============================================================================
2933
LatestVersionCheckerAndUpdater::LatestVersionCheckerAndUpdater()
@@ -141,16 +145,16 @@ void LatestVersionCheckerAndUpdater::run()
141145
#endif
142146
}();
143147

144-
#if JUCE_WINDOWS
145148
String requiredFilename ("open-ephys-" + versionString + "-" + osString + ".zip");
149+
150+
#if JUCE_WINDOWS
146151
File exeDir = File::getSpecialLocation(File::SpecialLocationType::currentExecutableFile).getParentDirectory();
147152
if(exeDir.findChildFiles(File::findFiles, false, "unins*").size() > 0)
148153
{
149154
requiredFilename = "Install-Open-Ephys-GUI-" + versionString + ".exe";
150155
}
151-
#elif
152-
String requiredFilename ("open-ephys-" + versionString + "-" + osString + ".zip");
153156
#endif
157+
154158
for (auto& asset : parsedAssets)
155159
{
156160
if (asset.name == requiredFilename)
@@ -288,7 +292,7 @@ class UpdateDialog : public Component
288292
TextButton chooseButton { "Download" }, cancelButton { "Cancel" };
289293
ToggleButton dontAskAgainButton { "Don't ask again" };
290294
std::unique_ptr<Drawable> juceIcon;
291-
Rectangle<int> juceIconBounds { 10, 10, 64, 64 };
295+
juce::Rectangle<int> juceIconBounds { 10, 10, 64, 64 };
292296

293297
DialogWindow* parentWindow = nullptr;
294298
};
@@ -305,7 +309,9 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Asset&
305309
if (targetFolder == File{})
306310
return;
307311

308-
downloadAndInstall (asset, targetFolder);
312+
File targetFile = targetFolder.getChildFile(asset.name).getNonexistentSibling();
313+
314+
downloadAndInstall (asset, targetFile);
309315
}
310316
}
311317

@@ -329,14 +335,14 @@ void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVe
329335
}
330336

331337
//==============================================================================
332-
class DownloadAndInstallThread : private ThreadWithProgressWindow
338+
class DownloadThread : private ThreadWithProgressWindow
333339
{
334340
public:
335-
DownloadAndInstallThread (const LatestVersionCheckerAndUpdater::Asset& a,
336-
const File& t,
337-
std::function<void()>&& cb)
341+
DownloadThread (const LatestVersionCheckerAndUpdater::Asset& a,
342+
const File& t,
343+
std::function<void()>&& cb)
338344
: ThreadWithProgressWindow ("Downloading New Version", true, true),
339-
asset (a), targetFolder (t), completionCallback (std::move (cb))
345+
asset (a), targetFile (t), completionCallback (std::move (cb))
340346
{
341347
launchThread (3);
342348
}
@@ -346,24 +352,17 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow
346352
{
347353
setProgress (0.0);
348354

349-
File targetFile = targetFolder.getChildFile(asset.name).getNonexistentSibling();
350355
auto result = download (targetFile);
351356

352-
// if (result.wasOk() && ! threadShouldExit())
353-
// result = install (zipData);
354-
355357
if (result.failed())
356358
{
357-
MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
358-
"Downloading Failed",
359-
result.getErrorMessage()); });
359+
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
360+
"Downloading Failed",
361+
result.getErrorMessage());
360362
}
361363
else
362364
{
363-
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
364-
"Download finished!",
365-
"New binaries can be found at: " +
366-
targetFile.getFullPathName());
365+
setProgress (-1.0);
367366
MessageManager::callAsync (completionCallback);
368367
}
369368
}
@@ -406,7 +405,10 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow
406405

407406
setProgress((double)total / (double)asset.size);
408407

409-
setStatusMessage ("Downloading... " + File::descriptionOfSizeInBytes (total));
408+
setStatusMessage ("Downloading... "
409+
+ File::descriptionOfSizeInBytes (total)
410+
+ " / "
411+
+ File::descriptionOfSizeInBytes (asset.size));
410412
}
411413

412414
out->flush();
@@ -416,132 +418,68 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow
416418
return Result::fail ("Failed to download from: " + asset.url);
417419
}
418420

419-
Result install (const File& dest)
420-
{
421-
setStatusMessage ("Installing...");
422-
423-
ZipFile zip (dest);
424-
425-
// if (zip.getNumEntries() == 0)
426-
// return Result::fail ("The downloaded file was not a valid JUCE file!");
427-
428-
// struct ScopedDownloadFolder
429-
// {
430-
// explicit ScopedDownloadFolder (const File& installTargetFolder)
431-
// {
432-
// folder = installTargetFolder.getSiblingFile (installTargetFolder.getFileNameWithoutExtension() + "_download").getNonexistentSibling();
433-
// jassert (folder.createDirectory());
434-
// }
435-
436-
// ~ScopedDownloadFolder() { folder.deleteRecursively(); }
437-
438-
// File folder;
439-
// };
440-
441-
// ScopedDownloadFolder unzipTarget (targetFolder);
442-
443-
// if (! unzipTarget.folder.isDirectory())
444-
// return Result::fail ("Couldn't create a temporary folder to unzip the new version!");
445-
446-
// auto r = zip.uncompressTo (unzipTarget.folder);
447-
448-
// if (r.failed())
449-
// return r;
450-
451-
// if (threadShouldExit())
452-
// return Result::fail ("Cancelled");
453-
454-
// #if JUCE_LINUX || JUCE_BSD || JUCE_MAC
455-
// r = setFilePermissions (unzipTarget.folder, zip);
456-
457-
// if (r.failed())
458-
// return r;
459-
460-
// if (threadShouldExit())
461-
// return Result::fail ("Cancelled");
462-
// #endif
463-
464-
// if (targetFolder.exists())
465-
// {
466-
// auto oldFolder = targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling();
467-
468-
// if (! targetFolder.moveFileTo (oldFolder))
469-
// return Result::fail ("Could not remove the existing folder!\n\n"
470-
// "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"
471-
// "Please select a folder that is writable by the current user.");
472-
// }
473-
474-
// if (! unzipTarget.folder.getChildFile ("JUCE").moveFileTo (targetFolder))
475-
// return Result::fail ("Could not overwrite the existing folder!\n\n"
476-
// "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"
477-
// "Please select a folder that is writable by the current user.");
478-
479-
// return Result::ok();
480-
}
481-
482-
Result setFilePermissions (const File& root, const ZipFile& zip)
483-
{
484-
// constexpr uint32 executableFlag = (1 << 22);
485-
486-
// for (int i = 0; i < zip.getNumEntries(); ++i)
487-
// {
488-
// auto* entry = zip.getEntry (i);
489-
490-
// if ((entry->externalFileAttributes & executableFlag) != 0 && entry->filename.getLastCharacter() != '/')
491-
// {
492-
// auto exeFile = root.getChildFile (entry->filename);
493-
494-
// if (! exeFile.exists())
495-
// return Result::fail ("Failed to find executable file when setting permissions " + exeFile.getFileName());
496-
497-
// if (! exeFile.setExecutePermission (true))
498-
// return Result::fail ("Failed to set executable file permission for " + exeFile.getFileName());
499-
// }
500-
// }
501-
502-
// return Result::ok();
503-
}
504-
505421
const LatestVersionCheckerAndUpdater::Asset asset;
506-
File targetFolder;
422+
File targetFile;
507423
std::function<void()> completionCallback;
508424
};
509425

510-
static void restartProcess (const File& targetFolder)
426+
static void runInstaller (const File& targetFile)
511427
{
512-
#if JUCE_MAC || JUCE_LINUX || JUCE_BSD
513-
#if JUCE_MAC
514-
auto newProcess = targetFolder.getChildFile ("Projucer.app").getChildFile ("Contents").getChildFile ("MacOS").getChildFile ("Projucer");
515-
#elif JUCE_LINUX || JUCE_BSD
516-
auto newProcess = targetFolder.getChildFile ("Projucer");
517-
#endif
518-
519-
StringArray command ("/bin/sh", "-c", "while killall -0 Projucer; do sleep 5; done; " + newProcess.getFullPathName().quoted());
520-
#elif JUCE_WINDOWS
521-
auto newProcess = targetFolder.getChildFile ("Projucer.exe");
522-
523-
auto command = "cmd.exe /c\"@echo off & for /l %a in (0) do ( tasklist | find \"Projucer\" >nul & ( if errorlevel 1 ( "
524-
+ targetFolder.getChildFile ("Projucer.exe").getFullPathName().quoted() + " & exit /b ) else ( timeout /t 10 >nul ) ) )\"";
525-
#endif
526-
527-
if (newProcess.existsAsFile())
428+
bool runInstaller = AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
429+
"Quit Open Ephys GUI?",
430+
"To run the installer, the current instance of GUI needs to be closed."
431+
"\nAre you sure you want to continue?",
432+
"Yes", "No");
433+
434+
if(runInstaller)
528435
{
529-
ChildProcess restartProcess;
530-
restartProcess.start (command, 0);
436+
#if JUCE_WINDOWS
437+
if (targetFile.existsAsFile())
438+
{
439+
auto returnCode = ShellExecute(NULL, (LPCSTR)"runas", targetFile.getFullPathName().toRawUTF8(), NULL, NULL, SW_SHOW);
531440

532-
JUCEApplication::getInstance()->systemRequestedQuit();
441+
if((int)returnCode > 31)
442+
JUCEApplication::getInstance()->systemRequestedQuit();
443+
else
444+
LOGE("Failed to run the installer: ", GetLastError());
445+
}
446+
#endif
533447
}
534448
}
535449

536-
void LatestVersionCheckerAndUpdater::downloadAndInstall (const Asset& asset, const File& targetFolder)
450+
void LatestVersionCheckerAndUpdater::downloadAndInstall (const Asset& asset, const File& targetFile)
537451
{
538-
installer.reset (new DownloadAndInstallThread (asset, targetFolder,
539-
[this, targetFolder]
540-
{
541-
installer.reset();
452+
#if JUCE_WINDOWS
453+
File exeDir = File::getSpecialLocation(
454+
File::SpecialLocationType::currentExecutableFile).getParentDirectory();
455+
456+
if(exeDir.findChildFiles(File::findFiles, false, "unins*").size() > 0)
457+
{
458+
downloader.reset (new DownloadThread (asset, targetFile,
459+
[this, targetFile]
460+
{
461+
downloader.reset();
462+
runInstaller(targetFile);
463+
464+
}));
465+
}
466+
else
467+
#endif
468+
{
469+
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
470+
"Download successful!",
471+
"Please extract the zip file located at: \n" +
472+
targetFile.getFullPathName().quoted() +
473+
"\nto your desired location and then run the updated version from there. "
474+
"You can also overwrite the current installation after quitting the current instance.");
475+
476+
downloader.reset (new DownloadThread (asset, targetFile,
477+
[this]
478+
{
479+
downloader.reset();
542480

543-
// restartProcess (targetFolder);
544-
}));
481+
}));
482+
}
545483
}
546484

547485
//==============================================================================

Source/AutoUpdater.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
#include "../JuceLibraryCode/JuceHeader.h"
2828

29-
class DownloadAndInstallThread;
29+
class DownloadThread;
3030

3131
class LatestVersionCheckerAndUpdater : public DeletedAtShutdown,
3232
private Thread
@@ -52,11 +52,11 @@ class LatestVersionCheckerAndUpdater : public DeletedAtShutdown,
5252
void run() override;
5353
void askUserAboutNewVersion (const String&, const String&, const Asset& asset);
5454
void askUserForLocationToDownload (const Asset& asset);
55-
void downloadAndInstall (const Asset& asset, const File& targetFolder);
55+
void downloadAndInstall (const Asset& asset, const File& targetFile);
5656

5757
//==============================================================================
5858
bool backgroundCheck = false;
5959

60-
std::unique_ptr<DownloadAndInstallThread> installer;
60+
std::unique_ptr<DownloadThread> downloader;
6161
std::unique_ptr<Component> dialogWindow;
6262
};

0 commit comments

Comments
 (0)