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  `))