Browse Source

ipn: use cmd/cloner for Prefs.Clone

Also, make cmd/cloner's top-level "func Clone" generation opt-in.

Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 5 years ago
parent
commit
7c8ca28c74
4 changed files with 75 additions and 29 deletions
  1. 21 18
      cmd/cloner/cloner.go
  2. 2 10
      ipn/prefs.go
  3. 51 0
      ipn/prefs_clone.go
  4. 1 1
      tailcfg/tailcfg.go

+ 21 - 18
cmd/cloner/cloner.go

@@ -33,6 +33,7 @@ var (
 	flagTypes     = flag.String("type", "", "comma-separated list of types; required")
 	flagOutput    = flag.String("output", "", "output file; required")
 	flagBuildTags = flag.String("tags", "", "compiler build tags to apply")
+	flagCloneFunc = flag.Bool("clonefunc", false, "add a top-level Clone func")
 )
 
 func main() {
@@ -98,25 +99,27 @@ func main() {
 	w := func(format string, args ...interface{}) {
 		fmt.Fprintf(buf, format+"\n", args...)
 	}
-	w("// Clone duplicates src into dst and reports whether it succeeded.")
-	w("// To succeed, <src, dst> must be of types <*T, *T> or <*T, **T>,")
-	w("// where T is one of %s.", *flagTypes)
-	w("func Clone(dst, src interface{}) bool {")
-	w("	switch src := src.(type) {")
-	for _, typeName := range typeNames {
-		w("	case *%s:", typeName)
-		w("		switch dst := dst.(type) {")
-		w("		case *%s:", typeName)
-		w("			*dst = *src.Clone()")
-		w("			return true")
-		w("		case **%s:", typeName)
-		w("			*dst = src.Clone()")
-		w("			return true")
-		w("		}")
+	if *flagCloneFunc {
+		w("// Clone duplicates src into dst and reports whether it succeeded.")
+		w("// To succeed, <src, dst> must be of types <*T, *T> or <*T, **T>,")
+		w("// where T is one of %s.", *flagTypes)
+		w("func Clone(dst, src interface{}) bool {")
+		w("	switch src := src.(type) {")
+		for _, typeName := range typeNames {
+			w("	case *%s:", typeName)
+			w("		switch dst := dst.(type) {")
+			w("		case *%s:", typeName)
+			w("			*dst = *src.Clone()")
+			w("			return true")
+			w("		case **%s:", typeName)
+			w("			*dst = src.Clone()")
+			w("			return true")
+			w("		}")
+		}
+		w("	}")
+		w("	return false")
+		w("}")
 	}
-	w("	}")
-	w("	return false")
-	w("}")
 
 	contents := new(bytes.Buffer)
 	fmt.Fprintf(contents, header, *flagTypes, pkg.Name)

+ 2 - 10
ipn/prefs.go

@@ -20,6 +20,8 @@ import (
 	"tailscale.com/wgengine/router"
 )
 
+//go:generate go run tailscale.com/cmd/cloner -type=Prefs -output=prefs_clone.go
+
 // Prefs are the user modifiable settings of the Tailscale node agent.
 type Prefs struct {
 	// ControlURL is the URL of the control server to use.
@@ -261,16 +263,6 @@ func PrefsFromBytes(b []byte, enforceDefaults bool) (*Prefs, error) {
 	return p, err
 }
 
-// Clone returns a deep copy of p.
-func (p *Prefs) Clone() *Prefs {
-	// TODO: write a faster/non-Fatal-y Clone implementation?
-	p2, err := PrefsFromBytes(p.ToBytes(), false)
-	if err != nil {
-		log.Fatalf("Prefs was uncopyable: %v\n", err)
-	}
-	return p2
-}
-
 // LoadPrefs loads a legacy relaynode config file into Prefs
 // with sensible migration defaults set.
 func LoadPrefs(filename string) (*Prefs, error) {

+ 51 - 0
ipn/prefs_clone.go

@@ -0,0 +1,51 @@
+// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by tailscale.com/cmd/cloner -type Prefs; DO NOT EDIT.
+
+package ipn
+
+import (
+	"github.com/tailscale/wireguard-go/wgcfg"
+	"tailscale.com/control/controlclient"
+	"tailscale.com/wgengine/router"
+)
+
+// Clone makes a deep copy of Prefs.
+// The result aliases no memory with the original.
+func (src *Prefs) Clone() *Prefs {
+	if src == nil {
+		return nil
+	}
+	dst := new(Prefs)
+	*dst = *src
+	dst.AdvertiseTags = append(src.AdvertiseTags[:0:0], src.AdvertiseTags...)
+	dst.AdvertiseRoutes = append(src.AdvertiseRoutes[:0:0], src.AdvertiseRoutes...)
+	if dst.Persist != nil {
+		dst.Persist = new(controlclient.Persist)
+		*dst.Persist = *src.Persist
+	}
+	return dst
+}
+
+// A compilation failure here means this code must be regenerated, with command:
+//   tailscale.com/cmd/cloner -type Prefs
+var _PrefsNeedsRegeneration = Prefs(struct {
+	ControlURL       string
+	RouteAll         bool
+	AllowSingleHosts bool
+	CorpDNS          bool
+	WantRunning      bool
+	ShieldsUp        bool
+	AdvertiseTags    []string
+	Hostname         string
+	OSVersion        string
+	DeviceModel      string
+	NotepadURLs      bool
+	ForceDaemon      bool
+	AdvertiseRoutes  []wgcfg.CIDR
+	NoSNAT           bool
+	NetfilterMode    router.NetfilterMode
+	Persist          *controlclient.Persist
+}{})

+ 1 - 1
tailcfg/tailcfg.go

@@ -4,7 +4,7 @@
 
 package tailcfg
 
-//go:generate go run tailscale.com/cmd/cloner -type=User,Node,Hostinfo,NetInfo,Group,Role,Capability,Login,DNSConfig,RegisterResponse -output=tailcfg_clone.go
+//go:generate go run tailscale.com/cmd/cloner --type=User,Node,Hostinfo,NetInfo,Group,Role,Capability,Login,DNSConfig,RegisterResponse --clonefunc=true --output=tailcfg_clone.go
 
 import (
 	"bytes"