duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

cocoa_main.mm (3937B)


      1 // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "cocoa_progress_callback.h"
      5 #include "updater.h"
      6 
      7 #include "common/file_system.h"
      8 #include "common/log.h"
      9 #include "common/path.h"
     10 #include "common/scoped_guard.h"
     11 #include "common/string_util.h"
     12 #include "common/timer.h"
     13 
     14 #include <cstdlib>
     15 #include <thread>
     16 
     17 static void LaunchApplication(const char* path)
     18 {
     19   @autoreleasepool
     20   {
     21     NSTask* task = [[[NSTask alloc] init] autorelease];
     22     [task setLaunchPath:[NSString stringWithUTF8String:path]];
     23     [task launch];
     24   }
     25 }
     26 
     27 int main(int argc, char* argv[])
     28 {
     29   [NSApplication sharedApplication];
     30   [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
     31 
     32   // Needed for keyboard in put.
     33   const ProcessSerialNumber psn = {0, kCurrentProcess};
     34   TransformProcessType(&psn, kProcessTransformToForegroundApplication);
     35 
     36   CocoaProgressCallback progress;
     37 
     38   if (argc != 4)
     39   {
     40     progress.ModalError("Expected 3 arguments: update zip, staging directory, output directory.\n\nThis program is not "
     41                         "intended to be run manually, please use the Qt frontend and click Help->Check for Updates.");
     42     return EXIT_FAILURE;
     43   }
     44 
     45   std::string zip_path = argv[1];
     46   std::string staging_directory = argv[2];
     47   std::string destination_directory = argv[3];
     48 
     49   if (zip_path.empty() || staging_directory.empty() || destination_directory.empty())
     50   {
     51     progress.ModalError("One or more parameters is empty.");
     52     return EXIT_FAILURE;
     53   }
     54 
     55   if (const char* home_dir = getenv("HOME"))
     56   {
     57     static constexpr char log_file[] = "Library/Application Support/DuckStation/updater.log";
     58     std::string log_path = Path::Combine(home_dir, log_file);
     59     Log::SetFileOutputParams(true, log_path.c_str());
     60   }
     61 
     62   std::string program_to_launch = Path::Combine(destination_directory, "Contents/MacOS/DuckStation");
     63   int result = EXIT_SUCCESS;
     64 
     65   std::thread worker([&progress, zip_path = std::move(zip_path),
     66                       destination_directory = std::move(destination_directory),
     67                       staging_directory = std::move(staging_directory), &result]() {
     68     ScopedGuard app_stopper([]() { dispatch_async(dispatch_get_main_queue(), []() { [NSApp stop:nil]; }); });
     69 
     70     Updater updater(&progress);
     71     if (!updater.Initialize(std::move(staging_directory), std::move(destination_directory)))
     72     {
     73       progress.ModalError("Failed to initialize updater.");
     74       result = EXIT_FAILURE;
     75       return;
     76     }
     77 
     78     if (!updater.OpenUpdateZip(zip_path.c_str()))
     79     {
     80       progress.FormatModalError("Could not open update zip '{}'. Update not installed.", zip_path);
     81       result = EXIT_FAILURE;
     82       return;
     83     }
     84 
     85     if (!updater.PrepareStagingDirectory())
     86     {
     87       progress.ModalError("Failed to prepare staging directory. Update not installed.");
     88       result = EXIT_FAILURE;
     89       return;
     90     }
     91 
     92     if (!updater.StageUpdate())
     93     {
     94       progress.ModalError("Failed to stage update. Update not installed.");
     95       result = EXIT_FAILURE;
     96       return;
     97     }
     98 
     99     if (!updater.ClearDestinationDirectory())
    100     {
    101       progress.ModalError("Failed to clear destination directory. Your installation may be corrupted, please "
    102                           "re-download a fresh version from GitHub.");
    103       result = EXIT_FAILURE;
    104       return;
    105     }
    106 
    107     if (!updater.CommitUpdate())
    108     {
    109       progress.ModalError(
    110         "Failed to commit update. Your installation may be corrupted, please re-download a fresh version from GitHub.");
    111       result = EXIT_FAILURE;
    112       return;
    113     }
    114 
    115     updater.CleanupStagingDirectory();
    116     updater.RemoveUpdateZip();
    117     
    118     result = EXIT_SUCCESS;
    119   });
    120 
    121   [NSApp run];
    122 
    123   worker.join();
    124 
    125   if (result == EXIT_SUCCESS)
    126   {
    127     progress.FormatInformation("Launching '{}'...", program_to_launch);
    128     LaunchApplication(program_to_launch.c_str());
    129   }
    130 
    131   return result;
    132 }