github.com/pmoroney/dnscontrol@v0.2.4-0.20171024134423-fad98f73f44a/build/generate/featureMatrix.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "html/template" 6 "io/ioutil" 7 "sort" 8 9 "github.com/StackExchange/dnscontrol/providers" 10 _ "github.com/StackExchange/dnscontrol/providers/_all" 11 ) 12 13 func generateFeatureMatrix() error { 14 allNames := map[string]bool{} 15 for n := range providers.RegistrarTypes { 16 allNames[n] = true 17 } 18 for n := range providers.DNSProviderTypes { 19 allNames[n] = true 20 } 21 providerTypes := []string{} 22 for n := range allNames { 23 providerTypes = append(providerTypes, n) 24 } 25 sort.Strings(providerTypes) 26 matrix := &FeatureMatrix{ 27 Providers: map[string]FeatureMap{}, 28 Features: []FeatureDef{ 29 {"Official Support", "This means the provider is actively used at Stack Exchange, bugs are more likely to be fixed, and failing integration tests will block a release. See below for details"}, 30 {"Registrar", "The provider has registrar capabilities to set nameservers for zones"}, 31 {"DNS Provider", "Can manage and serve DNS zones"}, 32 {"ALIAS", "Provider supports some kind of ALIAS, ANAME or flattened CNAME record type"}, 33 {"SRV", "Driver has explicitly implemented SRV record management"}, 34 {"PTR", "Provider supports adding PTR records for reverse lookup zones"}, 35 {"CAA", "Provider can manage CAA records"}, 36 {"TLSA", "Provider can manage TLSA records"}, 37 38 {"dual host", "This provider is recommended for use in 'dual hosting' scenarios. Usually this means the provider allows full control over the apex NS records"}, 39 {"create-domains", "This means the provider can automatically create domains that do not currently exist on your account. The 'dnscontrol create-domains' command will initialize any missing domains"}, 40 {"no_purge", "indicates you can use NO_PURGE macro to prevent deleting records not managed by dnscontrol. A few providers that generate the entire zone from scratch have a problem implementing this."}, 41 }, 42 } 43 for _, p := range providerTypes { 44 if p == "NONE" { 45 continue 46 } 47 fm := FeatureMap{} 48 notes := providers.Notes[p] 49 if notes == nil { 50 notes = providers.DocumentationNotes{} 51 } 52 setCap := func(name string, cap providers.Capability) { 53 if notes[cap] != nil { 54 fm[name] = notes[cap] 55 return 56 } 57 fm.SetSimple(name, true, func() bool { return providers.ProviderHasCabability(p, cap) }) 58 } 59 setDoc := func(name string, cap providers.Capability, defaultNo bool) { 60 if notes[cap] != nil { 61 fm[name] = notes[cap] 62 } else if defaultNo { 63 fm[name] = &providers.DocumentationNote{ 64 HasFeature: false, 65 } 66 } 67 } 68 setDoc("Official Support", providers.DocOfficiallySupported, true) 69 fm.SetSimple("Registrar", false, func() bool { return providers.RegistrarTypes[p] != nil }) 70 fm.SetSimple("DNS Provider", false, func() bool { return providers.DNSProviderTypes[p] != nil }) 71 setCap("ALIAS", providers.CanUseAlias) 72 setCap("SRV", providers.CanUseSRV) 73 setCap("PTR", providers.CanUsePTR) 74 setCap("CAA", providers.CanUseCAA) 75 setCap("TLSA", providers.CanUseTLSA) 76 setDoc("dual host", providers.DocDualHost, false) 77 setDoc("create-domains", providers.DocCreateDomains, true) 78 79 // no purge is a freaky double negative 80 cap := providers.CantUseNOPURGE 81 if notes[cap] != nil { 82 fm["no_purge"] = notes[cap] 83 } else { 84 fm.SetSimple("no_purge", false, func() bool { return !providers.ProviderHasCabability(p, cap) }) 85 } 86 matrix.Providers[p] = fm 87 } 88 buf := &bytes.Buffer{} 89 err := tmpl.Execute(buf, matrix) 90 if err != nil { 91 return err 92 } 93 return ioutil.WriteFile("docs/_includes/matrix.html", buf.Bytes(), 0644) 94 } 95 96 type FeatureDef struct { 97 Name, Desc string 98 } 99 type FeatureMap map[string]*providers.DocumentationNote 100 101 func (fm FeatureMap) SetSimple(name string, unknownsAllowed bool, f func() bool) { 102 if f() { 103 fm[name] = &providers.DocumentationNote{HasFeature: true} 104 } else if !unknownsAllowed { 105 fm[name] = &providers.DocumentationNote{HasFeature: false} 106 } 107 } 108 109 type FeatureMatrix struct { 110 Features []FeatureDef 111 Providers map[string]FeatureMap 112 } 113 114 var tmpl = template.Must(template.New("").Funcs(template.FuncMap{ 115 "safe": func(s string) template.HTML { return template.HTML(s) }, 116 }).Parse(` 117 {% comment %} 118 Matrix generated by build/generate/featureMatrix.go. DO NOT HAND EDIT! 119 {% endcomment %}{{$providers := .Providers}} 120 <table class="table-header-rotated"> 121 <thead> 122 <tr> 123 <th></th> 124 {{range $key,$val := $providers}}<th class="rotate"><div><span>{{$key}}</span></div></th> 125 {{end -}} 126 </tr> 127 </thead> 128 <tbody> 129 {{range .Features}}{{$name := .Name}}<tr> 130 <th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="{{.Desc}}">{{$name}}</th> 131 {{range $pname, $features := $providers}}{{$f := index $features $name}}{{if $f -}} 132 <td class="{{if $f.HasFeature}}success{{else if $f.Unimplemented}}info{{else}}danger{{end}}" 133 {{- if $f.Comment}} data-toggle="tooltip" data-container="body" data-placement="top" title="{{$f.Comment}}"{{end}}> 134 {{if $f.Link}}<a href="{{$f.Link}}">{{end}}<i class="fa {{if and $f.Comment (not $f.Unimplemented)}}has-tooltip {{end}} 135 {{- if $f.HasFeature}}fa-check text-success{{else if $f.Unimplemented}}fa-circle-o text-info{{else}}fa-times text-danger{{end}}" aria-hidden="true"></i>{{if $f.Link}}</a>{{end}} 136 </td> 137 {{- else}}<td><i class="fa fa-minus dim"></i></td>{{end}} 138 {{end -}} 139 </tr> 140 {{end -}} 141 </tbody> 142 </table> 143 `))