github.com/symfony-cli/symfony-cli@v0.0.0-20240514161054-ece2df437dfa/local/platformsh/generator/config.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 "os" 10 "sort" 11 "strings" 12 "text/template" 13 14 "github.com/hashicorp/go-version" 15 "gopkg.in/yaml.v2" 16 ) 17 18 type service struct { 19 Type string `json:"type"` 20 Runtime bool `json:"runtime"` 21 Versions serviceVersions `json:"versions"` 22 } 23 24 type serviceVersions struct { 25 Deprecated []string `json:"deprecated"` 26 Supported []string `json:"supported"` 27 } 28 29 var configTemplate = template.Must(template.New("output").Parse(`// Code generated by platformsh/generator/main.go 30 // DO NOT EDIT 31 32 /* 33 * Copyright (c) 2021-present Fabien Potencier <fabien@symfony.com> 34 * 35 * This file is part of Symfony CLI project 36 * 37 * This program is free software: you can redistribute it and/or modify 38 * it under the terms of the GNU Affero General Public License as 39 * published by the Free Software Foundation, either version 3 of the 40 * License, or (at your option) any later version. 41 * 42 * This program is distributed in the hope that it will be useful, 43 * but WITHOUT ANY WARRANTY; without even the implied warranty of 44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 45 * GNU Affero General Public License for more details. 46 * 47 * You should have received a copy of the GNU Affero General Public License 48 * along with this program. If not, see <http://www.gnu.org/licenses/>. 49 */ 50 51 package platformsh 52 53 var availablePHPExts = map[string][]string{ 54 {{ .Extensions -}} 55 } 56 57 var availableServices = []*service{ 58 {{ .Services -}} 59 } 60 `)) 61 62 func generateConfig() { 63 extsAsString, err := parsePHPExtensions() 64 if err != nil { 65 panic(err) 66 } 67 68 servicesAsString, err := parseServices() 69 if err != nil { 70 panic(err) 71 } 72 73 data := map[string]interface{}{ 74 "Extensions": extsAsString, 75 "Services": servicesAsString, 76 } 77 var buf bytes.Buffer 78 if err := configTemplate.Execute(&buf, data); err != nil { 79 panic(err) 80 } 81 f, err := os.Create("local/platformsh/config.go") 82 if err != nil { 83 panic(err) 84 } 85 f.Write(buf.Bytes()) 86 } 87 88 func parseServices() (string, error) { 89 resp, err := http.Get("https://raw.githubusercontent.com/platformsh/platformsh-docs/master/shared/data/registry.json") 90 if err != nil { 91 return "", err 92 } 93 defer resp.Body.Close() 94 var services map[string]*service 95 body, err := io.ReadAll(resp.Body) 96 if err != nil { 97 return "", err 98 } 99 if err := json.Unmarshal(body, &services); err != nil { 100 return "", err 101 } 102 serviceNames := []string{} 103 for name := range services { 104 serviceNames = append(serviceNames, name) 105 } 106 sort.Strings(serviceNames) 107 servicesAsString := "" 108 for _, name := range serviceNames { 109 s := services[name] 110 if !s.Runtime { 111 deprecatedVersions, err := sortVersions(s.Versions.Deprecated) 112 if err != nil { 113 return "", err 114 } 115 supportedVersions, err := sortVersions(s.Versions.Supported) 116 if err != nil { 117 return "", err 118 } 119 120 servicesAsString += "\t{\n" 121 servicesAsString += fmt.Sprintf("\t\tType: \"%s\",\n", s.Type) 122 servicesAsString += "\t\tVersions: serviceVersions{\n" 123 if len(deprecatedVersions) > 0 { 124 servicesAsString += fmt.Sprintf("\t\t\tDeprecated: []string{\"%s\"},\n", strings.Join(deprecatedVersions, "\", \"")) 125 } else { 126 servicesAsString += "\t\t\tDeprecated: []string{},\n" 127 } 128 if len(supportedVersions) > 0 { 129 servicesAsString += fmt.Sprintf("\t\t\tSupported: []string{\"%s\"},\n", strings.Join(supportedVersions, "\", \"")) 130 } else { 131 servicesAsString += "\t\t\tSupported: []string{},\n" 132 } 133 servicesAsString += "\t\t},\n" 134 servicesAsString += "\t},\n" 135 } 136 } 137 return servicesAsString, nil 138 } 139 140 func parsePHPExtensions() (string, error) { 141 resp, err := http.Get("https://raw.githubusercontent.com/platformsh/platformsh-docs/master/shared/data/php_extensions.yaml") 142 if err != nil { 143 return "", err 144 } 145 defer resp.Body.Close() 146 var versions []string 147 orderedExtensionNames := []string{} 148 extensions := make(map[string][]string) 149 150 body, err := io.ReadAll(resp.Body) 151 if err != nil { 152 return "", err 153 } 154 var fullConfig struct { 155 Grid map[string]struct { 156 Available []string 157 Default []string 158 } 159 } 160 if err := yaml.Unmarshal(body, &fullConfig); err != nil { 161 return "", err 162 } 163 for version, cfg := range fullConfig.Grid { 164 for _, ext := range append(cfg.Available, cfg.Default...) { 165 name := strings.ToLower(ext) 166 if _, ok := extensions[name]; !ok { 167 orderedExtensionNames = append(orderedExtensionNames, name) 168 } 169 extensions[name] = append(extensions[name], version) 170 } 171 } 172 173 sort.Strings(orderedExtensionNames) 174 maxNameLen := 0 175 for name := range extensions { 176 if len(name) > maxNameLen { 177 maxNameLen = len(name) 178 } 179 sort.Strings(extensions[name]) 180 } 181 extsAsString := "" 182 183 for _, name := range orderedExtensionNames { 184 versions = extensions[name] 185 line := fmt.Sprintf("\t\"%s\":%s{", name, strings.Repeat(" ", maxNameLen-len(name)+1)) 186 for i, version := range versions { 187 line = line + fmt.Sprintf(`"%s"`, version) 188 if i != len(versions)-1 { 189 line = line + ", " 190 } 191 } 192 line = line + "}," 193 extsAsString = extsAsString + line + "\n" 194 } 195 return extsAsString, nil 196 } 197 198 func parseLine(line string) (string, []string) { 199 next := strings.Index(line[1:], "|") + 1 200 name := strings.TrimSpace(line[1:next]) 201 var versions []string 202 for { 203 current := next + 1 204 nextIndex := strings.Index(line[current:], "|") 205 if nextIndex == -1 { 206 break 207 } 208 next = nextIndex + current 209 versions = append(versions, strings.TrimSpace(line[current:next])) 210 if next >= len(line) { 211 break 212 } 213 } 214 return name, versions 215 } 216 217 func sortVersions(versions []string) ([]string, error) { 218 parsedVersions := make([]*version.Version, len(versions)) 219 for i, raw := range versions { 220 v, err := version.NewVersion(raw) 221 if err != nil { 222 return nil, err 223 } 224 parsedVersions[i] = v 225 } 226 sort.Sort(version.Collection(parsedVersions)) 227 versionsAsStrings := make([]string, len(versions)) 228 for i, version := range parsedVersions { 229 versionsAsStrings[i] = version.Original() 230 } 231 return versionsAsStrings, nil 232 }