diff --git a/.gitignore b/.gitignore index f55663a..009ce25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ result ^qvm vendor/ +/qvm diff --git a/cmd/qvm/run.go b/cmd/qvm/run.go index bfa0f64..4f8febb 100644 --- a/cmd/qvm/run.go +++ b/cmd/qvm/run.go @@ -16,14 +16,20 @@ import ( ) var runCmd = &cobra.Command{ - Use: "run [args...]", + Use: "run [command] [args...]", Short: "Run a command in the VM workspace", Long: `Execute a command in the VM at the current directory. The current directory is automatically registered as a workspace -and mounted into the VM. The command runs in the mounted workspace.`, - Args: cobra.MinimumNArgs(1), +and mounted into the VM. The command runs in the mounted workspace. + +If no command is provided, starts an interactive zsh shell.`, + Args: cobra.ArbitraryArgs, Run: func(cmd *cobra.Command, args []string) { + // Default to zsh if no command provided + if len(args) == 0 { + args = []string{"zsh"} + } cwd, err := os.Getwd() if err != nil { logging.Error(fmt.Sprintf("Failed to get current directory: %v", err)) @@ -50,21 +56,50 @@ and mounted into the VM. The command runs in the mounted workspace.`, os.Exit(1) } + cfg, err := config.Load() + if err != nil { + logging.Error(err.Error()) + os.Exit(1) + } + wasRunning := vm.IsRunning() if !wasRunning { logging.Info("VM is not running, starting it...") - cfg, err := config.Load() - if err != nil { - logging.Error(err.Error()) - os.Exit(1) - } - startResult := vm.Start(cfg, reg) if startResult.IsError() { logging.Error(startResult.Error().Error()) os.Exit(1) } + } else { + statusResult := vm.Status() + if statusResult.IsError() { + logging.Error(statusResult.Error().Error()) + os.Exit(1) + } + status := statusResult.MustGet() + + checkCmd := exec.Command("sshpass", "-p", "root", "ssh", + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + "-o", "LogLevel=ERROR", + "-p", strconv.Itoa(status.SSHPort), + "root@localhost", + fmt.Sprintf("test -d /sys/bus/virtio/drivers/9pnet_virtio/*/mount_tag && grep -q 'ws_%s' /sys/bus/virtio/drivers/9pnet_virtio/*/mount_tag 2>/dev/null", ws.Hash)) + + if checkCmd.Run() != nil { + logging.Info("Workspace not available in running VM, restarting VM...") + stopResult := vm.Stop() + if stopResult.IsError() { + logging.Error(stopResult.Error().Error()) + os.Exit(1) + } + startResult := vm.Start(cfg, reg) + if startResult.IsError() { + logging.Error(startResult.Error().Error()) + os.Exit(1) + } + } } statusResult := vm.Status() @@ -74,8 +109,8 @@ and mounted into the VM. The command runs in the mounted workspace.`, } status := statusResult.MustGet() - remoteCmd := fmt.Sprintf("mkdir -p '%s' && mount -t 9p ws_%s '%s' -o trans=virtio,version=9p2000.L,msize=104857600 2>/dev/null || true && cd '%s' && %s", - ws.GuestPath, ws.Hash, ws.GuestPath, ws.GuestPath, strings.Join(args, " ")) + remoteCmd := fmt.Sprintf("mkdir -p '%s' && (mountpoint -q '%s' || mount -t 9p ws_%s '%s' -o trans=virtio,version=9p2000.L,msize=104857600) && cd '%s' && %s", + ws.GuestPath, ws.GuestPath, ws.Hash, ws.GuestPath, ws.GuestPath, strings.Join(args, " ")) sshArgs := []string{ "-p", "root",