Skip to content

Commit 3cbfeb4

Browse files
committed
Enhance update download process to move files to install directory for Linux/Windows
1 parent e997c52 commit 3cbfeb4

1 file changed

Lines changed: 82 additions & 17 deletions

File tree

lib/services/update_checker.dart

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ class UpdateCheckerService {
390390
return result.isGranted;
391391
}
392392

393-
// Download update file with progress tracking
393+
// Download update file with progress tracking and move to install dir (Linux/Windows)
394394
Future<String?> downloadUpdate({
395395
required ReleaseInfo release,
396396
required Function(double progress, int downloaded, int total) onProgress,
@@ -407,23 +407,23 @@ class UpdateCheckerService {
407407
final dio = Dio();
408408
final downloadsDir = await _getDownloadsDirectory();
409409
final fileExtension = _getFileExtension();
410-
final fileName = "openlib_${release.version}.$fileExtension";
411-
final filePath = "${downloadsDir.path}/$fileName";
410+
final tempFileName = "openlib_update_temp.$fileExtension";
411+
final tempFilePath = "${downloadsDir.path}/$tempFileName";
412412

413413
_logger.info("Starting update download", tag: "UpdateChecker", metadata: {
414414
"url": downloadUrl,
415-
"destination": filePath,
415+
"destination": tempFilePath,
416416
});
417417

418-
// Delete existing file if present
419-
final existingFile = File(filePath);
418+
// Delete existing temp file if present
419+
final existingFile = File(tempFilePath);
420420
if (await existingFile.exists()) {
421421
await existingFile.delete();
422422
}
423423

424424
await dio.download(
425425
downloadUrl,
426-
filePath,
426+
tempFilePath,
427427
cancelToken: cancelToken,
428428
options: Options(
429429
headers: {
@@ -440,24 +440,86 @@ class UpdateCheckerService {
440440

441441
dio.close();
442442

443+
// Determine install directory and target filename
444+
String installDirPath;
445+
String targetFileName;
446+
if (Platform.isWindows) {
447+
// Use the directory of the running executable
448+
installDirPath = File(Platform.resolvedExecutable).parent.path;
449+
targetFileName = "openlib.exe";
450+
} else if (Platform.isLinux) {
451+
installDirPath = File(Platform.resolvedExecutable).parent.path;
452+
targetFileName = "openlib.AppImage";
453+
} else {
454+
// For other platforms, just return the temp file path
455+
if (Platform.isMacOS || Platform.isIOS || Platform.isAndroid) {
456+
// No special move needed
457+
if (Platform.isLinux) {
458+
await Process.run("chmod", ["+x", tempFilePath]);
459+
}
460+
return tempFilePath;
461+
}
462+
return tempFilePath;
463+
}
464+
465+
final targetFilePath = "$installDirPath/$targetFileName";
466+
467+
// Remove old versioned executables in the install dir
468+
final dir = Directory(installDirPath);
469+
final files = dir.listSync();
470+
for (final f in files) {
471+
if (f is File) {
472+
final name = f.path.split(Platform.pathSeparator).last;
473+
if ((Platform.isWindows &&
474+
name.startsWith("openlib_") &&
475+
name.endsWith(".exe")) ||
476+
(Platform.isLinux &&
477+
name.startsWith("openlib_") &&
478+
name.endsWith(".AppImage"))) {
479+
try {
480+
await f.delete();
481+
} catch (_) {}
482+
}
483+
}
484+
}
485+
486+
// Move the downloaded file to the install directory, overwrite if exists
487+
final tempFile = File(tempFilePath);
488+
final targetFile = File(targetFilePath);
489+
if (await targetFile.exists()) {
490+
await targetFile.delete();
491+
}
492+
try {
493+
await tempFile.rename(targetFilePath);
494+
} on FileSystemException catch (e) {
495+
// errno=18 is EXDEV (cross-device link)
496+
if (e.osError != null && e.osError!.errorCode == 18) {
497+
// Fallback: copy then delete
498+
await tempFile.copy(targetFilePath);
499+
await tempFile.delete();
500+
} else {
501+
rethrow;
502+
}
503+
}
504+
443505
// Make file executable on Linux
444506
if (Platform.isLinux) {
445-
await Process.run("chmod", ["+x", filePath]);
507+
await Process.run("chmod", ["+x", targetFilePath]);
446508
}
447509

448-
_logger.info("Update downloaded successfully",
510+
_logger.info("Update moved to install directory",
449511
tag: "UpdateChecker",
450512
metadata: {
451-
"path": filePath,
513+
"path": targetFilePath,
452514
});
453515

454-
return filePath;
516+
return targetFilePath;
455517
} catch (e, stackTrace) {
456518
if (e is DioException && e.type == DioExceptionType.cancel) {
457519
_logger.info("Update download cancelled", tag: "UpdateChecker");
458520
return null;
459521
}
460-
_logger.error("Failed to download update",
522+
_logger.error("Failed to download/move update",
461523
tag: "UpdateChecker", error: e, stackTrace: stackTrace);
462524
rethrow;
463525
}
@@ -501,11 +563,14 @@ class UpdateCheckerService {
501563
if (!context.mounted) return false;
502564
return await _installApkWithFallbacks(filePath, context,
503565
release: release);
504-
} else if (Platform.isWindows) {
505-
await Process.start(filePath, [], mode: ProcessStartMode.detached);
506-
return true;
507-
} else if (Platform.isLinux) {
508-
await Process.start(filePath, [], mode: ProcessStartMode.detached);
566+
} else if (Platform.isWindows || Platform.isLinux) {
567+
// Always use the non-versioned filename in the install dir
568+
String installDirPath = File(Platform.resolvedExecutable).parent.path;
569+
String targetFileName =
570+
Platform.isWindows ? "openlib.exe" : "openlib.AppImage";
571+
String targetFilePath = "$installDirPath/$targetFileName";
572+
// Launch the new executable
573+
await Process.start(targetFilePath, [], mode: ProcessStartMode.detached);
509574
return true;
510575
} else if (Platform.isMacOS) {
511576
await OpenFile.open(filePath, type: "application/x-apple-diskimage");

0 commit comments

Comments
 (0)