Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for inline comments #218

Merged
merged 1 commit into from
Jan 29, 2017
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ With the wrapper, `ssh` will *always* be called with an updated `~/.ssh/config`
* Add support for the `AddKeysToAgent` key ([#210](https://github.com/moul/advanced-ssh-config/pull/210)) ([@bachya](https://github.com/bachya))
* OpenBSD support ([#182](https://github.com/moul/advanced-ssh-config/issues/182))
* Improve hostname output in `assh config list` ([#204](https://github.com/moul/advanced-ssh-config/issues/204))
* Support for inline comments ([#34](https://github.com/moul/advanced-ssh-config/issues/34))

[Full commits list](https://github.com/moul/advanced-ssh-config/compare/v2.5.0...master)

Expand Down
46 changes: 41 additions & 5 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ hosts:
User: user-$ENV_VAR_USER-user
LocalCommand: ${ENV_VAR_LOCALCOMMAND:-hello}
IdentityFile: ${NON_EXISTING_ENV_VAR}
Comment: Hello World !

ccc:
HostName: 5.6.7.8
Expand All @@ -38,12 +39,19 @@ hosts:
- BBB
- aaa
ControlMasterMkdir: true
Comment:
- AAA
- BBB

FFF:
Inherits:
- BBB
- eee
- "*.ddd"
Comment: >
First line
Second line
Third line

ggg:
Gateways:
Expand Down Expand Up @@ -133,12 +141,15 @@ func dummyConfig() *Config {
User: "moul",
ProxyCommand: "nc -v 4242",
ControlMasterMkdir: "true",
Comment: []string{"Hello World"},
}
config.Hosts["tonton"] = &Host{
ResolveNameservers: []string{"a.com", "1.2.3.4"},
Comment: []string{"AAA", "BBB"},
}
config.Hosts["toutou"] = &Host{
ResolveCommand: "dig -t %h",
Comment: []string{"First line Second line Third line\n"},
}
config.Hosts["tutu"] = &Host{
Gateways: []string{"titi", "direct", "1.2.3.4"},
Expand Down Expand Up @@ -405,12 +416,19 @@ func TestConfig_JsonString(t *testing.T) {
"User": "moul",
"HostName": "tata",
"ProxyCommand": "nc -v 4242",
"ControlMasterMkdir": "true"
"ControlMasterMkdir": "true",
"Comment": [
"Hello World"
]
},
"tonton": {
"ResolveNameservers": [
"a.com",
"1.2.3.4"
],
"Comment": [
"AAA",
"BBB"
]
},
"toto": {
Expand All @@ -423,7 +441,10 @@ func TestConfig_JsonString(t *testing.T) {
"User": "toto2"
},
"toutou": {
"ResolveCommand": "dig -t %h"
"ResolveCommand": "dig -t %h",
"Comment": [
"First line Second line Third line\n"
]
},
"tutu": {
"Inherits": [
Expand Down Expand Up @@ -611,7 +632,10 @@ func TestConfig_JsonString(t *testing.T) {
"LocalCommand": "${ENV_VAR_LOCALCOMMAND:-hello}",
"Port": "${ENV_VAR_PORT}",
"User": "user-$ENV_VAR_USER-user",
"HostName": "$ENV_VAR_HOSTNAME"
"HostName": "$ENV_VAR_HOSTNAME",
"Comment": [
"Hello World !"
]
},
"ccc": {
"Port": "24",
Expand All @@ -624,13 +648,20 @@ func TestConfig_JsonString(t *testing.T) {
"bbb",
"aaa"
],
"ControlMasterMkdir": "true"
"ControlMasterMkdir": "true",
"Comment": [
"AAA",
"BBB"
]
},
"fff": {
"Inherits": [
"bbb",
"eee",
"*.ddd"
],
"Comment": [
"First line Second line Third line\n"
]
},
"ggg": {
Expand Down Expand Up @@ -1245,7 +1276,7 @@ func TestConfig_GetHostSafe(t *testing.T) {
func TestConfig_String(t *testing.T) {
Convey("Testing Config.String", t, func() {
config := dummyConfig()
So(config.String(), ShouldEqual, `{"hosts":{"*.ddd":{"PasswordAuthentication":"yes","HostName":"1.3.5.7"},"empty":{},"nnn":{"Port":"26","Inherits":["mmm"]},"ooo1":{"Port":"23","Aliases":["ooo11","ooo12"]},"ooo2":{"Port":"24","Aliases":["ooo21","ooo22"]},"tata":{"Inherits":["tutu","titi","toto","tutu"]},"titi":{"Port":"23","User":"moul","HostName":"tata","ProxyCommand":"nc -v 4242","ControlMasterMkdir":"true"},"tonton":{"ResolveNameservers":["a.com","1.2.3.4"]},"toto":{"HostName":"1.2.3.4"},"toto[1-5]toto":{"User":"toto1"},"toto[7-9]toto":{"User":"toto2"},"toutou":{"ResolveCommand":"dig -t %h"},"tutu":{"Inherits":["toto","tutu","*.ddd"],"Gateways":["titi","direct","1.2.3.4"]},"zzz":{"AddressFamily":"any","AskPassGUI":"yes","BatchMode":"no","CanonicalDomains":"42.am","CanonicalizeFallbackLocal":"no","CanonicalizeHostname":"yes","CanonicalizeMaxDots":"1","CanonicalizePermittedCNAMEs":"*.a.example.com:*.b.example.com:*.c.example.com","ChallengeResponseAuthentication":"yes","CheckHostIP":"yes","Cipher":"blowfish","Ciphers":["aes128-ctr,aes192-ctr","aes256-ctr"],"ClearAllForwardings":"yes","Compression":"yes","CompressionLevel":6,"ConnectionAttempts":"1","ConnectTimeout":10,"ControlMaster":"yes","ControlPath":"/tmp/%L-%l-%n-%p-%u-%r-%C-%h","ControlPersist":"yes","DynamicForward":["0.0.0.0:4242","0.0.0.0:4343"],"EnableSSHKeysign":"yes","EscapeChar":"~","ExitOnForwardFailure":"yes","FingerprintHash":"sha256","ForwardAgent":"yes","ForwardX11":"yes","ForwardX11Timeout":42,"ForwardX11Trusted":"yes","GatewayPorts":"yes","GlobalKnownHostsFile":["/etc/ssh/ssh_known_hosts","/tmp/ssh_known_hosts"],"GSSAPIAuthentication":"no","GSSAPIClientIdentity":"moul","GSSAPIDelegateCredentials":"no","GSSAPIKeyExchange":"no","GSSAPIRenewalForcesRekey":"no","GSSAPIServerIdentity":"gssapi.example.com","GSSAPITrustDns":"no","HashKnownHosts":"no","HostbasedAuthentication":"no","HostbasedKeyTypes":"*","HostKeyAlgorithms":"ecdsa-sha2-nistp256-cert-v01@openssh.com","HostKeyAlias":"z","IdentitiesOnly":"yes","IdentityFile":["~/.ssh/identity","~/.ssh/identity2"],"IgnoreUnknown":"testtest","IPQoS":["lowdelay","highdelay"],"KbdInteractiveAuthentication":"yes","KbdInteractiveDevices":["bsdauth","test"],"KexAlgorithms":["curve25519-sha256@libssh.org","test"],"KeychainIntegration":"yes","LocalCommand":"echo %h \u003e /tmp/logs","LocalForward":["0.0.0.0:1234","0.0.0.0:1235"],"LogLevel":"DEBUG3","MACs":["umac-64-etm@openssh.com,umac-128-etm@openssh.com","test"],"Match":"all","NoHostAuthenticationForLocalhost":"yes","NumberOfPasswordPrompts":"3","PasswordAuthentication":"yes","PermitLocalCommand":"yes","PKCS11Provider":"/a/b/c/pkcs11.so","Port":"22","PreferredAuthentications":"gssapi-with-mic,hostbased,publickey","Protocol":["2","3"],"ProxyUseFdpass":"no","PubkeyAuthentication":"yes","RekeyLimit":"default none","RemoteForward":["0.0.0.0:1234","0.0.0.0:1255"],"RequestTTY":"yes","RevokedHostKeys":"/a/revoked-keys","RhostsRSAAuthentication":"no","RSAAuthentication":"yes","SendEnv":["CUSTOM_*,TEST","TEST2"],"ServerAliveCountMax":3,"StreamLocalBindMask":"0177","StreamLocalBindUnlink":"no","StrictHostKeyChecking":"ask","TCPKeepAlive":"yes","Tunnel":"yes","TunnelDevice":"any:any","UpdateHostKeys":"ask","UseKeychain":"no","UsePrivilegedPort":"no","User":"moul","UserKnownHostsFile":["~/.ssh/known_hosts ~/.ssh/known_hosts2","/tmp/known_hosts"],"VerifyHostKeyDNS":"no","VisualHostKey":"yes","XAuthLocation":"xauth","HostName":"zzz.com","ProxyCommand":"nc %h %p"}},"templates":{"mmm":{"Port":"25","User":"mmmm","HostName":"5.5.5.5","Inherits":["tata"]}},"defaults":{"Port":"22","User":"root"},"asshknownhostfile":"~/.ssh/assh_known_hosts"}`)
So(config.String(), ShouldEqual, `{"hosts":{"*.ddd":{"PasswordAuthentication":"yes","HostName":"1.3.5.7"},"empty":{},"nnn":{"Port":"26","Inherits":["mmm"]},"ooo1":{"Port":"23","Aliases":["ooo11","ooo12"]},"ooo2":{"Port":"24","Aliases":["ooo21","ooo22"]},"tata":{"Inherits":["tutu","titi","toto","tutu"]},"titi":{"Port":"23","User":"moul","HostName":"tata","ProxyCommand":"nc -v 4242","ControlMasterMkdir":"true","Comment":["Hello World"]},"tonton":{"ResolveNameservers":["a.com","1.2.3.4"],"Comment":["AAA","BBB"]},"toto":{"HostName":"1.2.3.4"},"toto[1-5]toto":{"User":"toto1"},"toto[7-9]toto":{"User":"toto2"},"toutou":{"ResolveCommand":"dig -t %h","Comment":["First line Second line Third line\n"]},"tutu":{"Inherits":["toto","tutu","*.ddd"],"Gateways":["titi","direct","1.2.3.4"]},"zzz":{"AddressFamily":"any","AskPassGUI":"yes","BatchMode":"no","CanonicalDomains":"42.am","CanonicalizeFallbackLocal":"no","CanonicalizeHostname":"yes","CanonicalizeMaxDots":"1","CanonicalizePermittedCNAMEs":"*.a.example.com:*.b.example.com:*.c.example.com","ChallengeResponseAuthentication":"yes","CheckHostIP":"yes","Cipher":"blowfish","Ciphers":["aes128-ctr,aes192-ctr","aes256-ctr"],"ClearAllForwardings":"yes","Compression":"yes","CompressionLevel":6,"ConnectionAttempts":"1","ConnectTimeout":10,"ControlMaster":"yes","ControlPath":"/tmp/%L-%l-%n-%p-%u-%r-%C-%h","ControlPersist":"yes","DynamicForward":["0.0.0.0:4242","0.0.0.0:4343"],"EnableSSHKeysign":"yes","EscapeChar":"~","ExitOnForwardFailure":"yes","FingerprintHash":"sha256","ForwardAgent":"yes","ForwardX11":"yes","ForwardX11Timeout":42,"ForwardX11Trusted":"yes","GatewayPorts":"yes","GlobalKnownHostsFile":["/etc/ssh/ssh_known_hosts","/tmp/ssh_known_hosts"],"GSSAPIAuthentication":"no","GSSAPIClientIdentity":"moul","GSSAPIDelegateCredentials":"no","GSSAPIKeyExchange":"no","GSSAPIRenewalForcesRekey":"no","GSSAPIServerIdentity":"gssapi.example.com","GSSAPITrustDns":"no","HashKnownHosts":"no","HostbasedAuthentication":"no","HostbasedKeyTypes":"*","HostKeyAlgorithms":"ecdsa-sha2-nistp256-cert-v01@openssh.com","HostKeyAlias":"z","IdentitiesOnly":"yes","IdentityFile":["~/.ssh/identity","~/.ssh/identity2"],"IgnoreUnknown":"testtest","IPQoS":["lowdelay","highdelay"],"KbdInteractiveAuthentication":"yes","KbdInteractiveDevices":["bsdauth","test"],"KexAlgorithms":["curve25519-sha256@libssh.org","test"],"KeychainIntegration":"yes","LocalCommand":"echo %h \u003e /tmp/logs","LocalForward":["0.0.0.0:1234","0.0.0.0:1235"],"LogLevel":"DEBUG3","MACs":["umac-64-etm@openssh.com,umac-128-etm@openssh.com","test"],"Match":"all","NoHostAuthenticationForLocalhost":"yes","NumberOfPasswordPrompts":"3","PasswordAuthentication":"yes","PermitLocalCommand":"yes","PKCS11Provider":"/a/b/c/pkcs11.so","Port":"22","PreferredAuthentications":"gssapi-with-mic,hostbased,publickey","Protocol":["2","3"],"ProxyUseFdpass":"no","PubkeyAuthentication":"yes","RekeyLimit":"default none","RemoteForward":["0.0.0.0:1234","0.0.0.0:1255"],"RequestTTY":"yes","RevokedHostKeys":"/a/revoked-keys","RhostsRSAAuthentication":"no","RSAAuthentication":"yes","SendEnv":["CUSTOM_*,TEST","TEST2"],"ServerAliveCountMax":3,"StreamLocalBindMask":"0177","StreamLocalBindUnlink":"no","StrictHostKeyChecking":"ask","TCPKeepAlive":"yes","Tunnel":"yes","TunnelDevice":"any:any","UpdateHostKeys":"ask","UseKeychain":"no","UsePrivilegedPort":"no","User":"moul","UserKnownHostsFile":["~/.ssh/known_hosts ~/.ssh/known_hosts2","/tmp/known_hosts"],"VerifyHostKeyDNS":"no","VisualHostKey":"yes","XAuthLocation":"xauth","HostName":"zzz.com","ProxyCommand":"nc %h %p"}},"templates":{"mmm":{"Port":"25","User":"mmmm","HostName":"5.5.5.5","Inherits":["tata"]}},"defaults":{"Port":"22","User":"root"},"asshknownhostfile":"~/.ssh/assh_known_hosts"}`)
})
}

Expand Down Expand Up @@ -1283,6 +1314,7 @@ Host nnn
# ControlMasterMkdir: true
# Inherits: [mmm]
# Gateways: [titi, direct, 1.2.3.4]
# Comment: [Hello World]

Host ooo1
Port 23
Expand Down Expand Up @@ -1317,15 +1349,18 @@ Host tata
# ControlMasterMkdir: true
# Inherits: [tutu, titi, toto, tutu]
# Gateways: [titi, direct, 1.2.3.4]
# Comment: [Hello World]

Host titi
Port 23
User moul
# ProxyCommand nc -v 4242
# HostName: tata
# ControlMasterMkdir: true
# Comment: [Hello World]

Host tonton
# Comment: [AAA, BBB]
# ResolveNameservers: [a.com, 1.2.3.4]

Host toto
Expand All @@ -1352,6 +1387,7 @@ Host toto7toto
# KnownHostOf: toto[7-9]toto

Host toutou
# Comment: [First line Second line Third line]
# ResolveCommand: dig -t %h

Host tutu
Expand Down
19 changes: 13 additions & 6 deletions pkg/config/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,20 @@ func sliceComment(name string, slice []string) string {
bundles = append(bundles, []string{})

for _, item := range slice {
if curLen+len(item) >= maxLength {
bundleIdx++
bundles = append(bundles, []string{})
curLen = 0
for _, line := range strings.Split(item, "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}

if curLen+len(line) >= maxLength {
bundleIdx++
bundles = append(bundles, []string{})
curLen = 0
}
bundles[bundleIdx] = append(bundles[bundleIdx], line)
curLen += len(line) + 2
}
bundles[bundleIdx] = append(bundles[bundleIdx], item)
curLen += len(item) + 2
}

ret := []string{}
Expand Down
9 changes: 9 additions & 0 deletions pkg/config/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ type Host struct {
ControlMasterMkdir string `yaml:"controlmastermkdir,omitempty,flow" json:"ControlMasterMkdir,omitempty"`
Aliases composeyaml.Stringorslice `yaml:"aliases,omitempty,flow" json:"Aliases,omitempty"`
Hooks *HostHooks `yaml:"hooks,omitempty,flow" json:"Hooks,omitempty"`
Comment composeyaml.Stringorslice `yaml:"comment,omitempty,flow" json:"Comment,omitempty"`

// private assh fields
knownHosts []string
Expand Down Expand Up @@ -488,6 +489,7 @@ func (h *Host) Options() OptionsList {
//ResolveCommand
//ControlMasterMkdir
//Aliases
//Comment
//Hooks

// private assh fields
Expand Down Expand Up @@ -1016,6 +1018,10 @@ func (h *Host) ApplyDefaults(defaults *Host) {
h.Aliases = defaults.Aliases
}

if len(h.Comment) == 0 {
h.Comment = defaults.Comment
}

if h.Hooks == nil {
h.Hooks = defaults.Hooks
if h.Hooks == nil {
Expand Down Expand Up @@ -1360,6 +1366,9 @@ func (h *Host) WriteSSHConfigTo(w io.Writer) error {
if len(h.Gateways) > 0 {
fmt.Fprint(w, sliceComment("Gateways", h.Gateways))
}
if len(h.Comment) > 0 {
fmt.Fprint(w, sliceComment("Comment", h.Comment))
}
if len(h.Aliases) > 0 {
if aliasIdx == 0 {
fmt.Fprint(w, sliceComment("Aliases", h.Aliases))
Expand Down