WriteGlobalConfig writes or updates the Host * configuration Creates the block at the END of config file if it doesn't exist
(cfg *HostConfig)
| 30 | // WriteGlobalConfig writes or updates the Host * configuration |
| 31 | // Creates the block at the END of config file if it doesn't exist |
| 32 | func WriteGlobalConfig(cfg *HostConfig) error { |
| 33 | // Mark as global |
| 34 | cfg.Name = "*" |
| 35 | cfg.IsGlobal = true |
| 36 | |
| 37 | // Validate configuration (allows missing Hostname) |
| 38 | if err := ValidateHostConfig(cfg); err != nil { |
| 39 | return fmt.Errorf("invalid global config: %w", err) |
| 40 | } |
| 41 | |
| 42 | // Create backup |
| 43 | backupPath, err := backupSSHConfig() |
| 44 | if err != nil { |
| 45 | return fmt.Errorf("backup failed: %w", err) |
| 46 | } |
| 47 | |
| 48 | // Read current config |
| 49 | lines, err := readSSHConfigLines() |
| 50 | if err != nil { |
| 51 | return err |
| 52 | } |
| 53 | |
| 54 | // Find existing Host * block |
| 55 | start, end, found := findHostBlock(lines, "*") |
| 56 | |
| 57 | // Render new Host * block |
| 58 | newBlock := renderHostBlock(cfg) |
| 59 | newBlockLines := strings.Split(strings.TrimRight(newBlock, "\n"), "\n") |
| 60 | |
| 61 | // Construct updated config |
| 62 | var result []string |
| 63 | if found { |
| 64 | // Replace existing block IN PLACE |
| 65 | result = append(result, lines[:start]...) |
| 66 | result = append(result, newBlockLines...) |
| 67 | result = append(result, lines[end:]...) |
| 68 | } else { |
| 69 | // Append to end of file (SSH best practice: Host * at the end) |
| 70 | result = append(result, lines...) |
| 71 | if len(result) > 0 && result[len(result)-1] != "" { |
| 72 | result = append(result, "") // Blank line before Host * |
| 73 | } |
| 74 | result = append(result, newBlockLines...) |
| 75 | } |
| 76 | |
| 77 | // Write updated config |
| 78 | if err := writeSSHConfigLines(result); err != nil { |
| 79 | // Restore backup on failure |
| 80 | if backupPath != "" { |
| 81 | configPath := sshConfigPath() |
| 82 | _ = copyFile(backupPath, configPath) |
| 83 | } |
| 84 | return err |
| 85 | } |
| 86 | |
| 87 | return nil |
| 88 | } |
| 89 |
no test coverage detected