1+ package cmd
2+
3+ import (
4+ "github.com/spf13/cobra"
5+ "encoding/json"
6+ "fmt"
7+ "encoding/xml"
8+ "path"
9+ "io/ioutil"
10+ "regexp"
11+ "os"
12+ "errors"
13+ "strconv"
14+ "sort"
15+ )
16+
17+ const (
18+ fileMode = 0644
19+ )
20+
21+ var (
22+ outputDirectory string
23+ dryRun bool
24+ )
25+
26+ var generateCmd = & cobra.Command {
27+ Use : "generate" ,
28+ Short : "Generate XML quota using JSON input file" ,
29+ Run : func (cmd * cobra.Command , args []string ) {
30+ input , err := parseInputFile (inputFilePath )
31+ if (err != nil ) {
32+ fmt .Println (err .Error ())
33+ os .Exit (1 )
34+ }
35+ files := convert (* input )
36+ names := []string {}
37+ for name := range files {
38+ names = append (names , name )
39+ }
40+ sort .Strings (names )
41+ for _ , name := range names {
42+ if err := output (name , files [name ], outputDirectory ); err != nil {
43+ fmt .Println (err .Error ())
44+ os .Exit (1 )
45+ }
46+ }
47+ },
48+ }
49+
50+ func init () {
51+ initCommonFlags (generateCmd )
52+ generateCmd .PersistentFlags ().StringVar (& outputDirectory , "outputDirectory" , "." , "output directory" )
53+ generateCmd .PersistentFlags ().BoolVar (& dryRun , "dryRun" , false , "whether to send output to stdout instead of writing files" )
54+ }
55+
56+ func convert (input JsonInput ) map [string ] XmlBrowsers {
57+ ret := make (map [string ] XmlBrowsers )
58+ hostsMap := input .Hosts
59+ quotaMap := input .Quota
60+ aliasesMap := input .Aliases
61+ for quotaName , quota := range quotaMap {
62+ ret [quotaName ] = createQuota (quotaName , hostsMap , quota )
63+ }
64+ for quotaName , aliases := range aliasesMap {
65+ if _ , ok := ret [quotaName ]; ok {
66+ for _ , alias := range aliases {
67+ ret [alias ] = ret [quotaName ]
68+ }
69+ } else {
70+ fmt .Printf ("Missing reference quota %s\n " , quotaName )
71+ os .Exit (1 )
72+ }
73+ }
74+ return ret
75+ }
76+
77+ func createQuota (quotaName string , hostsMap JsonHosts , quota JsonQuota ) XmlBrowsers {
78+ browsers := []XmlBrowser {}
79+ for browserName , browser := range quota {
80+ xmlVersions := []XmlVersion {}
81+ for versionName , hostsRef := range browser .Versions {
82+ regions := hostsMap [hostsRef ]
83+ if (regions != nil ) {
84+ xmlVersion := XmlVersion {
85+ Number : versionName ,
86+ Regions : jsonRegionsToXmlRegions (regions ),
87+ }
88+ xmlVersions = append (xmlVersions , xmlVersion )
89+ } else {
90+ fmt .Printf ("Missing host reference %s for browser %s:%s:%s\n " , hostsRef , quotaName , browserName , versionName )
91+ os .Exit (1 )
92+ }
93+ }
94+ xmlBrowser := XmlBrowser {
95+ Name : browserName ,
96+ DefaultVersion : browser .DefaultVersion ,
97+ Versions : xmlVersions ,
98+ }
99+ browsers = append (browsers , xmlBrowser )
100+ }
101+ return XmlBrowsers {
102+ Browsers : browsers ,
103+ XmlNS : "urn:config.gridrouter.qatools.ru" ,
104+ }
105+ }
106+
107+ func jsonRegionsToXmlRegions (regions JsonRegions ) []XmlRegion {
108+ xmlRegions := []XmlRegion {}
109+ for regionName , region := range regions {
110+ xmlHosts := XmlHosts {}
111+ for hostPattern , host := range region {
112+ hostNames := parseHostPattern (hostPattern )
113+ for _ , hostName := range hostNames {
114+ xmlHosts = append (xmlHosts , XmlHost {
115+ Name : hostName ,
116+ Port : host .Port ,
117+ Count : host .Count ,
118+ })
119+ }
120+ }
121+ xmlRegions = append (xmlRegions , XmlRegion {
122+ Name : regionName ,
123+ Hosts : xmlHosts ,
124+ })
125+ }
126+ return xmlRegions
127+ }
128+
129+ func parseInputFile (filePath string ) (* JsonInput , error ) {
130+ bytes , err := ioutil .ReadFile (filePath )
131+ if err != nil {
132+ return nil , errors .New (fmt .Sprintf ("error reading input file [%s]: %v" , filePath , err ))
133+ }
134+ input := new (JsonInput )
135+ if err := json .Unmarshal (bytes , input ); err != nil {
136+ return nil , errors .New (fmt .Sprintf ("error parsing input file [%s]: %v" , filePath , err ))
137+ }
138+ return input , nil
139+ }
140+
141+ func marshalBrowsers (browsers XmlBrowsers ) ([]byte , error ) {
142+ return xml .MarshalIndent (browsers , "" , " " )
143+ }
144+
145+ func output (quotaName string , browsers XmlBrowsers , outputDirectory string ) error {
146+ filePath := path .Join (outputDirectory , quotaName + ".xml" )
147+ if (dryRun ) {
148+ return printOutputFile (filePath , browsers )
149+ } else {
150+ return saveOutputFile (filePath , browsers )
151+ }
152+ }
153+
154+ func printOutputFile (filePath string , browsers XmlBrowsers ) error {
155+ bytes , err := marshalBrowsers (browsers )
156+ if (err != nil ) {
157+ return err
158+ }
159+ fmt .Println (filePath )
160+ fmt .Println ("---" )
161+ fmt .Println (string (bytes ))
162+ fmt .Println ("---" )
163+ return nil
164+ }
165+
166+ func saveOutputFile (filePath string , browsers XmlBrowsers ) error {
167+ bytes , err := marshalBrowsers (browsers )
168+ if (err != nil ) {
169+ return err
170+ }
171+ if err := ioutil .WriteFile (filePath , bytes , fileMode ); err != nil {
172+ return errors .New (fmt .Sprintf ("error saving to output file [%s]: %v" , filePath , err ))
173+ }
174+ return nil
175+ }
176+
177+ //Only one [1:10] pattern can be included in host pattern
178+ func parseHostPattern (pattern string ) []string {
179+ re := regexp .MustCompile ("(.*)\\ [(\\ d+):(\\ d+)\\ ](.*)" )
180+ pieces := re .FindStringSubmatch (pattern )
181+ if len (pieces ) == 5 {
182+ head := pieces [1 ]
183+ from , _ := strconv .Atoi (pieces [2 ])
184+ to , _ := strconv .Atoi (pieces [3 ])
185+ tail := pieces [4 ]
186+ if (from <= to ) {
187+ ret := []string {}
188+ for i := from ; i <= to ; i ++ {
189+ ret = append (ret , fmt .Sprintf ("%s%d%s" , head , i , tail ))
190+ }
191+ return ret
192+ }
193+ }
194+ return []string {pattern }
195+ }
0 commit comments