github.com/youyuanwu/go-swagger@v0.19.0/cmd/swagger/commands/mixin.go (about) 1 package commands 2 3 import ( 4 "errors" 5 "io" 6 "log" 7 "os" 8 9 "github.com/go-openapi/analysis" 10 "github.com/go-openapi/loads" 11 "github.com/go-openapi/spec" 12 flags "github.com/jessevdk/go-flags" 13 ) 14 15 const ( 16 // Output messages 17 nothingToDo = "Nothing to do. Need some swagger files to merge.\nUSAGE: swagger mixin [-c <expected#Collisions>] <primary-swagger-file> <mixin-swagger-file>..." 18 ) 19 20 // MixinSpec holds command line flag definitions specific to the mixin 21 // command. The flags are defined using struct field tags with the 22 // "github.com/jessevdk/go-flags" format. 23 type MixinSpec struct { 24 ExpectedCollisionCount uint `short:"c" description:"expected # of rejected mixin paths, defs, etc due to existing key. Non-zero exit if does not match actual."` 25 Compact bool `long:"compact" description:"applies to JSON formatted specs. When present, doesn't prettify the json"` 26 Output flags.Filename `long:"output" short:"o" description:"the file to write to"` 27 Format string `long:"format" description:"the format for the spec document" default:"json" choice:"yaml" choice:"json"` 28 } 29 30 // Execute runs the mixin command which merges Swagger 2.0 specs into 31 // one spec 32 // 33 // Use cases include adding independently versioned metadata APIs to 34 // application APIs for microservices. 35 // 36 // Typically, multiple APIs to the same service instance is not a 37 // problem for client generation as you can create more than one 38 // client to the service from the same calling process (one for each 39 // API). However, merging clients can improve clarity of client code 40 // by having a single client to given service vs several. 41 // 42 // Server skeleton generation, ie generating the model & marshaling 43 // code, http server instance etc. from Swagger, becomes easier with a 44 // merged spec for some tools & target-languages. Server code 45 // generation tools that natively support hosting multiple specs in 46 // one server process will not need this tool. 47 func (c *MixinSpec) Execute(args []string) error { 48 49 if len(args) < 2 { 50 return errors.New(nothingToDo) 51 } 52 53 log.Printf("args[0] = %v\n", args[0]) 54 log.Printf("args[1:] = %v\n", args[1:]) 55 collisions, err := c.MixinFiles(args[0], args[1:], os.Stdout) 56 57 for _, warn := range collisions { 58 log.Println(warn) 59 } 60 61 if err != nil { 62 return err 63 } 64 65 if len(collisions) != int(c.ExpectedCollisionCount) { 66 if len(collisions) != 0 { 67 // use bash $? to get actual # collisions 68 // (but has to be non-zero) 69 os.Exit(len(collisions)) 70 } 71 os.Exit(254) 72 } 73 return nil 74 } 75 76 // MixinFiles is a convenience function for Mixin that reads the given 77 // swagger files, adds the mixins to primary, calls 78 // FixEmptyResponseDescriptions on the primary, and writes the primary 79 // with mixins to the given writer in JSON. Returns the warning 80 // messages for collisions that occurred during mixin process and any 81 // error. 82 func (c *MixinSpec) MixinFiles(primaryFile string, mixinFiles []string, w io.Writer) ([]string, error) { 83 84 primaryDoc, err := loads.Spec(primaryFile) 85 if err != nil { 86 return nil, err 87 } 88 primary := primaryDoc.Spec() 89 90 var mixins []*spec.Swagger 91 for _, mixinFile := range mixinFiles { 92 mixin, lerr := loads.Spec(mixinFile) 93 if lerr != nil { 94 return nil, lerr 95 } 96 mixins = append(mixins, mixin.Spec()) 97 } 98 99 collisions := analysis.Mixin(primary, mixins...) 100 analysis.FixEmptyResponseDescriptions(primary) 101 102 return collisions, writeToFile(primary, !c.Compact, c.Format, string(c.Output)) 103 }