int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { std::optional<Options> maybe_opts = ParseCommandLine(pCmdLine); if (!maybe_opts) return 1; Options opts = std::move(*maybe_opts); if (opts.log_file) { log_fp = _wfopen(UTF8ToUTF16(*opts.log_file).c_str(), L"w"); if (!log_fp) log_fp = stderr; else atexit(FlushLog); } fprintf(log_fp, "Updating from: %s\n", opts.this_manifest_url.c_str()); fprintf(log_fp, "Updating to: %s\n", opts.next_manifest_url.c_str()); fprintf(log_fp, "Install path: %s\n", opts.install_base_path.c_str()); if (!File::IsDirectory(opts.install_base_path)) { fprintf(log_fp, "Cannot find install base path, or not a directory.\n"); return 1; } if (opts.parent_pid) { fprintf(log_fp, "Waiting for parent PID %d to complete...\n", *opts.parent_pid); HANDLE parent_handle = OpenProcess(SYNCHRONIZE, FALSE, *opts.parent_pid); WaitForSingleObject(parent_handle, INFINITE); CloseHandle(parent_handle); fprintf(log_fp, "Completed! Proceeding with update.\n"); } Manifest this_manifest, next_manifest; { std::optional<Manifest> maybe_manifest = FetchAndParseManifest(opts.this_manifest_url); if (!maybe_manifest) { fprintf(log_fp, "Could not fetch current manifest. Aborting.\n"); return 1; } this_manifest = std::move(*maybe_manifest); maybe_manifest = FetchAndParseManifest(opts.next_manifest_url); if (!maybe_manifest) { fprintf(log_fp, "Could not fetch next manifest. Aborting.\n"); return 1; } next_manifest = std::move(*maybe_manifest); } TodoList todo = ComputeActionsToDo(this_manifest, next_manifest); todo.Log(); std::optional<std::string> maybe_temp_dir = FindOrCreateTempDir(opts.install_base_path); if (!maybe_temp_dir) return 1; std::string temp_dir = std::move(*maybe_temp_dir); bool ok = PerformUpdate(todo, opts.install_base_path, opts.content_store_url, temp_dir); if (!ok) fprintf(log_fp, "Failed to apply the update.\n"); CleanUpTempDir(temp_dir, todo); return !ok; }
bool RunUpdater(std::vector<std::string> args) { std::optional<Options> maybe_opts = ParseCommandLine(args); if (!maybe_opts) { return false; } UI::Init(); Options opts = std::move(*maybe_opts); if (opts.log_file) { log_fp = fopen(opts.log_file.value().c_str(), "w"); if (!log_fp) log_fp = stderr; else atexit(FlushLog); } fprintf(log_fp, "Updating from: %s\n", opts.this_manifest_url.c_str()); fprintf(log_fp, "Updating to: %s\n", opts.next_manifest_url.c_str()); fprintf(log_fp, "Install path: %s\n", opts.install_base_path.c_str()); if (!File::IsDirectory(opts.install_base_path)) { FatalError("Cannot find install base path, or not a directory."); return false; } if (opts.parent_pid) { UI::SetDescription("Waiting for Dolphin to quit..."); fprintf(log_fp, "Waiting for parent PID %d to complete...\n", *opts.parent_pid); auto pid = opts.parent_pid.value(); UI::WaitForPID(static_cast<u32>(pid)); fprintf(log_fp, "Completed! Proceeding with update.\n"); } UI::SetVisible(true); UI::SetDescription("Fetching and parsing manifests..."); Manifest this_manifest, next_manifest; { std::optional<Manifest> maybe_manifest = FetchAndParseManifest(opts.this_manifest_url); if (!maybe_manifest) { FatalError("Could not fetch current manifest. Aborting."); return false; } this_manifest = std::move(*maybe_manifest); maybe_manifest = FetchAndParseManifest(opts.next_manifest_url); if (!maybe_manifest) { FatalError("Could not fetch next manifest. Aborting."); return false; } next_manifest = std::move(*maybe_manifest); } UI::SetDescription("Computing what to do..."); TodoList todo = ComputeActionsToDo(this_manifest, next_manifest); todo.Log(); std::optional<std::string> maybe_temp_dir = FindOrCreateTempDir(opts.install_base_path); if (!maybe_temp_dir) return false; std::string temp_dir = std::move(*maybe_temp_dir); UI::SetDescription("Performing Update..."); bool ok = PerformUpdate(todo, opts.install_base_path, opts.content_store_url, temp_dir); if (!ok) { FatalError("Failed to apply the update."); CleanUpTempDir(temp_dir, todo); return false; } UI::ResetCurrentProgress(); UI::ResetTotalProgress(); UI::SetCurrentMarquee(false); UI::SetTotalMarquee(false); UI::SetCurrentProgress(1, 1); UI::SetTotalProgress(1, 1); UI::SetDescription("Done!"); // Let the user process that we are done. UI::Sleep(1); if (opts.binary_to_restart) { UI::LaunchApplication(opts.binary_to_restart.value()); } UI::Stop(); return true; }