@@ -36,9 +36,6 @@ std::unique_ptr<system_info_utils::SystemInfo> GetSystemInfoWithUniversal() {
3636 return system_info;
3737}
3838
39- // https://delta.jan.ai/cortex/v1.0.0-176/windows-amd64/cortex-1.0.0-176-windows-amd64-network-installer.exe
40- // https://delta.jan.ai/cortex/v1.0.0-176/mac-universal/cortex-1.0.0-176-mac-universal-network-installer.pkg
41- // https://delta.jan.ai/cortex/v1.0.0-176/linux-amd64/cortex-1.0.0-176-linux-amd64-network-installer.deb
4239std::string GetNightlyInstallerName (const std::string& v,
4340 const std::string& os_arch) {
4441 const std::string kCortex = " cortex" ;
@@ -53,13 +50,14 @@ std::string GetNightlyInstallerName(const std::string& v,
5350#endif
5451}
5552
56- // C:\Users\vansa\AppData\Local\Temp\cortex\cortex-windows-amd64-network-installer.exe
5753std::string GetInstallCmd (const std::string& exe_path) {
5854#if defined(__APPLE__) && defined(__MACH__)
59- return " sudo touch /var/tmp/cortex_installer_skip_postinstall_check && sudo installer "
55+ return " sudo touch /var/tmp/cortex_installer_skip_postinstall_check && sudo "
56+ " installer "
6057 " -pkg " +
6158 exe_path +
62- " -target / && sudo rm /var/tmp/cortex_installer_skip_postinstall_check" ;
59+ " -target / && sudo rm "
60+ " /var/tmp/cortex_installer_skip_postinstall_check" ;
6361#elif defined(__linux__)
6462 return " echo -e \" n\\ n\" | sudo SKIP_POSTINSTALL=true apt install -y "
6563 " --allow-downgrades " +
@@ -70,8 +68,22 @@ std::string GetInstallCmd(const std::string& exe_path) {
7068#endif
7169}
7270
71+ std::string GetInstallCmdLinux (const std::string& script_path,
72+ const std::string& channel,
73+ const std::string& version) {
74+ std::string cmd = " sudo " + script_path;
75+ if (!channel.empty ()) {
76+ cmd += " --channel " + channel;
77+ }
78+ if (!version.empty ()) {
79+ cmd += " --version " + version.substr (1 );
80+ }
81+ return cmd + " --is_update" ;
82+ }
83+
7384bool InstallNewVersion (const std::filesystem::path& dst,
74- const std::string& exe_path) {
85+ const std::string& exe_script_path,
86+ const std::string& channel, const std::string& version) {
7587 std::filesystem::path temp = dst.parent_path () / " cortex_temp" ;
7688 auto restore_binary = [&temp, &dst]() {
7789 if (std::filesystem::exists (temp)) {
@@ -86,7 +98,14 @@ bool InstallNewVersion(const std::filesystem::path& dst,
8698 // rename binary
8799 std::rename (dst.string ().c_str (), temp.string ().c_str ());
88100 // install here
89- CommandExecutor c (GetInstallCmd (exe_path));
101+ std::string install_cmd;
102+ #if defined(__linux__)
103+ install_cmd = GetInstallCmdLinux (exe_script_path, channel, version);
104+ #else
105+ install_cmd = GetInstallCmd (exe_script_path);
106+ #endif
107+ CTL_INF (" Cmd: " << install_cmd);
108+ CommandExecutor c (install_cmd);
90109 auto output = c.execute ();
91110 if (!std::filesystem::exists (dst)) {
92111 CLI_LOG_ERROR (" Something went wrong: could not execute command" );
@@ -110,7 +129,6 @@ bool InstallNewVersion(const std::filesystem::path& dst,
110129 }
111130 return true ;
112131}
113-
114132} // namespace
115133
116134std::optional<std::string> CheckNewUpdate (
@@ -200,76 +218,6 @@ std::optional<std::string> CheckNewUpdate(
200218 return std::nullopt ;
201219}
202220
203- bool ReplaceBinaryInflight (const std::filesystem::path& src,
204- const std::filesystem::path& dst) {
205- if (src == dst) {
206- // Already has the newest
207- return true ;
208- }
209-
210- std::filesystem::path temp = dst.parent_path () / " cortex_temp" ;
211- auto restore_binary = [&temp, &dst]() {
212- if (std::filesystem::exists (temp)) {
213- std::rename (temp.string ().c_str (), dst.string ().c_str ());
214- CLI_LOG (" Restored binary file" );
215- }
216- };
217-
218- try {
219- if (std::filesystem::exists (temp)) {
220- std::filesystem::remove (temp);
221- }
222- #if !defined(_WIN32)
223- // Get permissions of the executable file
224- struct stat dst_file_stat;
225- if (stat (dst.string ().c_str (), &dst_file_stat) != 0 ) {
226- CLI_LOG_ERROR (
227- " Error getting permissions of executable file: " << dst.string ());
228- return false ;
229- }
230-
231- // Get owner and group of the executable file
232- uid_t dst_file_owner = dst_file_stat.st_uid ;
233- gid_t dst_file_group = dst_file_stat.st_gid ;
234- #endif
235-
236- std::rename (dst.string ().c_str (), temp.string ().c_str ());
237- std::filesystem::copy_file (
238- src, dst, std::filesystem::copy_options::overwrite_existing);
239-
240- #if !defined(_WIN32)
241- // Set permissions of the executable file
242- if (chmod (dst.string ().c_str (), dst_file_stat.st_mode ) != 0 ) {
243- CLI_LOG_ERROR (
244- " Error setting permissions of executable file: " << dst.string ());
245- restore_binary ();
246- return false ;
247- }
248-
249- // Set owner and group of the executable file
250- if (chown (dst.string ().c_str (), dst_file_owner, dst_file_group) != 0 ) {
251- CLI_LOG_ERROR (
252- " Error setting owner and group of executable file: " << dst.string ());
253- restore_binary ();
254- return false ;
255- }
256-
257- // Remove cortex_temp
258- if (unlink (temp.string ().c_str ()) != 0 ) {
259- CLI_LOG_ERROR (" Error deleting self: " << strerror (errno));
260- restore_binary ();
261- return false ;
262- }
263- #endif
264- } catch (const std::exception& e) {
265- CLI_LOG_ERROR (" Something went wrong: " << e.what ());
266- restore_binary ();
267- return false ;
268- }
269-
270- return true ;
271- }
272-
273221void CortexUpdCmd::Exec (const std::string& v, bool force) {
274222 // Check for update, if current version is the latest, notify to user
275223 if (auto latest_version = commands::CheckNewUpdate (std::nullopt );
@@ -314,6 +262,9 @@ void CortexUpdCmd::Exec(const std::string& v, bool force) {
314262}
315263
316264bool CortexUpdCmd::GetStable (const std::string& v) {
265+ #if defined(__linux__)
266+ return GetLinuxInstallScript (v, " stable" );
267+ #else
317268 std::optional<std::string> downloaded_exe_path;
318269 auto system_info = GetSystemInfoWithUniversal ();
319270 CTL_INF (" OS: " << system_info->os << " , Arch: " << system_info->arch );
@@ -366,10 +317,14 @@ bool CortexUpdCmd::GetStable(const std::string& v) {
366317 });
367318
368319 assert (!!downloaded_exe_path);
369- return InstallNewVersion (dst, downloaded_exe_path.value ());
320+ return InstallNewVersion (dst, downloaded_exe_path.value (), " " , " " );
321+ #endif
370322}
371323
372324bool CortexUpdCmd::GetBeta (const std::string& v) {
325+ #if defined(__linux__)
326+ return GetLinuxInstallScript (v, " beta" );
327+ #else
373328 std::optional<std::string> downloaded_exe_path;
374329 auto system_info = GetSystemInfoWithUniversal ();
375330 CTL_INF (" OS: " << system_info->os << " , Arch: " << system_info->arch );
@@ -434,7 +389,8 @@ bool CortexUpdCmd::GetBeta(const std::string& v) {
434389 });
435390
436391 assert (!!downloaded_exe_path);
437- return InstallNewVersion (dst, downloaded_exe_path.value ());
392+ return InstallNewVersion (dst, downloaded_exe_path.value (), " " , " " );
393+ #endif
438394}
439395
440396std::optional<std::string> CortexUpdCmd::HandleGithubRelease (
@@ -500,6 +456,9 @@ std::optional<std::string> CortexUpdCmd::HandleGithubRelease(
500456}
501457
502458bool CortexUpdCmd::GetNightly (const std::string& v) {
459+ #if defined(__linux__)
460+ return GetLinuxInstallScript (v, " nightly" );
461+ #else
503462 auto system_info = GetSystemInfoWithUniversal ();
504463 CTL_INF (" OS: " << system_info->os << " , Arch: " << system_info->arch );
505464
@@ -566,6 +525,82 @@ bool CortexUpdCmd::GetNightly(const std::string& v) {
566525 }
567526 });
568527
569- return InstallNewVersion (dst, localPath.string ());
528+ return InstallNewVersion (dst, localPath.string (), " " , " " );
529+ #endif
530+ }
531+
532+ bool CortexUpdCmd::GetLinuxInstallScript (const std::string& v,
533+ const std::string& channel) {
534+ std::vector<std::string> path_list;
535+ if (channel == " nightly" ) {
536+ path_list = {" janhq" , " cortex.cpp" , " feat" , " linux-bash-install-script" ,
537+ " engine" , " templates" , " linux" , " install.sh" };
538+ } else {
539+ path_list = {" janhq" , " cortex.cpp" , " main" , " engine" ,
540+ " templates" , " linux" , " install.sh" };
541+ }
542+ auto url_obj = url_parser::Url{
543+ .protocol = " https" ,
544+ .host = " raw.githubusercontent.com" ,
545+ .pathParams = path_list,
546+ };
547+
548+ CTL_INF (" Linux installer script path: " << url_parser::FromUrl (url_obj));
549+
550+ std::filesystem::path localPath =
551+ std::filesystem::temp_directory_path () / " cortex" / path_list.back ();
552+ try {
553+ if (!std::filesystem::exists (localPath.parent_path ())) {
554+ std::filesystem::create_directories (localPath.parent_path ());
555+ }
556+ } catch (const std::filesystem::filesystem_error& e) {
557+ CLI_LOG_ERROR (" Failed to create directories: " << e.what ());
558+ return false ;
559+ }
560+ auto download_task =
561+ DownloadTask{.id = " cortex" ,
562+ .type = DownloadType::Cortex,
563+ .items = {DownloadItem{
564+ .id = " cortex" ,
565+ .downloadUrl = url_parser::FromUrl (url_obj),
566+ .localPath = localPath,
567+ }}};
568+
569+ auto result = download_service_->AddDownloadTask (
570+ download_task, [](const DownloadTask& finishedTask) {
571+ // try to unzip the downloaded file
572+ CTL_INF (" Downloaded cortex path: "
573+ << finishedTask.items [0 ].localPath .string ());
574+
575+ CTL_INF (" Finished!" );
576+ });
577+ if (result.has_error ()) {
578+ CLI_LOG_ERROR (" Failed to download: " << result.error ());
579+ return false ;
580+ }
581+
582+ auto executable_path = file_manager_utils::GetExecutableFolderContainerPath ();
583+ auto dst = executable_path / GetCortexBinary ();
584+ cortex::utils::ScopeExit se ([]() {
585+ auto cortex_tmp = std::filesystem::temp_directory_path () / " cortex" ;
586+ try {
587+ auto n = std::filesystem::remove_all (cortex_tmp);
588+ CTL_INF (" Deleted " << n << " files or directories" );
589+ } catch (const std::exception& e) {
590+ CTL_WRN (e.what ());
591+ }
592+ });
593+ try {
594+ std::filesystem::permissions (localPath,
595+ std::filesystem::perms::owner_exec |
596+ std::filesystem::perms::group_exec |
597+ std::filesystem::perms::others_exec,
598+ std::filesystem::perm_options::add);
599+ } catch (const std::filesystem::filesystem_error& e) {
600+ CTL_WRN (" Error: " << e.what ());
601+ return false ;
602+ }
603+
604+ return InstallNewVersion (dst, localPath.string (), channel, v);
570605}
571606} // namespace commands
0 commit comments