github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/runtime/deep_copy_generator.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package runtime 18 19 import ( 20 "fmt" 21 "io" 22 "path" 23 "reflect" 24 "sort" 25 "strings" 26 27 "k8s.io/kubernetes/pkg/conversion" 28 "k8s.io/kubernetes/pkg/util/sets" 29 ) 30 31 // TODO(wojtek-t): As suggested in #8320, we should consider the strategy 32 // to first do the shallow copy and then recurse into things that need a 33 // deep copy (maps, pointers, slices). That sort of copy function would 34 // need one parameter - a pointer to the thing it's supposed to expand, 35 // and it would involve a lot less memory copying. 36 type DeepCopyGenerator interface { 37 // Adds a type to a generator. 38 // If the type is non-struct, it will return an error, otherwise deep-copy 39 // functions for this type and all nested types will be generated. 40 AddType(inType reflect.Type) error 41 42 // ReplaceType registers a type that should be used instead of the type 43 // with the provided pkgPath and name. 44 ReplaceType(pkgPath, name string, in interface{}) 45 46 // AddImport registers a package name with the generator and returns its 47 // short name. 48 AddImport(pkgPath string) string 49 50 // RepackImports creates a stable ordering of import short names 51 RepackImports() 52 53 // Writes all imports that are necessary for deep-copy function and 54 // their registration. 55 WriteImports(w io.Writer) error 56 57 // Writes deel-copy functions for all types added via AddType() method 58 // and their nested types. 59 WriteDeepCopyFunctions(w io.Writer) error 60 61 // Writes an init() function that registers all the generated deep-copy 62 // functions. 63 RegisterDeepCopyFunctions(w io.Writer, pkg string) error 64 65 // When generating code, all references to "pkg" package name will be 66 // replaced with "overwrite". It is used mainly to replace references 67 // to name of the package in which the code will be created with empty 68 // string. 69 OverwritePackage(pkg, overwrite string) 70 } 71 72 func NewDeepCopyGenerator(scheme *conversion.Scheme, targetPkg string, include sets.String) DeepCopyGenerator { 73 g := &deepCopyGenerator{ 74 scheme: scheme, 75 targetPkg: targetPkg, 76 copyables: make(map[reflect.Type]bool), 77 imports: make(map[string]string), 78 shortImports: make(map[string]string), 79 pkgOverwrites: make(map[string]string), 80 replace: make(map[pkgPathNamePair]reflect.Type), 81 include: include, 82 } 83 g.targetPackage(targetPkg) 84 g.AddImport("k8s.io/kubernetes/pkg/conversion") 85 return g 86 } 87 88 type pkgPathNamePair struct { 89 PkgPath string 90 Name string 91 } 92 93 type deepCopyGenerator struct { 94 scheme *conversion.Scheme 95 targetPkg string 96 copyables map[reflect.Type]bool 97 // map of package names to shortname 98 imports map[string]string 99 // map of short names to package names 100 shortImports map[string]string 101 pkgOverwrites map[string]string 102 replace map[pkgPathNamePair]reflect.Type 103 include sets.String 104 } 105 106 func (g *deepCopyGenerator) addImportByPath(pkg string) string { 107 if name, ok := g.imports[pkg]; ok { 108 return name 109 } 110 name := path.Base(pkg) 111 if _, ok := g.shortImports[name]; !ok { 112 g.imports[pkg] = name 113 g.shortImports[name] = pkg 114 return name 115 } 116 if dirname := path.Base(path.Dir(pkg)); len(dirname) > 0 { 117 name = dirname + name 118 if _, ok := g.shortImports[name]; !ok { 119 g.imports[pkg] = name 120 g.shortImports[name] = pkg 121 return name 122 } 123 if subdirname := path.Base(path.Dir(path.Dir(pkg))); len(subdirname) > 0 { 124 name = subdirname + name 125 if _, ok := g.shortImports[name]; !ok { 126 g.imports[pkg] = name 127 g.shortImports[name] = pkg 128 return name 129 } 130 } 131 } 132 for i := 2; i < 100; i++ { 133 generatedName := fmt.Sprintf("%s%d", name, i) 134 if _, ok := g.shortImports[generatedName]; !ok { 135 g.imports[pkg] = generatedName 136 g.shortImports[generatedName] = pkg 137 return generatedName 138 } 139 } 140 panic(fmt.Sprintf("unable to find a unique name for the package path %q: %v", pkg, g.shortImports)) 141 } 142 143 func (g *deepCopyGenerator) targetPackage(pkg string) { 144 g.imports[pkg] = "" 145 g.shortImports[""] = pkg 146 } 147 148 func (g *deepCopyGenerator) addAllRecursiveTypes(inType reflect.Type) error { 149 if _, found := g.copyables[inType]; found { 150 return nil 151 } 152 switch inType.Kind() { 153 case reflect.Map: 154 if err := g.addAllRecursiveTypes(inType.Key()); err != nil { 155 return err 156 } 157 if err := g.addAllRecursiveTypes(inType.Elem()); err != nil { 158 return err 159 } 160 case reflect.Slice, reflect.Ptr: 161 if err := g.addAllRecursiveTypes(inType.Elem()); err != nil { 162 return err 163 } 164 case reflect.Interface: 165 g.addImportByPath(inType.PkgPath()) 166 return nil 167 case reflect.Struct: 168 g.addImportByPath(inType.PkgPath()) 169 found := false 170 for s := range g.include { 171 if strings.HasPrefix(inType.PkgPath(), s) { 172 found = true 173 break 174 } 175 } 176 if !found { 177 return nil 178 } 179 for i := 0; i < inType.NumField(); i++ { 180 inField := inType.Field(i) 181 if err := g.addAllRecursiveTypes(inField.Type); err != nil { 182 return err 183 } 184 } 185 g.copyables[inType] = true 186 default: 187 // Simple types should be copied automatically. 188 } 189 return nil 190 } 191 192 func (g *deepCopyGenerator) AddImport(pkg string) string { 193 return g.addImportByPath(pkg) 194 } 195 196 // ReplaceType registers a replacement type to be used instead of the named type 197 func (g *deepCopyGenerator) ReplaceType(pkgPath, name string, t interface{}) { 198 g.replace[pkgPathNamePair{pkgPath, name}] = reflect.TypeOf(t) 199 } 200 201 func (g *deepCopyGenerator) AddType(inType reflect.Type) error { 202 if inType.Kind() != reflect.Struct { 203 return fmt.Errorf("non-struct copies are not supported") 204 } 205 return g.addAllRecursiveTypes(inType) 206 } 207 208 func (g *deepCopyGenerator) RepackImports() { 209 var packages []string 210 for key := range g.imports { 211 packages = append(packages, key) 212 } 213 sort.Strings(packages) 214 g.imports = make(map[string]string) 215 g.shortImports = make(map[string]string) 216 217 g.targetPackage(g.targetPkg) 218 for _, pkg := range packages { 219 g.addImportByPath(pkg) 220 } 221 } 222 223 func (g *deepCopyGenerator) WriteImports(w io.Writer) error { 224 var packages []string 225 for key := range g.imports { 226 packages = append(packages, key) 227 } 228 sort.Strings(packages) 229 230 buffer := newBuffer() 231 indent := 0 232 buffer.addLine("import (\n", indent) 233 for _, importPkg := range packages { 234 if len(importPkg) == 0 { 235 continue 236 } 237 if len(g.imports[importPkg]) == 0 { 238 continue 239 } 240 buffer.addLine(fmt.Sprintf("%s \"%s\"\n", g.imports[importPkg], importPkg), indent+1) 241 } 242 buffer.addLine(")\n", indent) 243 buffer.addLine("\n", indent) 244 if err := buffer.flushLines(w); err != nil { 245 return err 246 } 247 return nil 248 } 249 250 type byPkgAndName []reflect.Type 251 252 func (s byPkgAndName) Len() int { 253 return len(s) 254 } 255 256 func (s byPkgAndName) Less(i, j int) bool { 257 fullNameI := s[i].PkgPath() + "/" + s[i].Name() 258 fullNameJ := s[j].PkgPath() + "/" + s[j].Name() 259 return fullNameI < fullNameJ 260 } 261 262 func (s byPkgAndName) Swap(i, j int) { 263 s[i], s[j] = s[j], s[i] 264 } 265 266 func (g *deepCopyGenerator) nameForType(inType reflect.Type) string { 267 switch inType.Kind() { 268 case reflect.Slice: 269 return fmt.Sprintf("[]%s", g.typeName(inType.Elem())) 270 case reflect.Ptr: 271 return fmt.Sprintf("*%s", g.typeName(inType.Elem())) 272 case reflect.Map: 273 if len(inType.Name()) == 0 { 274 return fmt.Sprintf("map[%s]%s", g.typeName(inType.Key()), g.typeName(inType.Elem())) 275 } 276 fallthrough 277 default: 278 pkg, name := inType.PkgPath(), inType.Name() 279 if len(name) == 0 && inType.Kind() == reflect.Struct { 280 return "struct{}" 281 } 282 if len(pkg) == 0 { 283 // Default package. 284 return name 285 } 286 if val, found := g.pkgOverwrites[pkg]; found { 287 pkg = val 288 } 289 if len(pkg) == 0 { 290 return name 291 } 292 short := g.addImportByPath(pkg) 293 if len(short) > 0 { 294 return fmt.Sprintf("%s.%s", short, name) 295 } 296 return name 297 } 298 } 299 300 func (g *deepCopyGenerator) typeName(inType reflect.Type) string { 301 if t, ok := g.replace[pkgPathNamePair{inType.PkgPath(), inType.Name()}]; ok { 302 return g.nameForType(t) 303 } 304 return g.nameForType(inType) 305 } 306 307 func (g *deepCopyGenerator) deepCopyFunctionName(inType reflect.Type) string { 308 funcNameFormat := "deepCopy_%s_%s" 309 inPkg := packageForName(inType) 310 funcName := fmt.Sprintf(funcNameFormat, inPkg, inType.Name()) 311 return funcName 312 } 313 314 func (g *deepCopyGenerator) writeHeader(b *buffer, inType reflect.Type, indent int) { 315 format := "func %s(in %s, out *%s, c *conversion.Cloner) error {\n" 316 stmt := fmt.Sprintf(format, g.deepCopyFunctionName(inType), g.typeName(inType), g.typeName(inType)) 317 b.addLine(stmt, indent) 318 } 319 320 func (g *deepCopyGenerator) writeFooter(b *buffer, indent int) { 321 b.addLine("return nil\n", indent+1) 322 b.addLine("}\n", indent) 323 } 324 325 func (g *deepCopyGenerator) WriteDeepCopyFunctions(w io.Writer) error { 326 var keys []reflect.Type 327 for key := range g.copyables { 328 keys = append(keys, key) 329 } 330 sort.Sort(byPkgAndName(keys)) 331 332 buffer := newBuffer() 333 indent := 0 334 for _, inType := range keys { 335 if err := g.writeDeepCopyForType(buffer, inType, indent); err != nil { 336 return err 337 } 338 buffer.addLine("\n", 0) 339 } 340 if err := buffer.flushLines(w); err != nil { 341 return err 342 } 343 return nil 344 } 345 346 func (g *deepCopyGenerator) writeDeepCopyForMap(b *buffer, inField reflect.StructField, indent int) error { 347 ifFormat := "if in.%s != nil {\n" 348 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 349 b.addLine(ifStmt, indent) 350 newFormat := "out.%s = make(%s)\n" 351 newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type)) 352 b.addLine(newStmt, indent+1) 353 forFormat := "for key, val := range in.%s {\n" 354 forStmt := fmt.Sprintf(forFormat, inField.Name) 355 b.addLine(forStmt, indent+1) 356 357 switch inField.Type.Key().Kind() { 358 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct: 359 return fmt.Errorf("not supported") 360 default: 361 switch inField.Type.Elem().Kind() { 362 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct: 363 if _, found := g.copyables[inField.Type.Elem()]; found { 364 newFormat := "newVal := new(%s)\n" 365 newStmt := fmt.Sprintf(newFormat, g.typeName(inField.Type.Elem())) 366 b.addLine(newStmt, indent+2) 367 assignFormat := "if err := %s(val, newVal, c); err != nil {\n" 368 funcName := g.deepCopyFunctionName(inField.Type.Elem()) 369 assignStmt := fmt.Sprintf(assignFormat, funcName) 370 b.addLine(assignStmt, indent+2) 371 b.addLine("return err\n", indent+3) 372 b.addLine("}\n", indent+2) 373 setFormat := "out.%s[key] = *newVal\n" 374 setStmt := fmt.Sprintf(setFormat, inField.Name) 375 b.addLine(setStmt, indent+2) 376 } else { 377 ifStmt := "if newVal, err := c.DeepCopy(val); err != nil {\n" 378 b.addLine(ifStmt, indent+2) 379 b.addLine("return err\n", indent+3) 380 b.addLine("} else {\n", indent+2) 381 assignFormat := "out.%s[key] = newVal.(%s)\n" 382 assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type.Elem())) 383 b.addLine(assignStmt, indent+3) 384 b.addLine("}\n", indent+2) 385 } 386 default: 387 assignFormat := "out.%s[key] = val\n" 388 assignStmt := fmt.Sprintf(assignFormat, inField.Name) 389 b.addLine(assignStmt, indent+2) 390 } 391 } 392 b.addLine("}\n", indent+1) 393 b.addLine("} else {\n", indent) 394 elseFormat := "out.%s = nil\n" 395 elseStmt := fmt.Sprintf(elseFormat, inField.Name) 396 b.addLine(elseStmt, indent+1) 397 b.addLine("}\n", indent) 398 return nil 399 } 400 401 func (g *deepCopyGenerator) writeDeepCopyForPtr(b *buffer, inField reflect.StructField, indent int) error { 402 ifFormat := "if in.%s != nil {\n" 403 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 404 b.addLine(ifStmt, indent) 405 406 kind := inField.Type.Elem().Kind() 407 switch kind { 408 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct: 409 if _, found := g.copyables[inField.Type.Elem()]; found { 410 newFormat := "out.%s = new(%s)\n" 411 newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type.Elem())) 412 b.addLine(newStmt, indent+1) 413 assignFormat := "if err := %s(*in.%s, out.%s, c); err != nil {\n" 414 funcName := g.deepCopyFunctionName(inField.Type.Elem()) 415 assignStmt := fmt.Sprintf(assignFormat, funcName, inField.Name, inField.Name) 416 b.addLine(assignStmt, indent+1) 417 b.addLine("return err\n", indent+2) 418 b.addLine("}\n", indent+1) 419 } else { 420 ifFormat := "if newVal, err := c.DeepCopy(in.%s); err != nil {\n" 421 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 422 b.addLine(ifStmt, indent+1) 423 b.addLine("return err\n", indent+2) 424 if kind != reflect.Struct { 425 b.addLine("} else if newVal == nil {\n", indent+1) 426 b.addLine(fmt.Sprintf("out.%s = nil\n", inField.Name), indent+2) 427 } 428 b.addLine("} else {\n", indent+1) 429 assignFormat := "out.%s = newVal.(%s)\n" 430 assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type)) 431 b.addLine(assignStmt, indent+2) 432 b.addLine("}\n", indent+1) 433 } 434 default: 435 newFormat := "out.%s = new(%s)\n" 436 newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type.Elem())) 437 b.addLine(newStmt, indent+1) 438 assignFormat := "*out.%s = *in.%s\n" 439 assignStmt := fmt.Sprintf(assignFormat, inField.Name, inField.Name) 440 b.addLine(assignStmt, indent+1) 441 } 442 b.addLine("} else {\n", indent) 443 elseFormat := "out.%s = nil\n" 444 elseStmt := fmt.Sprintf(elseFormat, inField.Name) 445 b.addLine(elseStmt, indent+1) 446 b.addLine("}\n", indent) 447 return nil 448 } 449 450 func (g *deepCopyGenerator) writeDeepCopyForSlice(b *buffer, inField reflect.StructField, indent int) error { 451 ifFormat := "if in.%s != nil {\n" 452 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 453 b.addLine(ifStmt, indent) 454 newFormat := "out.%s = make(%s, len(in.%s))\n" 455 newStmt := fmt.Sprintf(newFormat, inField.Name, g.typeName(inField.Type), inField.Name) 456 b.addLine(newStmt, indent+1) 457 forFormat := "for i := range in.%s {\n" 458 forStmt := fmt.Sprintf(forFormat, inField.Name) 459 b.addLine(forStmt, indent+1) 460 461 kind := inField.Type.Elem().Kind() 462 switch kind { 463 case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct: 464 if _, found := g.copyables[inField.Type.Elem()]; found { 465 assignFormat := "if err := %s(in.%s[i], &out.%s[i], c); err != nil {\n" 466 funcName := g.deepCopyFunctionName(inField.Type.Elem()) 467 assignStmt := fmt.Sprintf(assignFormat, funcName, inField.Name, inField.Name) 468 b.addLine(assignStmt, indent+2) 469 b.addLine("return err\n", indent+3) 470 b.addLine("}\n", indent+2) 471 } else { 472 ifFormat := "if newVal, err := c.DeepCopy(in.%s[i]); err != nil {\n" 473 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 474 b.addLine(ifStmt, indent+2) 475 b.addLine("return err\n", indent+3) 476 if kind != reflect.Struct { 477 b.addLine("} else if newVal == nil {\n", indent+2) 478 b.addLine(fmt.Sprintf("out.%s[i] = nil\n", inField.Name), indent+3) 479 } 480 b.addLine("} else {\n", indent+2) 481 assignFormat := "out.%s[i] = newVal.(%s)\n" 482 assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type.Elem())) 483 b.addLine(assignStmt, indent+3) 484 b.addLine("}\n", indent+2) 485 } 486 default: 487 assignFormat := "out.%s[i] = in.%s[i]\n" 488 assignStmt := fmt.Sprintf(assignFormat, inField.Name, inField.Name) 489 b.addLine(assignStmt, indent+2) 490 } 491 b.addLine("}\n", indent+1) 492 b.addLine("} else {\n", indent) 493 elseFormat := "out.%s = nil\n" 494 elseStmt := fmt.Sprintf(elseFormat, inField.Name) 495 b.addLine(elseStmt, indent+1) 496 b.addLine("}\n", indent) 497 return nil 498 } 499 500 func (g *deepCopyGenerator) writeDeepCopyForStruct(b *buffer, inType reflect.Type, indent int) error { 501 for i := 0; i < inType.NumField(); i++ { 502 inField := inType.Field(i) 503 switch inField.Type.Kind() { 504 case reflect.Map: 505 if err := g.writeDeepCopyForMap(b, inField, indent); err != nil { 506 return err 507 } 508 case reflect.Ptr: 509 if err := g.writeDeepCopyForPtr(b, inField, indent); err != nil { 510 return err 511 } 512 case reflect.Slice: 513 if err := g.writeDeepCopyForSlice(b, inField, indent); err != nil { 514 return err 515 } 516 case reflect.Interface: 517 ifFormat := "if newVal, err := c.DeepCopy(in.%s); err != nil {\n" 518 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 519 b.addLine(ifStmt, indent) 520 b.addLine("return err\n", indent+1) 521 b.addLine("} else if newVal == nil {\n", indent) 522 b.addLine(fmt.Sprintf("out.%s = nil\n", inField.Name), indent+1) 523 b.addLine("} else {\n", indent) 524 copyFormat := "out.%s = newVal.(%s)\n" 525 copyStmt := fmt.Sprintf(copyFormat, inField.Name, g.typeName(inField.Type)) 526 b.addLine(copyStmt, indent+1) 527 b.addLine("}\n", indent) 528 case reflect.Struct: 529 if _, found := g.copyables[inField.Type]; found { 530 ifFormat := "if err := %s(in.%s, &out.%s, c); err != nil {\n" 531 funcName := g.deepCopyFunctionName(inField.Type) 532 ifStmt := fmt.Sprintf(ifFormat, funcName, inField.Name, inField.Name) 533 b.addLine(ifStmt, indent) 534 b.addLine("return err\n", indent+1) 535 b.addLine("}\n", indent) 536 } else { 537 ifFormat := "if newVal, err := c.DeepCopy(in.%s); err != nil {\n" 538 ifStmt := fmt.Sprintf(ifFormat, inField.Name) 539 b.addLine(ifStmt, indent) 540 b.addLine("return err\n", indent+1) 541 b.addLine("} else {\n", indent) 542 assignFormat := "out.%s = newVal.(%s)\n" 543 assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type)) 544 b.addLine(assignStmt, indent+1) 545 b.addLine("}\n", indent) 546 } 547 default: 548 // This should handle all simple types. 549 assignFormat := "out.%s = in.%s\n" 550 assignStmt := fmt.Sprintf(assignFormat, inField.Name, inField.Name) 551 b.addLine(assignStmt, indent) 552 } 553 } 554 return nil 555 } 556 557 func (g *deepCopyGenerator) writeDeepCopyForType(b *buffer, inType reflect.Type, indent int) error { 558 g.writeHeader(b, inType, indent) 559 switch inType.Kind() { 560 case reflect.Struct: 561 if err := g.writeDeepCopyForStruct(b, inType, indent+1); err != nil { 562 return err 563 } 564 default: 565 return fmt.Errorf("type not supported: %v", inType) 566 } 567 g.writeFooter(b, indent) 568 return nil 569 } 570 571 func (g *deepCopyGenerator) writeRegisterHeader(b *buffer, pkg string, indent int) { 572 b.addLine("func init() {\n", indent) 573 registerFormat := "err := %s.AddGeneratedDeepCopyFuncs(\n" 574 b.addLine(fmt.Sprintf(registerFormat, pkg), indent+1) 575 } 576 577 func (g *deepCopyGenerator) writeRegisterFooter(b *buffer, indent int) { 578 b.addLine(")\n", indent+1) 579 b.addLine("if err != nil {\n", indent+1) 580 b.addLine("// if one of the deep copy functions is malformed, detect it immediately.\n", indent+2) 581 b.addLine("panic(err)\n", indent+2) 582 b.addLine("}\n", indent+1) 583 b.addLine("}\n", indent) 584 b.addLine("\n", indent) 585 } 586 587 func (g *deepCopyGenerator) RegisterDeepCopyFunctions(w io.Writer, pkg string) error { 588 var keys []reflect.Type 589 for key := range g.copyables { 590 keys = append(keys, key) 591 } 592 sort.Sort(byPkgAndName(keys)) 593 594 buffer := newBuffer() 595 indent := 0 596 g.writeRegisterHeader(buffer, pkg, indent) 597 for _, inType := range keys { 598 funcStmt := fmt.Sprintf("%s,\n", g.deepCopyFunctionName(inType)) 599 buffer.addLine(funcStmt, indent+2) 600 } 601 g.writeRegisterFooter(buffer, indent) 602 if err := buffer.flushLines(w); err != nil { 603 return err 604 } 605 return nil 606 } 607 608 func (g *deepCopyGenerator) OverwritePackage(pkg, overwrite string) { 609 g.pkgOverwrites[pkg] = overwrite 610 }