Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 44 additions & 16 deletions model/daemon-installer.linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"text/template"

Expand All @@ -26,7 +27,7 @@ func NewLinuxDaemonInstaller(baseFolder, user string) *LinuxDaemonInstaller {
}

func (l *LinuxDaemonInstaller) Check() error {
cmd := exec.Command("systemctl", "is-active", "shelltime")
cmd := exec.Command("systemctl", "--user", "is-active", "shelltime")
if err := cmd.Run(); err == nil {
return nil
}
Expand All @@ -36,13 +37,20 @@ func (l *LinuxDaemonInstaller) Check() error {
func (l *LinuxDaemonInstaller) CheckAndStopExistingService() error {
color.Yellow.Println("🔍 Checking if service is running...")

if err := l.Check(); err != nil {
return err
}

color.Yellow.Println("🛑 Stopping existing service...")
if err := exec.Command("systemctl", "stop", "shelltime").Run(); err != nil {
return fmt.Errorf("failed to stop existing service: %w", err)
if err := l.Check(); err == nil {
color.Yellow.Println("🛑 Stopping existing service...")
currentUser, err := user.Current()
if err != nil {
return fmt.Errorf("failed to get current user: %w", err)
}
servicePath := filepath.Join(currentUser.HomeDir, ".config/systemd/user/shelltime.service")
if err := exec.Command("systemctl", "--user", "stop", "shelltime").Run(); err != nil {
return fmt.Errorf("failed to stop existing service: %w", err)
}
// Also disable to clean up
_ = exec.Command("systemctl", "--user", "disable", "shelltime").Run()
// Remove old symlink if exists
_ = os.Remove(servicePath)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error from os.Remove is ignored here. This is inconsistent with UnregisterService (line 150), which correctly handles the error by checking for os.IsNotExist. For better robustness and consistency, you should handle the error here as well. This will prevent silent failures if the file removal fails for unexpected reasons, such as permission issues.

		if err := os.Remove(servicePath); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("failed to remove old service symlink: %w", err)
		}

}
return nil
}
Expand Down Expand Up @@ -80,7 +88,19 @@ func (l *LinuxDaemonInstaller) RegisterService() error {
if l.baseFolder == "" {
return fmt.Errorf("base folder is not set")
}
servicePath := "/etc/systemd/system/shelltime.service"

currentUser, err := user.Current()
if err != nil {
return fmt.Errorf("failed to get current user: %w", err)
}

// Create systemd user directory if it doesn't exist
systemdUserDir := filepath.Join(currentUser.HomeDir, ".config/systemd/user")
Comment on lines +92 to +98
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is code duplication in RegisterService, CheckAndStopExistingService, and UnregisterService. Each of these functions retrieves the current user and constructs paths for the systemd user directory. To improve maintainability and adhere to the DRY (Don't Repeat Yourself) principle, consider refactoring this logic into a shared helper method. This method could be responsible for providing the systemdUserDir and servicePath, centralizing the path construction logic.

if err := os.MkdirAll(systemdUserDir, 0755); err != nil {
return fmt.Errorf("failed to create systemd user directory: %w", err)
}

servicePath := filepath.Join(systemdUserDir, "shelltime.service")
if _, err := os.Stat(servicePath); err != nil {
sourceFile := filepath.Join(l.baseFolder, "daemon/shelltime.service")
if err := os.Symlink(sourceFile, servicePath); err != nil {
Expand All @@ -92,17 +112,17 @@ func (l *LinuxDaemonInstaller) RegisterService() error {

func (l *LinuxDaemonInstaller) StartService() error {
color.Yellow.Println("🔄 Reloading systemd...")
if err := exec.Command("systemctl", "daemon-reload").Run(); err != nil {
if err := exec.Command("systemctl", "--user", "daemon-reload").Run(); err != nil {
return fmt.Errorf("failed to reload systemd: %w", err)
}

color.Yellow.Println("✨ Enabling service...")
if err := exec.Command("systemctl", "enable", "shelltime").Run(); err != nil {
if err := exec.Command("systemctl", "--user", "enable", "shelltime").Run(); err != nil {
return fmt.Errorf("failed to enable service: %w", err)
}

color.Yellow.Println("🚀 Starting service...")
if err := exec.Command("systemctl", "start", "shelltime").Run(); err != nil {
if err := exec.Command("systemctl", "--user", "start", "shelltime").Run(); err != nil {
return fmt.Errorf("failed to start service: %w", err)
}
return nil
Expand All @@ -112,19 +132,27 @@ func (l *LinuxDaemonInstaller) UnregisterService() error {
if l.baseFolder == "" {
return fmt.Errorf("base folder is not set")
}

currentUser, err := user.Current()
if err != nil {
return fmt.Errorf("failed to get current user: %w", err)
}

servicePath := filepath.Join(currentUser.HomeDir, ".config/systemd/user/shelltime.service")

color.Yellow.Println("🛑 Stopping and disabling service if running...")
// Try to stop and disable the service
_ = exec.Command("systemctl", "stop", "shelltime").Run()
_ = exec.Command("systemctl", "disable", "shelltime").Run()
_ = exec.Command("systemctl", "--user", "stop", "shelltime").Run()
_ = exec.Command("systemctl", "--user", "disable", "shelltime").Run()

color.Yellow.Println("🗑 Removing service files...")
// Remove symlink from systemd
if err := os.Remove("/etc/systemd/system/shelltime.service"); err != nil && !os.IsNotExist(err) {
if err := os.Remove(servicePath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed to remove systemd service symlink: %w", err)
}

color.Yellow.Println("🔄 Reloading systemd...")
if err := exec.Command("systemctl", "daemon-reload").Run(); err != nil {
if err := exec.Command("systemctl", "--user", "daemon-reload").Run(); err != nil {
return fmt.Errorf("failed to reload systemd: %w", err)
}

Expand Down
4 changes: 1 addition & 3 deletions model/sys-desc/shelltime.service
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ After=network.target
Type=simple
ExecStart=/usr/local/bin/shelltime-daemon
Restart=always
User=root
Group=root

[Install]
WantedBy=multi-user.target
WantedBy=default.target
Loading