From 2cd59c19c7222f0185d1aaa8c4cdf81d82789424 Mon Sep 17 00:00:00 2001 From: k1LoW Date: Sat, 9 Jan 2021 15:38:52 +0900 Subject: [PATCH 1/7] Add command `ndiag fetch-icons k8s` --- .gitignore | 3 +- cmd/fetchIcons.go | 57 ++++++++++++++++++++++++++++++++++++ icon/fetcher.go | 46 +++++++++++++++++++++++++++++ icon/k8s/k8s.go | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 cmd/fetchIcons.go create mode 100644 icon/fetcher.go create mode 100644 icon/k8s/k8s.go diff --git a/.gitignore b/.gitignore index 9062f263..f38cad43 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,8 @@ ndiag dist/ doc/ archdoc/ -./ndiag.descriptions/ +ndiag.descriptions/ +ndiag.icons/ coverage.txt *-packr.go .envrc diff --git a/cmd/fetchIcons.go b/cmd/fetchIcons.go new file mode 100644 index 00000000..29d8463d --- /dev/null +++ b/cmd/fetchIcons.go @@ -0,0 +1,57 @@ +/* +Copyright © 2021 Ken'ichiro Oyama + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +package cmd + +import ( + "github.com/k1LoW/ndiag/icon" + "github.com/k1LoW/ndiag/icon/k8s" + "github.com/spf13/cobra" +) + +var fetchIconsCmd = &cobra.Command{ + Use: "fetch-icons", + Short: "Fecth icon set from internet", + Long: `Fecth icon set from internet.`, + Args: cobra.OnlyValidArgs, + ValidArgs: []string{"k8s"}, + RunE: func(cmd *cobra.Command, args []string) error { + target := args[0] + var fetcher icon.Fetcher + + cfg, err := newConfig() + if err != nil { + return err + } + + switch target { + case "k8s": + fetcher = &k8s.K8sIcon{} + } + + return fetcher.Fetch(cfg.IconPath) + }, +} + +func init() { + rootCmd.AddCommand(fetchIconsCmd) + fetchIconsCmd.Flags().StringVarP(&configPath, "config", "c", "", "config file path") +} diff --git a/icon/fetcher.go b/icon/fetcher.go new file mode 100644 index 00000000..994e0b02 --- /dev/null +++ b/icon/fetcher.go @@ -0,0 +1,46 @@ +package icon + +import ( + "io" + "net" + "net/http" + "os" + "path/filepath" + "time" +) + +type Fetcher interface { + Fetch(iconPath string) error +} + +func Download(src, dest string) (string, error) { + client := &http.Client{ + Timeout: 30 * time.Second, + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 5 * time.Second, + }).Dial, + TLSHandshakeTimeout: 5 * time.Second, + }, + } + + resp, err := client.Get(src) + if err != nil { + return "", err + } + defer resp.Body.Close() + + p := filepath.Join(dest, filepath.Base(src)) + f, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return "", err + } + if _, err = io.Copy(f, resp.Body); err != nil { + _ = f.Close() + return "", err + } + if err := f.Close(); err != nil { + return "", err + } + return p, nil +} diff --git a/icon/k8s/k8s.go b/icon/k8s/k8s.go new file mode 100644 index 00000000..e4aa57e5 --- /dev/null +++ b/icon/k8s/k8s.go @@ -0,0 +1,74 @@ +package k8s + +import ( + "archive/zip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/k1LoW/ndiag/icon" +) + +const prefix = "k8s" +const archiveURL = "https://github.com/kubernetes/community/archive/master.zip" + +var pathRe = regexp.MustCompile(`\A.+/([^/]+)/([^/]+)/([^/]+)\.svg\z`) + +type K8sIcon struct{} + +func (f *K8sIcon) Fetch(iconPath string) error { + dir, err := ioutil.TempDir("", "ndiag-icon-k8s") + if err != nil { + return err + } + defer os.RemoveAll(dir) + ap, err := icon.Download(archiveURL, dir) + if err != nil { + return err + } + r, err := zip.OpenReader(ap) + if err != nil { + return err + } + for _, f := range r.File { + if !strings.Contains(f.Name, "icons/svg") { + continue + } + if f.FileInfo().IsDir() { + continue + } + matched := pathRe.FindStringSubmatch(f.Name) + + rc, err := f.Open() + if err != nil { + return err + } + buf := make([]byte, f.UncompressedSize) + _, err = io.ReadFull(rc, buf) + if err != nil { + _ = rc.Close() + return err + } + var path string + if matched[2] == "labeled" { + path = filepath.Join(iconPath, prefix, matched[1], fmt.Sprintf("%s.%s", matched[3], "svg")) + } else { + path = filepath.Join(iconPath, prefix, matched[1], matched[3], fmt.Sprintf("%s.%s", matched[2], "svg")) + } + if err := os.MkdirAll(filepath.Dir(path), 0750); err != nil { + return err + } + if err := ioutil.WriteFile(path, buf, f.Mode()); err != nil { + _ = rc.Close() + return err + } + if err := rc.Close(); err != nil { + return err + } + } + return nil +} From a478283cd0ce0fac159335c475a1aa593b460bb3 Mon Sep 17 00:00:00 2001 From: k1LoW Date: Sat, 9 Jan 2021 15:41:43 +0900 Subject: [PATCH 2/7] bonsai --- icon/k8s/k8s.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/icon/k8s/k8s.go b/icon/k8s/k8s.go index e4aa57e5..7ce452d0 100644 --- a/icon/k8s/k8s.go +++ b/icon/k8s/k8s.go @@ -21,6 +21,7 @@ var pathRe = regexp.MustCompile(`\A.+/([^/]+)/([^/]+)/([^/]+)\.svg\z`) type K8sIcon struct{} func (f *K8sIcon) Fetch(iconPath string) error { + _, _ = fmt.Fprintf(os.Stderr, "Fetching from %s ...\n", archiveURL) dir, err := ioutil.TempDir("", "ndiag-icon-k8s") if err != nil { return err @@ -70,5 +71,6 @@ func (f *K8sIcon) Fetch(iconPath string) error { return err } } + _, _ = fmt.Fprintf(os.Stderr, "%s\n", "Done.") return nil } From 1279d6e0b14cff86151bb9e7183fc6926d1a43e3 Mon Sep 17 00:00:00 2001 From: k1LoW Date: Sat, 9 Jan 2021 15:49:10 +0900 Subject: [PATCH 3/7] Add --prefix option --- cmd/fetchIcons.go | 6 +++++- cmd/root.go | 1 + icon/fetcher.go | 2 +- icon/k8s/k8s.go | 3 +-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/fetchIcons.go b/cmd/fetchIcons.go index 29d8463d..e0637f09 100644 --- a/cmd/fetchIcons.go +++ b/cmd/fetchIcons.go @@ -47,11 +47,15 @@ var fetchIconsCmd = &cobra.Command{ fetcher = &k8s.K8sIcon{} } - return fetcher.Fetch(cfg.IconPath) + if iconPrefix == "" { + iconPrefix = target + } + return fetcher.Fetch(cfg.IconPath, iconPrefix) }, } func init() { rootCmd.AddCommand(fetchIconsCmd) fetchIconsCmd.Flags().StringVarP(&configPath, "config", "c", "", "config file path") + fetchIconsCmd.Flags().StringVarP(&iconPrefix, "prefix", "", "", "prefix of icon key") } diff --git a/cmd/root.go b/cmd/root.go index 24c31e8b..68a80ed0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -39,6 +39,7 @@ var ( configPath string out string rmDist bool + iconPrefix string ) var rootCmd = &cobra.Command{ diff --git a/icon/fetcher.go b/icon/fetcher.go index 994e0b02..3625fe0f 100644 --- a/icon/fetcher.go +++ b/icon/fetcher.go @@ -10,7 +10,7 @@ import ( ) type Fetcher interface { - Fetch(iconPath string) error + Fetch(iconPath, prefix string) error } func Download(src, dest string) (string, error) { diff --git a/icon/k8s/k8s.go b/icon/k8s/k8s.go index 7ce452d0..37f78d35 100644 --- a/icon/k8s/k8s.go +++ b/icon/k8s/k8s.go @@ -13,14 +13,13 @@ import ( "github.com/k1LoW/ndiag/icon" ) -const prefix = "k8s" const archiveURL = "https://github.com/kubernetes/community/archive/master.zip" var pathRe = regexp.MustCompile(`\A.+/([^/]+)/([^/]+)/([^/]+)\.svg\z`) type K8sIcon struct{} -func (f *K8sIcon) Fetch(iconPath string) error { +func (f *K8sIcon) Fetch(iconPath, prefix string) error { _, _ = fmt.Fprintf(os.Stderr, "Fetching from %s ...\n", archiveURL) dir, err := ioutil.TempDir("", "ndiag-icon-k8s") if err != nil { From 7dd94b729ae70965519692aa7431b2deb86bcbf0 Mon Sep 17 00:00:00 2001 From: k1LoW Date: Sat, 9 Jan 2021 15:52:24 +0900 Subject: [PATCH 4/7] bonsai --- cmd/fetchIcons.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/fetchIcons.go b/cmd/fetchIcons.go index e0637f09..a5f97a17 100644 --- a/cmd/fetchIcons.go +++ b/cmd/fetchIcons.go @@ -57,5 +57,5 @@ var fetchIconsCmd = &cobra.Command{ func init() { rootCmd.AddCommand(fetchIconsCmd) fetchIconsCmd.Flags().StringVarP(&configPath, "config", "c", "", "config file path") - fetchIconsCmd.Flags().StringVarP(&iconPrefix, "prefix", "", "", "prefix of icon key") + fetchIconsCmd.Flags().StringVarP(&iconPrefix, "prefix", "", "", "icon key prefix") } From 14c855e204dd61e713ff027451b71c51930ec780 Mon Sep 17 00:00:00 2001 From: k1LoW Date: Sat, 9 Jan 2021 16:17:28 +0900 Subject: [PATCH 5/7] Add command `ndiag fetch-icons gcp` --- cmd/fetchIcons.go | 5 +++- icon/gcp/gcp.go | 75 +++++++++++++++++++++++++++++++++++++++++++++++ icon/k8s/k8s.go | 3 ++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 icon/gcp/gcp.go diff --git a/cmd/fetchIcons.go b/cmd/fetchIcons.go index a5f97a17..40807469 100644 --- a/cmd/fetchIcons.go +++ b/cmd/fetchIcons.go @@ -23,6 +23,7 @@ package cmd import ( "github.com/k1LoW/ndiag/icon" + "github.com/k1LoW/ndiag/icon/gcp" "github.com/k1LoW/ndiag/icon/k8s" "github.com/spf13/cobra" ) @@ -32,7 +33,7 @@ var fetchIconsCmd = &cobra.Command{ Short: "Fecth icon set from internet", Long: `Fecth icon set from internet.`, Args: cobra.OnlyValidArgs, - ValidArgs: []string{"k8s"}, + ValidArgs: []string{"k8s", "gcp"}, RunE: func(cmd *cobra.Command, args []string) error { target := args[0] var fetcher icon.Fetcher @@ -45,6 +46,8 @@ var fetchIconsCmd = &cobra.Command{ switch target { case "k8s": fetcher = &k8s.K8sIcon{} + case "gcp": + fetcher = &gcp.GCPIcon{} } if iconPrefix == "" { diff --git a/icon/gcp/gcp.go b/icon/gcp/gcp.go new file mode 100644 index 00000000..986d3762 --- /dev/null +++ b/icon/gcp/gcp.go @@ -0,0 +1,75 @@ +package gcp + +import ( + "archive/zip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/k1LoW/ndiag/icon" +) + +const archiveURL = "https://cloud.google.com/icons/files/google-cloud-icons.zip" + +var pathRe = regexp.MustCompile(`\A.+/([^/]+)\.svg\z`) + +type GCPIcon struct{} + +func (f *GCPIcon) Fetch(iconPath, prefix string) error { + _, _ = fmt.Fprintf(os.Stderr, "Fetching from %s ...\n", archiveURL) + dir, err := ioutil.TempDir("", "ndiag-icon-gcp") + if err != nil { + return err + } + defer os.RemoveAll(dir) + ap, err := icon.Download(archiveURL, dir) + if err != nil { + return err + } + r, err := zip.OpenReader(ap) + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Join(iconPath, prefix), 0750); err != nil { + return err + } + + rep := strings.NewReplacer("-512-color", "", "-521-color", "", " (1)", "") + + for _, f := range r.File { + if strings.Contains(f.Name, "__MACOSX") { + continue + } + if f.FileInfo().IsDir() { + continue + } + matched := pathRe.FindStringSubmatch(f.Name) + if len(matched) == 0 { + continue + } + rc, err := f.Open() + if err != nil { + return err + } + buf := make([]byte, f.UncompressedSize) + _, err = io.ReadFull(rc, buf) + if err != nil { + _ = rc.Close() + return err + } + path := filepath.Join(iconPath, prefix, fmt.Sprintf("%s.%s", strings.ToLower(rep.Replace(matched[1])), "svg")) + if err := ioutil.WriteFile(path, buf, f.Mode()); err != nil { + _ = rc.Close() + return err + } + if err := rc.Close(); err != nil { + return err + } + } + _, _ = fmt.Fprintf(os.Stderr, "%s\n", "Done.") + return nil +} diff --git a/icon/k8s/k8s.go b/icon/k8s/k8s.go index 37f78d35..9811db5f 100644 --- a/icon/k8s/k8s.go +++ b/icon/k8s/k8s.go @@ -42,6 +42,9 @@ func (f *K8sIcon) Fetch(iconPath, prefix string) error { continue } matched := pathRe.FindStringSubmatch(f.Name) + if len(matched) == 0 { + continue + } rc, err := f.Open() if err != nil { From 19deb41c7884b31e007d7e7bf37f7ee8da55fc55 Mon Sep 17 00:00:00 2001 From: k1LoW Date: Sat, 9 Jan 2021 16:39:21 +0900 Subject: [PATCH 6/7] optimize path --- go.mod | 1 + go.sum | 2 ++ icon/gcp/gcp.go | 9 ++++++--- icon/k8s/k8s.go | 5 +++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index b6c3a19a..4744624d 100644 --- a/go.mod +++ b/go.mod @@ -16,4 +16,5 @@ require ( github.com/olekukonko/tablewriter v0.0.4 github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c github.com/spf13/cobra v1.1.1 + github.com/stoewer/go-strcase v1.2.0 ) diff --git a/go.sum b/go.sum index 20f0c7b9..a8a299f0 100644 --- a/go.sum +++ b/go.sum @@ -509,6 +509,8 @@ github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQO github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM= github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/icon/gcp/gcp.go b/icon/gcp/gcp.go index 986d3762..33152570 100644 --- a/icon/gcp/gcp.go +++ b/icon/gcp/gcp.go @@ -11,11 +11,13 @@ import ( "strings" "github.com/k1LoW/ndiag/icon" + "github.com/stoewer/go-strcase" ) const archiveURL = "https://cloud.google.com/icons/files/google-cloud-icons.zip" var pathRe = regexp.MustCompile(`\A.+/([^/]+)\.svg\z`) +var rep = strings.NewReplacer("-512-color", "", "-521-color", "", "-color", "", " (1)", "", "_", "-") type GCPIcon struct{} @@ -38,12 +40,13 @@ func (f *GCPIcon) Fetch(iconPath, prefix string) error { return err } - rep := strings.NewReplacer("-512-color", "", "-521-color", "", " (1)", "") - for _, f := range r.File { if strings.Contains(f.Name, "__MACOSX") { continue } + if strings.Contains(f.Name, "Expanded Product Card Icons") { + continue + } if f.FileInfo().IsDir() { continue } @@ -61,7 +64,7 @@ func (f *GCPIcon) Fetch(iconPath, prefix string) error { _ = rc.Close() return err } - path := filepath.Join(iconPath, prefix, fmt.Sprintf("%s.%s", strings.ToLower(rep.Replace(matched[1])), "svg")) + path := filepath.Join(iconPath, prefix, fmt.Sprintf("%s.%s", strcase.KebabCase(rep.Replace(matched[1])), "svg")) if err := ioutil.WriteFile(path, buf, f.Mode()); err != nil { _ = rc.Close() return err diff --git a/icon/k8s/k8s.go b/icon/k8s/k8s.go index 9811db5f..12d6f5c9 100644 --- a/icon/k8s/k8s.go +++ b/icon/k8s/k8s.go @@ -16,6 +16,7 @@ import ( const archiveURL = "https://github.com/kubernetes/community/archive/master.zip" var pathRe = regexp.MustCompile(`\A.+/([^/]+)/([^/]+)/([^/]+)\.svg\z`) +var rep = strings.NewReplacer("control_plane_components", "control-plane", "infrastructure_components", "infra", "_", "-") type K8sIcon struct{} @@ -58,9 +59,9 @@ func (f *K8sIcon) Fetch(iconPath, prefix string) error { } var path string if matched[2] == "labeled" { - path = filepath.Join(iconPath, prefix, matched[1], fmt.Sprintf("%s.%s", matched[3], "svg")) + path = rep.Replace(filepath.Join(iconPath, prefix, matched[1], fmt.Sprintf("%s.%s", matched[3], "svg"))) } else { - path = filepath.Join(iconPath, prefix, matched[1], matched[3], fmt.Sprintf("%s.%s", matched[2], "svg")) + path = rep.Replace(filepath.Join(iconPath, prefix, matched[1], matched[3], fmt.Sprintf("%s.%s", matched[2], "svg"))) } if err := os.MkdirAll(filepath.Dir(path), 0750); err != nil { return err From ae1de28f67595553f88420653b6d2e5cb82aa355 Mon Sep 17 00:00:00 2001 From: k1LoW Date: Sat, 9 Jan 2021 17:59:05 +0900 Subject: [PATCH 7/7] Add command `ndiag fetch-icons aws` --- cmd/fetchIcons.go | 9 ++++-- icon/aws/aws.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 icon/aws/aws.go diff --git a/cmd/fetchIcons.go b/cmd/fetchIcons.go index 40807469..d16ecc05 100644 --- a/cmd/fetchIcons.go +++ b/cmd/fetchIcons.go @@ -23,6 +23,7 @@ package cmd import ( "github.com/k1LoW/ndiag/icon" + "github.com/k1LoW/ndiag/icon/aws" "github.com/k1LoW/ndiag/icon/gcp" "github.com/k1LoW/ndiag/icon/k8s" "github.com/spf13/cobra" @@ -33,7 +34,7 @@ var fetchIconsCmd = &cobra.Command{ Short: "Fecth icon set from internet", Long: `Fecth icon set from internet.`, Args: cobra.OnlyValidArgs, - ValidArgs: []string{"k8s", "gcp"}, + ValidArgs: []string{"aws", "gcp", "k8s"}, RunE: func(cmd *cobra.Command, args []string) error { target := args[0] var fetcher icon.Fetcher @@ -44,10 +45,12 @@ var fetchIconsCmd = &cobra.Command{ } switch target { - case "k8s": - fetcher = &k8s.K8sIcon{} + case "aws": + fetcher = &aws.AWSIcon{} case "gcp": fetcher = &gcp.GCPIcon{} + case "k8s": + fetcher = &k8s.K8sIcon{} } if iconPrefix == "" { diff --git a/icon/aws/aws.go b/icon/aws/aws.go new file mode 100644 index 00000000..2f8bafd8 --- /dev/null +++ b/icon/aws/aws.go @@ -0,0 +1,81 @@ +package aws + +import ( + "archive/zip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/k1LoW/ndiag/icon" + "github.com/stoewer/go-strcase" +) + +const archiveURL = "https://d1.awsstatic.com/webteam/architecture-icons/Q32020/AWS-Architecture-Assets-For-Light-and-Dark-BG_20200911.478ff05b80f909792f7853b1a28de8e28eac67f4.zip" + +type AWSIcon struct{} + +var rep = strings.NewReplacer("_Light", "", "_48", "", "loT", "iot", "IoT", "iot", "FSx", "fsx", "AMIs", "amis", "_", "-", "&", "and", "VMware", "vmware") +var rep2 = strings.NewReplacer("res-amazon", "res", "res-aws", "res", "arch-aws-", "", "arch-amazon-", "") + +func (f *AWSIcon) Fetch(iconPath, prefix string) error { + _, _ = fmt.Fprintf(os.Stderr, "Fetching from %s ...\n", archiveURL) + dir, err := ioutil.TempDir("", "ndiag-icon-aws") + if err != nil { + return err + } + defer os.RemoveAll(dir) + ap, err := icon.Download(archiveURL, dir) + if err != nil { + return err + } + r, err := zip.OpenReader(ap) + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Join(iconPath, prefix), 0750); err != nil { + return err + } + + for _, f := range r.File { + if strings.Contains(f.Name, "_Dark") { + continue + } + if strings.Contains(f.Name, "_64") || strings.Contains(f.Name, "_32") || strings.Contains(f.Name, "_16") { + continue + } + if !strings.Contains(f.Name, ".svg") { + continue + } + if f.FileInfo().IsDir() { + continue + } + + rc, err := f.Open() + if err != nil { + return err + } + fn := rep2.Replace(strcase.KebabCase(rep.Replace(filepath.Base(f.Name)))) + + path := filepath.Join(iconPath, prefix, fn) + + buf := make([]byte, f.UncompressedSize) + _, err = io.ReadFull(rc, buf) + if err != nil { + _ = rc.Close() + return err + } + if err := ioutil.WriteFile(path, buf, f.Mode()); err != nil { + _ = rc.Close() + return err + } + if err := rc.Close(); err != nil { + return err + } + } + + _, _ = fmt.Fprintf(os.Stderr, "%s\n", "Done.") + return nil +}