@@ -510,6 +510,9 @@ namespace vix::commands
510510 out << " User=" << cfg.user << " \n " ;
511511 out << " WorkingDirectory=" << cfg.workingDir .string () << " \n " ;
512512
513+ if (const auto cliPath = current_vix_cli_path ())
514+ out << " Environment=VIX_CLI_PATH=" << cliPath->string () << " \n " ;
515+
513516 if (cfg.vixDir )
514517 {
515518 out << " Environment=Vix_DIR=" << cfg.vixDir ->string () << " \n " ;
@@ -527,6 +530,159 @@ namespace vix::commands
527530 return out.str ();
528531 }
529532
533+ std::optional<std::string> systemctl_property (
534+ const std::string &serviceName,
535+ const std::string &property)
536+ {
537+ const std::string cmd =
538+ " systemctl show " +
539+ shell_quote (serviceName) +
540+ " -p " +
541+ shell_quote (property) +
542+ " --value 2>/dev/null" ;
543+
544+ return run_capture (cmd);
545+ }
546+
547+ fs::path canonical_or_absolute (const fs::path &path)
548+ {
549+ std::error_code ec;
550+
551+ fs::path resolved = fs::weakly_canonical (path, ec);
552+
553+ if (!ec && !resolved.empty ())
554+ return resolved;
555+
556+ resolved = fs::absolute (path, ec);
557+
558+ if (!ec && !resolved.empty ())
559+ return resolved;
560+
561+ return path;
562+ }
563+
564+ std::optional<fs::path> current_vix_cli_path ()
565+ {
566+ if (const char *path = vix::utils::vix_getenv (" VIX_CLI_PATH" ))
567+ {
568+ if (*path)
569+ return fs::path (path);
570+ }
571+
572+ const auto found = run_capture (" command -v vix 2>/dev/null" );
573+
574+ if (!found)
575+ return std::nullopt ;
576+
577+ return fs::path (*found);
578+ }
579+
580+ std::optional<std::string> parse_environment_value (
581+ const std::string &raw,
582+ const std::string &key)
583+ {
584+ std::istringstream stream (raw);
585+ std::string token;
586+ const std::string prefix = key + " =" ;
587+
588+ while (stream >> token)
589+ {
590+ if (token.rfind (prefix, 0 ) == 0 )
591+ return token.substr (prefix.size ());
592+ }
593+
594+ return std::nullopt ;
595+ }
596+
597+ void warn_if_service_points_to_old_build_dir (const ServiceConfig &cfg)
598+ {
599+ const auto execStart =
600+ systemctl_property (cfg.serviceName , " ExecStart" );
601+
602+ if (!execStart || execStart->empty ())
603+ return ;
604+
605+ const fs::path currentExec =
606+ canonical_or_absolute (cfg.execPath );
607+
608+ const std::string currentExecString = currentExec.string ();
609+
610+ if (execStart->find (currentExecString) != std::string::npos)
611+ return ;
612+
613+ vix::cli::util::warn_line (
614+ std::cerr,
615+ " Service executable points to a different build path." );
616+
617+ vix::cli::util::kv (
618+ std::cerr,
619+ " Service" ,
620+ *execStart);
621+
622+ vix::cli::util::kv (
623+ std::cerr,
624+ " Current" ,
625+ currentExecString);
626+
627+ vix::cli::util::warn_line (
628+ std::cerr,
629+ " Fix: run `vix service install` then `vix service restart`." );
630+ }
631+
632+ void warn_if_service_uses_different_vix_installation (const ServiceConfig &cfg)
633+ {
634+ const auto currentCli =
635+ current_vix_cli_path ();
636+
637+ if (!currentCli)
638+ return ;
639+
640+ const auto environment =
641+ systemctl_property (cfg.serviceName , " Environment" );
642+
643+ if (!environment || environment->empty ())
644+ return ;
645+
646+ const auto serviceCli =
647+ parse_environment_value (*environment, " VIX_CLI_PATH" );
648+
649+ if (!serviceCli || serviceCli->empty ())
650+ return ;
651+
652+ const fs::path current =
653+ canonical_or_absolute (*currentCli);
654+
655+ const fs::path service =
656+ canonical_or_absolute (fs::path (*serviceCli));
657+
658+ if (current == service)
659+ return ;
660+
661+ vix::cli::util::warn_line (
662+ std::cerr,
663+ " Service uses a different Vix CLI installation." );
664+
665+ vix::cli::util::kv (
666+ std::cerr,
667+ " Current CLI" ,
668+ current.string ());
669+
670+ vix::cli::util::kv (
671+ std::cerr,
672+ " Service CLI" ,
673+ service.string ());
674+
675+ vix::cli::util::warn_line (
676+ std::cerr,
677+ " Fix: update production.service.environment.VIX_CLI_PATH, then run `vix service install`." );
678+ }
679+
680+ void warn_if_service_config_is_stale (const ServiceConfig &cfg)
681+ {
682+ warn_if_service_points_to_old_build_dir (cfg);
683+ warn_if_service_uses_different_vix_installation (cfg);
684+ }
685+
530686 int install_service ()
531687 {
532688 const ServiceConfig cfg = load_service_config ();
@@ -611,6 +767,8 @@ namespace vix::commands
611767
612768 if (action == " status" )
613769 {
770+ warn_if_service_config_is_stale (cfg);
771+
614772 return std::system (
615773 (" systemctl status " + shell_quote (cfg.serviceName )).c_str ());
616774 }
0 commit comments