package main import ( "fmt" "golang.org/x/crypto/ssh" "io" "log" ) func isExitMissingError(err error) bool { _, isExitMissingError := err.(*ssh.ExitMissingError) return isExitMissingError } func deploy(manifest Manifest) error { connectionData, err := provideConnection(manifest) if err != nil { return fmt.Errorf("error while obtaining connection data: %w", err) } sshClient, err := openSshClient(connectionData) if err != nil { return fmt.Errorf("error while opening ssh client: %w", err) } defer sshClient.Close() for _, file := range manifest.Files { sshSession, err := openSshSession(sshClient) if err != nil { return fmt.Errorf("error while opening ssh session: %w", err) } log.Printf("copying file %s to %s with mode 0%d \n", file.Source, file.Target, file.Mode) if err := copyFile(sshSession, file); err != nil && !isExitMissingError(err) { _ = sshSession.Close() return fmt.Errorf("error while copying file %s: %w", file.Target, err) } if err := sshSession.Close(); err != nil && err != io.EOF { return fmt.Errorf("error while closing ssh session: %w", err) } } for _, file := range manifest.Files { if file.Execute { sshSession, err := openSshSession(sshClient) if err != nil { return fmt.Errorf("error while opening ssh session: %w", err) } log.Printf("running command %s\n", file.Target) if err := sshSession.Run(file.Target); err != nil && !isExitMissingError(err) { _ = sshSession.Close() return fmt.Errorf("error while running command: %w", err) } if err := sshSession.Close(); err != nil && err != io.EOF { return fmt.Errorf("error while closing ssh session: %w", err) } } } return nil }