From 0b79a570c558956f9c9b468b54f07637d25a2039 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 13 May 2019 13:24:15 -0700 Subject: [PATCH 01/25] Initial attempt at localization with gotext --- cmd/minikube/main.go | 3 +- pkg/minikube/console/console.go | 60 ++++----------- pkg/minikube/console/console_test.go | 10 +-- pkg/minikube/console/style.go | 4 +- pkg/minikube/translate/fr-FR.json | 3 + pkg/minikube/translate/translate.go | 109 +++++++++++++++++++++++++++ 6 files changed, 135 insertions(+), 54 deletions(-) create mode 100644 pkg/minikube/translate/fr-FR.json create mode 100644 pkg/minikube/translate/translate.go diff --git a/cmd/minikube/main.go b/cmd/minikube/main.go index cfdf2847d4da..f50ed4831e01 100644 --- a/cmd/minikube/main.go +++ b/cmd/minikube/main.go @@ -25,6 +25,7 @@ import ( "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/translate" _ "k8s.io/minikube/pkg/provision" ) @@ -40,6 +41,6 @@ func main() { } console.SetOutFile(os.Stdout) console.SetErrFile(os.Stderr) - console.DetermineLocale() + translate.DetermineLocale() cmd.Execute() } diff --git a/pkg/minikube/console/console.go b/pkg/minikube/console/console.go index d9beb284511e..693dd7d2545b 100644 --- a/pkg/minikube/console/console.go +++ b/pkg/minikube/console/console.go @@ -24,11 +24,10 @@ import ( "strconv" "strings" - "github.com/cloudfoundry-attic/jibber_jabber" "github.com/golang/glog" isatty "github.com/mattn/go-isatty" - "golang.org/x/text/language" "golang.org/x/text/message" + "k8s.io/minikube/pkg/minikube/translate" ) // By design, this package uses global references to language and output objects, in preference @@ -48,10 +47,6 @@ var ( outFile fdWriter // errFile is where Err* functions send output to. Set using SetErrFile() errFile fdWriter - // preferredLanguage is the default language messages will be output in - preferredLanguage = language.AmericanEnglish - // our default language - defaultLanguage = language.AmericanEnglish // useColor is whether or not color output should be used, updated by Set*Writer. useColor = false // OverrideEnv is the environment variable used to override color/emoji usage @@ -89,15 +84,13 @@ func OutStyle(style, format string, a ...interface{}) error { // Out writes a basic formatted string to stdout func Out(format string, a ...interface{}) error { - p := message.NewPrinter(preferredLanguage) if outFile == nil { - if _, err := p.Fprintf(os.Stdout, "(stdout unset)"+format, a...); err != nil { + if err := PrintToConsole(os.Stdout, "(stdout unset)"+format, a...); err != nil { return err } - return fmt.Errorf("no output file has been set") + return fmt.Errorf("no out file has been set") } - _, err := p.Fprintf(outFile, format, a...) - return err + return PrintToConsole(outFile, format, a...) } // OutLn writes a basic formatted string with a newline to stdout @@ -125,14 +118,20 @@ func ErrStyle(style, format string, a ...interface{}) error { // Err writes a basic formatted string to stderr func Err(format string, a ...interface{}) error { - p := message.NewPrinter(preferredLanguage) if errFile == nil { - if _, err := p.Fprintf(os.Stderr, "(stderr unset)"+format, a...); err != nil { + if err := PrintToConsole(os.Stderr, "(stderr unset)"+format, a...); err != nil { return err } return fmt.Errorf("no error file has been set") } - _, err := p.Fprintf(errFile, format, a...) + return PrintToConsole(errFile, format, a...) +} + +// PrintToConsole writes a formatted string to the supplied writer +func PrintToConsole(file fdWriter, format string, a ...interface{}) error { + p := message.NewPrinter(translate.GetPreferredLanguage()) + format = translate.Translate(format) + _, err := p.Fprintf(file, format, a...) return err } @@ -161,30 +160,6 @@ func Failure(format string, a ...interface{}) error { return ErrStyle("failure", format, a...) } -// SetPreferredLanguageTag configures which language future messages should use. -func SetPreferredLanguageTag(l language.Tag) { - glog.Infof("Setting Language to %s ...", l) - preferredLanguage = l -} - -// SetPreferredLanguage configures which language future messages should use, based on a LANG string. -func SetPreferredLanguage(s string) error { - // "C" is commonly used to denote a neutral POSIX locale. See http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html#tag_07_02 - if s == "" || s == "C" { - SetPreferredLanguageTag(defaultLanguage) - return nil - } - // Handles "de_DE" or "de_DE.utf8" - // We don't process encodings, since Rob Pike invented utf8 and we're mostly stuck with it. - parts := strings.Split(s, ".") - l, err := language.Parse(parts[0]) - if err != nil { - return err - } - SetPreferredLanguageTag(l) - return nil -} - // SetOutFile configures which writer standard output goes to. func SetOutFile(w fdWriter) { glog.Infof("Setting OutFile to fd %d ...", w.Fd()) @@ -199,15 +174,6 @@ func SetErrFile(w fdWriter) { useColor = wantsColor(w.Fd()) } -func DetermineLocale() { - locale, err := jibber_jabber.DetectIETF() - if err != nil { - glog.Warningf("Getting system locale failed: %s", err) - locale = "" - } - SetPreferredLanguage(locale) -} - // wantsColor determines if the user might want colorized output. func wantsColor(fd uintptr) bool { // First process the environment: we allow users to force colors on or off. diff --git a/pkg/minikube/console/console_test.go b/pkg/minikube/console/console_test.go index c9f2d77b9bea..8729c54d2d2e 100644 --- a/pkg/minikube/console/console_test.go +++ b/pkg/minikube/console/console_test.go @@ -23,6 +23,7 @@ import ( "golang.org/x/text/language" "golang.org/x/text/message" + "k8s.io/minikube/pkg/minikube/translate" ) // fakeFile satisfies fdWriter @@ -115,7 +116,7 @@ func TestOut(t *testing.T) { } for _, tc := range tests { t.Run(tc.format, func(t *testing.T) { - SetPreferredLanguageTag(tc.lang) + translate.SetPreferredLanguageTag(tc.lang) f := newFakeFile() SetOutFile(f) ErrLn("unrelated message") @@ -175,14 +176,13 @@ func TestSetPreferredLanguage(t *testing.T) { for _, tc := range tests { t.Run(tc.input, func(t *testing.T) { // Set something so that we can assert change. - SetPreferredLanguageTag(language.Icelandic) - if err := SetPreferredLanguage(tc.input); err != nil { + translate.SetPreferredLanguageTag(language.Icelandic) + if err := translate.SetPreferredLanguage(tc.input); err != nil { t.Errorf("unexpected error: %q", err) } - // Just compare the bases ("en", "fr"), since I can't seem to refer directly to them want, _ := tc.want.Base() - got, _ := preferredLanguage.Base() + got, _ := translate.GetPreferredLanguage().Base() if got != want { t.Errorf("SetPreferredLanguage(%s) = %q, want %q", tc.input, got, want) } diff --git a/pkg/minikube/console/style.go b/pkg/minikube/console/style.go index 453a90d0277d..630615f09a7e 100644 --- a/pkg/minikube/console/style.go +++ b/pkg/minikube/console/style.go @@ -22,6 +22,7 @@ import ( "golang.org/x/text/message" "golang.org/x/text/number" + "k8s.io/minikube/pkg/minikube/translate" ) var ( @@ -131,12 +132,13 @@ func lowPrefix(s style) string { // Apply styling to a format string func applyStyle(style string, useColor bool, format string, a ...interface{}) (string, error) { - p := message.NewPrinter(preferredLanguage) + p := message.NewPrinter(translate.GetPreferredLanguage()) for i, x := range a { if _, ok := x.(int); ok { a[i] = number.Decimal(x, number.NoSeparator()) } } + format = translate.Translate(format) out := p.Sprintf(format, a...) s, ok := styles[style] diff --git a/pkg/minikube/translate/fr-FR.json b/pkg/minikube/translate/fr-FR.json new file mode 100644 index 000000000000..9b6e844f724d --- /dev/null +++ b/pkg/minikube/translate/fr-FR.json @@ -0,0 +1,3 @@ +{ + "Re-using the currently running %s VM for %q ...": "Réutilisant le VM %s en cours d'exécution pour %q ..." +} diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go new file mode 100644 index 000000000000..48cadbce7de3 --- /dev/null +++ b/pkg/minikube/translate/translate.go @@ -0,0 +1,109 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package translate + +import ( + "encoding/json" + "io/ioutil" + "strings" + + "github.com/cloudfoundry-attic/jibber_jabber" + "github.com/golang/glog" + "github.com/nicksnyder/go-i18n/v2/i18n" + "golang.org/x/text/language" +) + +var ( + // preferredLanguage is the default language messages will be output in + preferredLanguage = language.AmericanEnglish + // our default language + defaultLanguage = language.AmericanEnglish + + // Translations is a translation map from strings that can be output to console + // to its translation in the user's system locale. + Translations map[string]interface{} + + localizer i18n.Localizer +) + +// Translate translates the given string to the supplied langauge. +func Translate(s string) string { + if len(Translations) == 0 { + return s + } + + if translation, ok := Translations[s]; ok { + return translation.(string) + } + + return s +} + +// DetermineLocale finds the system locale and sets the preferred language +// for output appropriately. +func DetermineLocale() { + locale, err := jibber_jabber.DetectIETF() + if err != nil { + glog.Warningf("Getting system locale failed: %s", err) + locale = "" + } + SetPreferredLanguage(locale) + + // Load translations for preferred language into memory. + if preferredLanguage != defaultLanguage { + translationFile := "pkg/minikube/translate/" + preferredLanguage.String() + ".json" + t, err := ioutil.ReadFile(translationFile) + if err != nil { + glog.Infof("Failed to load transalation file for %s: %s", preferredLanguage.String(), err) + return + } + + err = json.Unmarshal(t, &Translations) + if err != nil { + glog.Infof("Failed to populate translation map: %s", err) + } + } +} + +// SetPreferredLanguageTag configures which language future messages should use. +func SetPreferredLanguageTag(l language.Tag) { + glog.Infof("Setting Language to %s ...", l) + preferredLanguage = l +} + +// SetPreferredLanguage configures which language future messages should use, based on a LANG string. +func SetPreferredLanguage(s string) error { + // "C" is commonly used to denote a neutral POSIX locale. See http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html#tag_07_02 + if s == "" || s == "C" { + SetPreferredLanguageTag(defaultLanguage) + return nil + } + // Handles "de_DE" or "de_DE.utf8" + // We don't process encodings, since Rob Pike invented utf8 and we're mostly stuck with it. + parts := strings.Split(s, ".") + l, err := language.Parse(parts[0]) + if err != nil { + return err + } + SetPreferredLanguageTag(l) + return nil +} + +// GetPreferredLanguage returns the preferred language tag. +func GetPreferredLanguage() language.Tag { + return preferredLanguage +} From fd75433f073c4fe84380ad02e4305aa9b03abf05 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 13 May 2019 18:02:44 -0700 Subject: [PATCH 02/25] fixing go mods --- go.mod | 117 ++++++++++++++++++++++++++++++--------------------------- go.sum | 92 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 133 insertions(+), 76 deletions(-) diff --git a/go.mod b/go.mod index 7b7724ea34cb..b4093f63c7db 100644 --- a/go.mod +++ b/go.mod @@ -3,94 +3,99 @@ module k8s.io/minikube go 1.12 require ( - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/Parallels/docker-machine-parallels v1.3.0 + github.com/Sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 // indirect github.com/blang/semver v3.5.0+incompatible - github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 + github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 // indirect github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 - github.com/cpuguy83/go-md2man v1.0.4 - github.com/davecgh/go-spew v0.0.0-20170626231645-782f4967f2dc - github.com/docker/docker v0.0.0-20180917213351-bbe08dc7f0b9 + github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect + github.com/cpuguy83/go-md2man v1.0.4 // indirect + github.com/docker/docker v1.13.1 // indirect github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69 github.com/docker/machine v0.16.1 - github.com/fsnotify/fsnotify v0.0.0-20160816051541-f12c6236fe7b - github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 - github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e + github.com/fatih/color v1.7.0 // indirect + github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 // indirect + github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e // indirect github.com/golang/glog v0.0.0-20141105023935-44145f04b68c - github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 - github.com/golang/protobuf v1.2.0 - github.com/google/btree v1.0.0 + github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 // indirect + github.com/google/btree v1.0.0 // indirect github.com/google/go-cmp v0.2.0 github.com/google/go-containerregistry v0.0.0-20190318164241-019cdfc6adf9 github.com/google/go-github/v25 v25.0.2 - github.com/google/go-querystring v1.0.0 - github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 - github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d - github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 - github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce - github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 - github.com/hashicorp/go-version v1.1.0 - github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 - github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1 + github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 // indirect + github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d // indirect + github.com/gorilla/mux v1.7.1 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce // indirect + github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 // indirect + github.com/hashicorp/go-version v1.1.0 // indirect + github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 // indirect + github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1 // indirect + github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8 - github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 - github.com/inconshreveable/mousetrap v1.0.0 - github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 + github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 // indirect github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345 - github.com/json-iterator/go v1.1.5 - github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 + github.com/json-iterator/go v1.1.5 // indirect + github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 // indirect github.com/libvirt/libvirt-go v3.4.0+incompatible github.com/machine-drivers/docker-machine-driver-vmware v0.1.1 - github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4 - github.com/mattn/go-isatty v0.0.4 - github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b + github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4 // indirect + github.com/mattn/go-colorable v0.1.1 // indirect + github.com/mattn/go-isatty v0.0.5 + github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b // indirect github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 - github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49 + github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49 // indirect github.com/moby/hyperkit v0.0.0-20171020124204-a12cd7250bcd - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd - github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect + github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.7 github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca - github.com/pelletier/go-buffruneio v0.1.0 - github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4 - github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c - github.com/peterbourgon/diskv v2.0.1+incompatible + github.com/pelletier/go-buffruneio v0.1.0 // indirect + github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/browser v0.0.0-20160118053552-9302be274faa github.com/pkg/errors v0.8.0 github.com/pkg/profile v0.0.0-20161223203901-3a8809bd8a80 - github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6 + github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6 // indirect github.com/pmezard/go-difflib v1.0.0 github.com/r2d4/external-storage v0.0.0-20171222174501-8c0e8605dc7b - github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5 - github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 - github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db - github.com/sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 - github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97 - github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a + github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5 // indirect + github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 // indirect + github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db // indirect + github.com/sirupsen/logrus v1.4.1 + github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97 // indirect + github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a // indirect github.com/spf13/cobra v0.0.0-20180228053838-6644d46b81fa - github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80 + github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80 // indirect github.com/spf13/pflag v1.0.1 github.com/spf13/viper v1.0.0 - github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 - github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c + github.com/stretchr/testify v1.3.0 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c // indirect github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 - golang.org/x/net v0.0.0-20190311183353-d8887717615a + golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c - golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 - golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a + golang.org/x/sync v0.0.0-20190423024810-112230192c58 + golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b golang.org/x/text v0.3.2 - golang.org/x/time v0.0.0-20161028155119-f51c12702a4d - google.golang.org/appengine v1.4.0 - gopkg.in/cheggaaa/pb.v1 v1.0.6 - gopkg.in/inf.v0 v0.9.0 - gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054 + golang.org/x/time v0.0.0-20161028155119-f51c12702a4d // indirect + gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect + gopkg.in/cheggaaa/pb.v1 v1.0.6 // indirect + gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect + gopkg.in/inf.v0 v0.9.0 // indirect + gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect k8s.io/api v0.0.0-20180712090710-2d6f90ab1293 k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d - k8s.io/apiserver v0.0.0-20180914001516-67c892841170 + k8s.io/apiserver v0.0.0-20180914001516-67c892841170 // indirect k8s.io/client-go v0.0.0-20180806134042-1f13a808da65 - k8s.io/kube-openapi v0.0.0-20180216212618-50ae88d24ede + k8s.io/kube-openapi v0.0.0-20180216212618-50ae88d24ede // indirect k8s.io/kubernetes v1.11.3 ) diff --git a/go.sum b/go.sum index d001caa1bab8..3d161fc6bb7d 100644 --- a/go.sum +++ b/go.sum @@ -1,26 +1,35 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY= +github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Parallels/docker-machine-parallels v1.3.0 h1:RG1fyf3v1GwXMCeHRiZkB4tL9phFZEv6ixcvRZ1raN8= github.com/Parallels/docker-machine-parallels v1.3.0/go.mod h1:HCOMm3Hulq/xuEVQMyZOuQlA+dSZpFY5kdCTZWjMVis= +github.com/Sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 h1:k1A7eIeUk6rnX2yuagwljW/pDezkK8oSpvPumT9zdZY= +github.com/Sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U= github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 h1:+ziP/wVJWuAORkjv7386TRidVKY57X0bXBZFMeFlW+U= github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9/go.mod h1:txokOny9wavBtq2PWuHmj1P+eFwpCsj+gQeNNANChfU= github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:Yg2hDs4b13Evkpj42FU2idX2cVXVFqQSheXYKM86Qsk= github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:MgJyK38wkzZbiZSKeIeFankxxSA8gayko/nr5x5bgBA= +github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= +github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= github.com/cpuguy83/go-md2man v1.0.4 h1:OwjhDpK9YGCcI5CDf8HcdfsXqr6znFyAJfuZ27ixJsc= github.com/cpuguy83/go-md2man v1.0.4/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY= -github.com/davecgh/go-spew v0.0.0-20170626231645-782f4967f2dc h1:0A0n6a0Y3vW5ktoWKC+ggkGXRzMJWMvqIYlFmsjwQzY= -github.com/davecgh/go-spew v0.0.0-20170626231645-782f4967f2dc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/docker v0.0.0-20180917213351-bbe08dc7f0b9 h1:dArdEP6A7F7aoAph4Gs505ME7QSBjjbRdpklFV384KU= -github.com/docker/docker v0.0.0-20180917213351-bbe08dc7f0b9/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo= +github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69 h1:N4WAsrRIb+4U1yIwJO3FMrLnrr61ael894nygpViQTU= github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/machine v0.16.1 h1:zrgroZounGVkxLmBqMyc1uT2GgapXVjIWHCfBf0udrA= github.com/docker/machine v0.16.1/go.mod h1:I8mPNDeK1uH+JTcUU7X0ZW8KiYz0jyAgNaeSJ1rCfDI= -github.com/fsnotify/fsnotify v0.0.0-20160816051541-f12c6236fe7b h1:lHoxUxMozh/yCASOoFep9dPMva62ztmxKK2VB8//Aoo= -github.com/fsnotify/fsnotify v0.0.0-20160816051541-f12c6236fe7b/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e h1:ago6fNuQ6IhszPsXkeU7qRCyfsIX7L67WDybsAPkLl8= @@ -29,7 +38,6 @@ github.com/golang/glog v0.0.0-20141105023935-44145f04b68c h1:CbdkBQ1/PiAo0FYJhQG github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= @@ -46,6 +54,8 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 h1:ScAXWS+TR6MZKex+7 github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= +github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= @@ -58,8 +68,12 @@ github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 h1:OaRuzt9oCK github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1 h1:9j16AiR0R5hDbDBMzfUfIP9CUbbw6T8nYN4iZz3/wjg= github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI= +github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E= github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8 h1:ARl0RuGZTqBOMXQIfXen0twVSJ8kMojd7ThJf4EBcrc= github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8/go.mod h1:sOC47ru8lB0DlU0EZ7BJ0KCP5rDqOvx0c/5K5ADm8H0= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 h1:FeeCi0I2Fu8kA8IXrdVPtGzym+mW9bzfj9f26EaES9k= github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -72,6 +86,8 @@ github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345 h1:XP1 github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345/go.mod h1:+c1/kUpg2zlkoWqTOvzDs36Wpbm3Gd1nlmtXAEB0WGU= github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 h1:YUrU1/jxRqnt0PSrKj1Uj/wEjk/fjnE80QFfi2Zlj7Q= github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169/go.mod h1:glhvuHOU9Hy7/8PwwdtnarXqLagOX0b/TbZx2zLMqEg= github.com/libvirt/libvirt-go v3.4.0+incompatible h1:Cpyalgj1x8JIeTlL6SDYZBo7j8nY3+5XHqmi8DaunCk= @@ -80,8 +96,10 @@ github.com/machine-drivers/docker-machine-driver-vmware v0.1.1 h1:+E1IKKk+6kaQrC github.com/machine-drivers/docker-machine-driver-vmware v0.1.1/go.mod h1:ej014C83EmSnxJeJ8PtVb8OLJ91PJKO1Q8Y7sM5CK0o= github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4 h1:YVH4JcnWs1z/qQ2Dg5BnGGQL8PcUOO97Sb5w7RyuBl4= github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b h1:idzeyUe3K4aU/SIZWMykIkJJyTD7CgDkxUQEjV07fno= github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 h1:kw1v0NlnN+GZcU8Ma8CLF2Zzgjfx95gs3/GN3vYAPpo= @@ -94,15 +112,21 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.7 h1:wCBv/ZWBkVl/x3xvw4MAMXgjtYbzyNTcZXO5jpmVQuA= +github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.7/go.mod h1:JXS4+OKhbcwDoVTEj0sLFWL1vOwec2g/YBAxZ9owJqY= github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd h1:nEatQ6JnwCT9iYD5uqYUiFqq8tJGX25to8KVKXqya7k= github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca h1:dKRMHfduZ/ZqOHuYGk/0kkTIUbnyorkAfzLOp6Ts8pU= github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pelletier/go-buffruneio v0.1.0 h1:ig6N9Cg71k/P+UUbhwdOFtJWz+qa8/3by7AzMprMWBM= github.com/pelletier/go-buffruneio v0.1.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4 h1:tMVXZ04h5CqgTvMyA8IL1b9xlJz7G+mTcCsYi3WXRtA= github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/browser v0.0.0-20160118053552-9302be274faa h1:od00Tr1U7+cLVtc+RNFmR53spHUF98Ziu33S8UIQnt0= @@ -123,8 +147,8 @@ github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 h1:XRl74t6xHK github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859/go.mod h1:yeYR4SlaRZJct6lwNRKR+qd0CocnxxWDE7Vh5dxsn/w= github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db h1:lrOUn8raSZS/V52c7elGaEyuogqSkEo/Qj2Auo2G1ik= github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 h1:+8J/sCAVv2Y9Ct1BKszDFJEVWv6Aynr2O4FYGUg6+Mc= -github.com/sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97 h1:Gv1HykSEG+RKWWWkM69nPrJKhE/EM2oFb1nBWogHNv8= github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a h1:tPI5RnYZJhcXj0LhJ9pi7PS7gqOhuFR+4HEKyDz3BnQ= @@ -137,6 +161,11 @@ github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +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= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 h1:KM4T3G70MiR+JtqplcYkNVoNz7pDwYaBxWBXQK804So= github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c h1:XZWnr3bsDQWAZg4Ne+cPoXRPILrNlPNQfxBuwLl43is= @@ -145,42 +174,65 @@ github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be h1:sRGd3e18iz github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 h1:Ucx5I1l1+TWXvqFmBigYu4Ub4MLvUuUU/whjoUvV95I= github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097/go.mod h1:lFZSWRIpCfE/pt91hHBBpV6+x87YlCjsp+aIR2qCPPU= -golang.org/x/crypto v0.0.0-20170825220121-81e90905daef h1:R8ubLIilYRXIXpgjOg2l/ECVs3HzVKIjJEhxSsQ91u4= -golang.org/x/crypto v0.0.0-20170825220121-81e90905daef/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20170809000501-1c05540f6879/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 h1:rlLehGeYg6jfoyz/eDqDU1iRXLKfR42nnNh57ytKEWo= +golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c h1:pcBdqVcrlT+A3i+tWsOROFONQyey9tisIQHI4xqVGLg= golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20171031081856-95c657629925 h1:nCH33NboKIsT4HoXBsXTWX8ul303HxWgkc5s2Ezwacg= -golang.org/x/sys v0.0.0-20171031081856-95c657629925/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.6 h1:YQye4a1JysUfXYB6VihDfxb4lxOAei0xS44yN+srOew= gopkg.in/cheggaaa/pb.v1 v1.0.6/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054 h1:ROF+R/wHHruzF40n5DfPv2jwm7rCJwvs8fz+RTZWjLE= -gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= k8s.io/api v0.0.0-20180712090710-2d6f90ab1293 h1:hROmpFC7JMobXFXMmD7ZKZLhDKvr1IKfFJoYS/45G/8= k8s.io/api v0.0.0-20180712090710-2d6f90ab1293/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d h1:MZjlsu9igBoVPZkXpIGoxI6EonqNsXXZU7hhvfQLkd4= From e174f3bdc62316b8f56dcc0bcd90a4f67f35d9e1 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Fri, 17 May 2019 14:20:25 -0700 Subject: [PATCH 03/25] Add semi-functional extractor --- hack/extract.go | 73 +++++++++++++++++++++++++++++ pkg/minikube/console/console.go | 4 +- pkg/minikube/translate/translate.go | 4 ++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 hack/extract.go diff --git a/hack/extract.go b/hack/extract.go new file mode 100644 index 000000000000..d8a2d1371080 --- /dev/null +++ b/hack/extract.go @@ -0,0 +1,73 @@ +package main + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +var funcs []string + +func main() { + paths := []string{"../pkg/minikube/", "../cmd/minikube"} + funcs = []string{"OutStyle", "ErrStyle"} + for _, f := range funcs { + for _, root := range paths { + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if strings.HasSuffix(path, ".go") { + return inspectFile(path, f) + } + return nil + }) + + if err != nil { + panic(err) + } + } + } +} + +func inspectFile(filename string, f string) error { + fset := token.NewFileSet() + r, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + //fmt.Printf("Parsing %s\n", filename) + file, err := parser.ParseFile(fset, "", r, parser.ParseComments) + if err != nil { + return err + } + + ast.Inspect(file, func(x ast.Node) bool { + fd, ok := x.(*ast.FuncDecl) + if !ok { + return true + } + + fmt.Println(fd.Name) + for _, stmt := range fd.Body.List { + fmt.Printf(" %s\n", stmt) + /*if !ok { + return true + } + + if strings.Contains(fmt.Sprintf("%s", s.Fun), f) { + argString := fmt.Sprintf("%s", s.Args[1]) + if strings.Contains(argString, "\"") { + fmt.Printf("%s\n", argString[strings.Index(argString, "\""):strings.LastIndex(argString, "\"")+1]) + } else { + funcs = append(funcs) + } + }*/ + } + return true + }) + + return nil +} diff --git a/pkg/minikube/console/console.go b/pkg/minikube/console/console.go index b99fdd3969fa..576051fba9a3 100644 --- a/pkg/minikube/console/console.go +++ b/pkg/minikube/console/console.go @@ -78,7 +78,7 @@ func OutStyle(style, format string, a ...interface{}) { // Out writes a basic formatted string to stdout func Out(format string, a ...interface{}) { - p := message.NewPrinter(preferredLanguage) + p := message.NewPrinter(translate.GetPreferredLanguage()) if outFile == nil { glog.Errorf("no output file has been set") return @@ -110,7 +110,7 @@ func ErrStyle(style, format string, a ...interface{}) { // Err writes a basic formatted string to stderr func Err(format string, a ...interface{}) { - p := message.NewPrinter(preferredLanguage) + p := message.NewPrinter(translate.GetPreferredLanguage()) if errFile == nil { glog.Errorf("no error file has been set") return diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go index 48cadbce7de3..b4d263e0712e 100644 --- a/pkg/minikube/translate/translate.go +++ b/pkg/minikube/translate/translate.go @@ -42,6 +42,10 @@ var ( // Translate translates the given string to the supplied langauge. func Translate(s string) string { + if preferredLanguage == defaultLanguage { + return s + } + if len(Translations) == 0 { return s } From fbc11c327a899a6fb065975bafbdd95cc91ef4ff Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Wed, 29 May 2019 14:35:28 -0700 Subject: [PATCH 04/25] Recursive search for extractor --- go.mod | 1 + go.sum | 3 ++ hack/extract.go | 92 +++++++++++++++++++++++++++++++-------- pkg/minikube/exit/exit.go | 2 +- 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index e64af2224646..41880d0f9e95 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/fatih/color v1.7.0 // indirect github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 // indirect github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e // indirect + github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 github.com/golang/glog v0.0.0-20141105023935-44145f04b68c github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 // indirect github.com/google/btree v1.0.0 // indirect diff --git a/go.sum b/go.sum index 870a8a39faa5..ca3c0d122d4e 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,8 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e h1:ago6fNuQ6IhszPsXkeU7qRCyfsIX7L67WDybsAPkLl8= github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= +github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= github.com/golang/glog v0.0.0-20141105023935-44145f04b68c h1:CbdkBQ1/PiAo0FYJhQGwASD8wrgNvTdf01g6+O9tNuA= github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= @@ -217,6 +219,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c h1:97SnQk1GYRXJgvwZ8fadnxDOWfKvkNQHH3CtZntPSrM= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= diff --git a/hack/extract.go b/hack/extract.go index d8a2d1371080..3cef3f3904c7 100644 --- a/hack/extract.go +++ b/hack/extract.go @@ -9,17 +9,27 @@ import ( "os" "path/filepath" "strings" + + "github.com/golang-collections/collections/stack" ) -var funcs []string +var funcs map[string]struct{} +var funcStack *stack.Stack func main() { - paths := []string{"../pkg/minikube/", "../cmd/minikube"} - funcs = []string{"OutStyle", "ErrStyle"} - for _, f := range funcs { + paths := []string{"../pkg/minikube/", "../cmd/minikube/"} + //paths := []string{".."} + funcs = map[string]struct{}{"OutStyle": {}, "ErrStyle": {}} + funcStack = stack.New() + funcStack.Push("OutStyle") + funcStack.Push("ErrStyle") + + for funcStack.Len() > 0 { + f := funcStack.Pop().(string) + fmt.Printf("-----%s------\n", f) for _, root := range paths { err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if strings.HasSuffix(path, ".go") { + if strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") { return inspectFile(path, f) } return nil @@ -38,7 +48,7 @@ func inspectFile(filename string, f string) error { if err != nil { return err } - //fmt.Printf("Parsing %s\n", filename) + //fmt.Printf(" Parsing %s\n", filename) file, err := parser.ParseFile(fset, "", r, parser.ParseComments) if err != nil { return err @@ -50,24 +60,68 @@ func inspectFile(filename string, f string) error { return true } - fmt.Println(fd.Name) + //fmt.Println(fd.Name) for _, stmt := range fd.Body.List { - fmt.Printf(" %s\n", stmt) - /*if !ok { - return true - } + //fmt.Printf(" %s\n", stmt) - if strings.Contains(fmt.Sprintf("%s", s.Fun), f) { - argString := fmt.Sprintf("%s", s.Args[1]) - if strings.Contains(argString, "\"") { - fmt.Printf("%s\n", argString[strings.Index(argString, "\""):strings.LastIndex(argString, "\"")+1]) - } else { - funcs = append(funcs) - } - }*/ + //fmt.Printf(" %s: %s\n", reflect.TypeOf(stmt), stmt) + checkStmt(stmt, fd.Name.String(), f) } return true }) return nil } + +func checkStmt(stmt ast.Stmt, fd string, f string) { + // If this line is an expression, see if it's a function call + if t, ok := stmt.(*ast.ExprStmt); ok { + checkCallExpression(t, fd, f) + } + + // If this line is the beginning of an if statment, then check of the body of the block + if b, ok := stmt.(*ast.IfStmt); ok { + for _, s := range b.Body.List { + checkStmt(s, fd, f) + } + } + + // Same for loops + if b, ok := stmt.(*ast.ForStmt); ok { + for _, s := range b.Body.List { + checkStmt(s, fd, f) + } + } +} +func checkCallExpression(t *ast.ExprStmt, fd string, f string) { + if s, ok := t.X.(*ast.CallExpr); ok { + if strings.Contains(fmt.Sprintf("%s", s.Fun), f) && !strings.Contains(fmt.Sprintf("%s", s.Fun), "glog") && len(s.Args) > 0 { + //fmt.Printf(" %s\n", fd.Name) + //fmt.Printf(" %s\n", s.Args) + // If this print call has a string with quote marks, then print that out as a phrase to translate. + hit := false + for i, arg := range s.Args { + // Dealing with inconsistent argument ordering + if (strings.Contains(f, "Style") || strings.Contains(f, "Fatal")) && i == 0 { + continue + } + argString := fmt.Sprintf("%s", arg) + //fmt.Println(argString) + if strings.Contains(argString, "\"") { + fmt.Printf(" %s\n", argString[strings.Index(argString, "\""):strings.LastIndex(argString, "\"")+1]) + hit = true + break + } + } + + // Otherwise, this call used variables passed in from a previous call, add that function to the list of ones to check. + if !hit { + if _, ok := funcs[fd]; !ok { + //fmt.Printf(" ADDING %s TO LIST\n", fd.Name) + funcs[fd] = struct{}{} + funcStack.Push(fd) + } + } + } + } +} diff --git a/pkg/minikube/exit/exit.go b/pkg/minikube/exit/exit.go index bb18b02ca40a..91916fb2ac89 100644 --- a/pkg/minikube/exit/exit.go +++ b/pkg/minikube/exit/exit.go @@ -99,7 +99,7 @@ func displayError(msg string, err error) { // use Warning because Error will display a duplicate message to stderr glog.Warningf(fmt.Sprintf("%s: %v", msg, err)) console.Err("\n") - console.Fatal(msg+": %v", err) + console.Fatal("%s: %v", msg, err) console.Err("\n") console.ErrStyle("sad", "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:") console.ErrStyle("url", "https://github.com/kubernetes/minikube/issues/new") From 610e4f115959add66b14f51ecfa23cf74149aa3c Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Thu, 6 Jun 2019 14:10:32 -0700 Subject: [PATCH 05/25] More extractor work --- cmd/minikube/cmd/root.go | 2 +- cmd/minikube/cmd/start.go | 2 +- hack/extract.go | 177 ++++++++++++++---- pkg/minikube/console/console_test.go | 38 +--- pkg/minikube/notify/notify.go | 14 +- pkg/minikube/notify/notify_test.go | 9 +- pkg/minikube/tests/dir_utils.go | 21 +++ pkg/minikube/translate/fr-FR.json | 3 - pkg/minikube/translate/translate.go | 6 +- .../translate/translations/fr-FR.json | 91 +++++++++ 10 files changed, 273 insertions(+), 90 deletions(-) delete mode 100644 pkg/minikube/translate/fr-FR.json create mode 100644 pkg/minikube/translate/translations/fr-FR.json diff --git a/cmd/minikube/cmd/root.go b/cmd/minikube/cmd/root.go index c8094aa03372..61e90be20d79 100644 --- a/cmd/minikube/cmd/root.go +++ b/cmd/minikube/cmd/root.go @@ -92,7 +92,7 @@ var RootCmd = &cobra.Command{ } if enableUpdateNotification { - notify.MaybePrintUpdateTextFromGithub(os.Stderr) + notify.MaybePrintUpdateTextFromGithub() } }, } diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index fd45b867190d..c47d58e6ea48 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -226,7 +226,7 @@ func runStart(cmd *cobra.Command, args []string) { // Makes minikube node ip to bypass http(s) proxy. since it is local traffic. err = proxy.ExcludeIP(ip) if err != nil { - console.ErrStyle(console.FailureType, "Failed to set NO_PROXY Env. please Use `export NO_PROXY=$NO_PROXY,%s`.", ip) + console.ErrStyle(console.FailureType, "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.", ip) } // Save IP to configuration file for subsequent use config.KubernetesConfig.NodeIP = ip diff --git a/hack/extract.go b/hack/extract.go index 3cef3f3904c7..d950faca54a1 100644 --- a/hack/extract.go +++ b/hack/extract.go @@ -1,13 +1,16 @@ package main import ( + "encoding/json" "fmt" "go/ast" "go/parser" "go/token" "io/ioutil" + "net/url" "os" "path/filepath" + "strconv" "strings" "github.com/golang-collections/collections/stack" @@ -15,21 +18,25 @@ import ( var funcs map[string]struct{} var funcStack *stack.Stack +var translations map[string]interface{} func main() { - paths := []string{"../pkg/minikube/", "../cmd/minikube/"} - //paths := []string{".."} - funcs = map[string]struct{}{"OutStyle": {}, "ErrStyle": {}} + translations = make(map[string]interface{}) + paths := []string{"../cmd", "../pkg"} + //paths := []string{"../cmd/minikube/cmd/delete.go"} + //paths := []string{"../pkg/minikube/cluster/cluster.go"} + funcs = map[string]struct{}{"Translate": {}} funcStack = stack.New() - funcStack.Push("OutStyle") - funcStack.Push("ErrStyle") + for f := range funcs { + funcStack.Push(f) + } for funcStack.Len() > 0 { f := funcStack.Pop().(string) fmt.Printf("-----%s------\n", f) for _, root := range paths { err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") { + if shouldCheckFile(path) { return inspectFile(path, f) } return nil @@ -40,6 +47,56 @@ func main() { } } } + + translationsFiles := "../pkg/minikube/translate/translations" + err := filepath.Walk(translationsFiles, func(path string, info os.FileInfo, err error) error { + if info.Mode().IsDir() { + return nil + } + fmt.Println(path) + var currentTranslations map[string]interface{} + f, err := ioutil.ReadFile(path) + if err != nil { + return err + } + err = json.Unmarshal(f, ¤tTranslations) + if err != nil { + return err + } + + fmt.Println(currentTranslations) + + for k := range translations { + fmt.Println(k) + if _, ok := currentTranslations[k]; !ok { + currentTranslations[k] = " " + } + } + + c, err := json.MarshalIndent(currentTranslations, "", "\t") + if err != nil { + return err + } + err = ioutil.WriteFile(path, c, info.Mode()) + return err + }) + + if err != nil { + panic(err) + } + + fmt.Println("Done!") +} + +func addFuncToList(f string) { + if _, ok := funcs[f]; !ok { + funcs[f] = struct{}{} + funcStack.Push(f) + } +} + +func shouldCheckFile(path string) bool { + return strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") } func inspectFile(filename string, f string) error { @@ -57,14 +114,23 @@ func inspectFile(filename string, f string) error { ast.Inspect(file, func(x ast.Node) bool { fd, ok := x.(*ast.FuncDecl) if !ok { + /*gd, ok := x.(*ast.GenDecl) + if !ok { + return true + } + for _, spec := range gd.Specs { + if vs, ok := spec.(*ast.ValueSpec); ok { + for _, v := range vs.Values { + if ue, ok := v.(*ast.UnaryExpr); ok { + fmt.Printf("%s: %s\n", ue.X, reflect.TypeOf(ue.X)) + } + } + } + }*/ return true } - //fmt.Println(fd.Name) for _, stmt := range fd.Body.List { - //fmt.Printf(" %s\n", stmt) - - //fmt.Printf(" %s: %s\n", reflect.TypeOf(stmt), stmt) checkStmt(stmt, fd.Name.String(), f) } return true @@ -73,53 +139,82 @@ func inspectFile(filename string, f string) error { return nil } -func checkStmt(stmt ast.Stmt, fd string, f string) { +func checkStmt(stmt ast.Stmt, parentFunc string, f string) { // If this line is an expression, see if it's a function call if t, ok := stmt.(*ast.ExprStmt); ok { - checkCallExpression(t, fd, f) + checkCallExpression(t, parentFunc, f) } // If this line is the beginning of an if statment, then check of the body of the block if b, ok := stmt.(*ast.IfStmt); ok { - for _, s := range b.Body.List { - checkStmt(s, fd, f) - } + checkIfStmt(b, parentFunc, f) } // Same for loops if b, ok := stmt.(*ast.ForStmt); ok { for _, s := range b.Body.List { - checkStmt(s, fd, f) + checkStmt(s, parentFunc, f) } } } -func checkCallExpression(t *ast.ExprStmt, fd string, f string) { - if s, ok := t.X.(*ast.CallExpr); ok { - if strings.Contains(fmt.Sprintf("%s", s.Fun), f) && !strings.Contains(fmt.Sprintf("%s", s.Fun), "glog") && len(s.Args) > 0 { - //fmt.Printf(" %s\n", fd.Name) - //fmt.Printf(" %s\n", s.Args) - // If this print call has a string with quote marks, then print that out as a phrase to translate. - hit := false - for i, arg := range s.Args { - // Dealing with inconsistent argument ordering - if (strings.Contains(f, "Style") || strings.Contains(f, "Fatal")) && i == 0 { - continue - } - argString := fmt.Sprintf("%s", arg) - //fmt.Println(argString) - if strings.Contains(argString, "\"") { - fmt.Printf(" %s\n", argString[strings.Index(argString, "\""):strings.LastIndex(argString, "\"")+1]) - hit = true - break - } + +func checkIfStmt(stmt *ast.IfStmt, parentFunc string, f string) { + for _, s := range stmt.Body.List { + checkStmt(s, parentFunc, f) + } + if stmt.Else != nil { + // A straight else + if block, ok := stmt.Else.(*ast.BlockStmt); ok { + for _, s := range block.List { + checkStmt(s, parentFunc, f) } + } + + // An else if + if elseif, ok := stmt.Else.(*ast.IfStmt); ok { + checkIfStmt(elseif, parentFunc, f) + } + + } +} - // Otherwise, this call used variables passed in from a previous call, add that function to the list of ones to check. - if !hit { - if _, ok := funcs[fd]; !ok { - //fmt.Printf(" ADDING %s TO LIST\n", fd.Name) - funcs[fd] = struct{}{} - funcStack.Push(fd) +func checkCallExpression(t *ast.ExprStmt, parentFunc string, f string) { + if s, ok := t.X.(*ast.CallExpr); ok { + sf, ok := s.Fun.(*ast.SelectorExpr) + if !ok { + addFuncToList(parentFunc) + return + } + if f == sf.Sel.Name && len(s.Args) > 0 { + addFuncToList(parentFunc) + for _, arg := range s.Args { + // Find references to strings + if i, ok := arg.(*ast.Ident); ok { + if i.Obj != nil { + if as, ok := i.Obj.Decl.(*ast.AssignStmt); ok { + if rhs, ok := as.Rhs[0].(*ast.BasicLit); ok { + fmt.Printf(" %s\n", rhs.Value) + translations[rhs.Value] = "" + break + } + } + } + } + // Find string arguments + if argString, ok := arg.(*ast.BasicLit); ok { + stringToTranslate := argString.Value + // Don't translate integers + if _, err := strconv.Atoi(stringToTranslate); err != nil { + //Don't translate URLs + if u, err := url.Parse(stringToTranslate[1 : len(stringToTranslate)-1]); err != nil || u.Scheme == "" || u.Host == "" { + // Don't translate empty strings + if len(stringToTranslate) > 2 { + translations[stringToTranslate] = "" + fmt.Printf(" %s\n", stringToTranslate) + break + } + } + } } } } diff --git a/pkg/minikube/console/console_test.go b/pkg/minikube/console/console_test.go index 64fdab69f2e5..bc513e247d32 100644 --- a/pkg/minikube/console/console_test.go +++ b/pkg/minikube/console/console_test.go @@ -17,7 +17,6 @@ limitations under the License. package console import ( - "bytes" "fmt" "os" "strconv" @@ -25,32 +24,13 @@ import ( "golang.org/x/text/language" "golang.org/x/text/message" + "k8s.io/minikube/pkg/minikube/tests" "k8s.io/minikube/pkg/minikube/translate" ) -// fakeFile satisfies fdWriter -type fakeFile struct { - b bytes.Buffer -} - -func newFakeFile() *fakeFile { - return &fakeFile{} -} - -func (f *fakeFile) Fd() uintptr { - return uintptr(0) -} - -func (f *fakeFile) Write(p []byte) (int, error) { - return f.b.Write(p) -} -func (f *fakeFile) String() string { - return f.b.String() -} - func TestOutStyle(t *testing.T) { - var tests = []struct { + var testCases = []struct { style StyleEnum message string params []interface{} @@ -65,12 +45,12 @@ func TestOutStyle(t *testing.T) { {Issue, "http://i/%d", []interface{}{10000}, " ▪ http://i/10000\n", " - http://i/10000\n"}, {Usage, "raw: %s %s", []interface{}{"'%'", "%d"}, "💡 raw: '%' %d\n", "* raw: '%' %d\n"}, } - for _, tc := range tests { + for _, tc := range testCases { for _, override := range []bool{true, false} { t.Run(fmt.Sprintf("%s-override-%v", tc.message, override), func(t *testing.T) { // Set MINIKUBE_IN_STYLE= os.Setenv(OverrideEnv, strconv.FormatBool(override)) - f := newFakeFile() + f := tests.NewFakeFile() SetOutFile(f) OutStyle(tc.style, tc.message, tc.params...) got := f.String() @@ -94,7 +74,7 @@ func TestOut(t *testing.T) { t.Fatalf("setstring: %v", err) } - var tests = []struct { + var testCases = []struct { format string lang language.Tag arg interface{} @@ -105,10 +85,10 @@ func TestOut(t *testing.T) { {format: "Installing Kubernetes version %s ...", lang: language.AmericanEnglish, arg: "v1.13", want: "Installing Kubernetes version v1.13 ..."}, {format: "Parameter encoding: %s", arg: "%s%%%d", want: "Parameter encoding: %s%%%d"}, } - for _, tc := range tests { + for _, tc := range testCases { t.Run(tc.format, func(t *testing.T) { translate.SetPreferredLanguageTag(tc.lang) - f := newFakeFile() + f := tests.NewFakeFile() SetOutFile(f) ErrLn("unrelated message") Out(tc.format, tc.arg) @@ -122,7 +102,7 @@ func TestOut(t *testing.T) { func TestErr(t *testing.T) { os.Setenv(OverrideEnv, "0") - f := newFakeFile() + f := tests.NewFakeFile() SetErrFile(f) Err("xyz123 %s\n", "%s%%%d") OutLn("unrelated message") @@ -136,7 +116,7 @@ func TestErr(t *testing.T) { func TestErrStyle(t *testing.T) { os.Setenv(OverrideEnv, "1") - f := newFakeFile() + f := tests.NewFakeFile() SetErrFile(f) ErrStyle(FatalType, "error: %s", "%s%%%d") got := f.String() diff --git a/pkg/minikube/notify/notify.go b/pkg/minikube/notify/notify.go index dc94b3d1c490..2a10ad81e5e8 100644 --- a/pkg/minikube/notify/notify.go +++ b/pkg/minikube/notify/notify.go @@ -19,7 +19,6 @@ package notify import ( "encoding/json" "fmt" - "io" "io/ioutil" "net/http" "runtime" @@ -31,6 +30,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/version" ) @@ -43,12 +43,12 @@ var ( ) // MaybePrintUpdateTextFromGithub prints update text if needed, from github -func MaybePrintUpdateTextFromGithub(output io.Writer) { - MaybePrintUpdateText(output, constants.GithubMinikubeReleasesURL, lastUpdateCheckFilePath) +func MaybePrintUpdateTextFromGithub() { + MaybePrintUpdateText(constants.GithubMinikubeReleasesURL, lastUpdateCheckFilePath) } // MaybePrintUpdateText prints update text if needed -func MaybePrintUpdateText(output io.Writer, url string, lastUpdatePath string) { +func MaybePrintUpdateText(url string, lastUpdatePath string) { if !shouldCheckURLVersion(lastUpdatePath) { return } @@ -66,12 +66,12 @@ func MaybePrintUpdateText(output io.Writer, url string, lastUpdatePath string) { if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil { glog.Errorf("write time failed: %v", err) } - fmt.Fprintf(output, `There is a newer version of minikube available (%s%s). Download it here: + console.ErrStyle(console.WarningType, `There is a newer version of minikube available (%s%s). Download it here: %s%s - + To disable this notification, run the following: minikube config set WantUpdateNotification false -`, + `, version.VersionPrefix, latestVersion, updateLinkPrefix, latestVersion) } } diff --git a/pkg/minikube/notify/notify_test.go b/pkg/minikube/notify/notify_test.go index 62861c549a15..e78f6bf7b30a 100644 --- a/pkg/minikube/notify/notify_test.go +++ b/pkg/minikube/notify/notify_test.go @@ -17,7 +17,6 @@ limitations under the License. package notify import ( - "bytes" "encoding/json" "fmt" "net/http" @@ -30,6 +29,7 @@ import ( "github.com/blang/semver" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/tests" "k8s.io/minikube/pkg/version" ) @@ -150,7 +150,8 @@ func TestMaybePrintUpdateText(t *testing.T) { viper.Set(config.WantUpdateNotification, true) viper.Set(config.ReminderWaitPeriodInHours, 24) - var outputBuffer bytes.Buffer + outputBuffer := tests.NewFakeFile() + console.SetErrFile(outputBuffer) lastUpdateCheckFilePath := filepath.Join(tempDir, "last_update_check") // test that no update text is printed if the latest version is lower/equal to the current version @@ -161,7 +162,7 @@ func TestMaybePrintUpdateText(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - MaybePrintUpdateText(&outputBuffer, server.URL, lastUpdateCheckFilePath) + MaybePrintUpdateText(server.URL, lastUpdateCheckFilePath) if len(outputBuffer.String()) != 0 { t.Fatalf("Expected MaybePrintUpdateText to not output text as the current version is %s and version %s was served from URL but output was [%s]", version.GetVersion(), latestVersionFromURL, outputBuffer.String()) @@ -175,7 +176,7 @@ func TestMaybePrintUpdateText(t *testing.T) { server = httptest.NewServer(handler) defer server.Close() - MaybePrintUpdateText(&outputBuffer, server.URL, lastUpdateCheckFilePath) + MaybePrintUpdateText(server.URL, lastUpdateCheckFilePath) if len(outputBuffer.String()) == 0 { t.Fatalf("Expected MaybePrintUpdateText to output text as the current version is %s and version %s was served from URL but output was [%s]", version.GetVersion(), latestVersionFromURL, outputBuffer.String()) diff --git a/pkg/minikube/tests/dir_utils.go b/pkg/minikube/tests/dir_utils.go index c85915ec329b..c1ee8bd63b61 100644 --- a/pkg/minikube/tests/dir_utils.go +++ b/pkg/minikube/tests/dir_utils.go @@ -17,6 +17,7 @@ limitations under the License. package tests import ( + "bytes" "io/ioutil" "log" "os" @@ -43,3 +44,23 @@ func MakeTempDir() string { os.Setenv(constants.MinikubeHome, tempDir) return constants.GetMinipath() } + +// FakeFile satisfies fdWriter +type FakeFile struct { + b bytes.Buffer +} + +func NewFakeFile() *FakeFile { + return &FakeFile{} +} + +func (f *FakeFile) Fd() uintptr { + return uintptr(0) +} + +func (f *FakeFile) Write(p []byte) (int, error) { + return f.b.Write(p) +} +func (f *FakeFile) String() string { + return f.b.String() +} diff --git a/pkg/minikube/translate/fr-FR.json b/pkg/minikube/translate/fr-FR.json deleted file mode 100644 index 9b6e844f724d..000000000000 --- a/pkg/minikube/translate/fr-FR.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Re-using the currently running %s VM for %q ...": "Réutilisant le VM %s en cours d'exécution pour %q ..." -} diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go index b4d263e0712e..933e8d029210 100644 --- a/pkg/minikube/translate/translate.go +++ b/pkg/minikube/translate/translate.go @@ -23,7 +23,6 @@ import ( "github.com/cloudfoundry-attic/jibber_jabber" "github.com/golang/glog" - "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/text/language" ) @@ -36,8 +35,6 @@ var ( // Translations is a translation map from strings that can be output to console // to its translation in the user's system locale. Translations map[string]interface{} - - localizer i18n.Localizer ) // Translate translates the given string to the supplied langauge. @@ -69,7 +66,7 @@ func DetermineLocale() { // Load translations for preferred language into memory. if preferredLanguage != defaultLanguage { - translationFile := "pkg/minikube/translate/" + preferredLanguage.String() + ".json" + translationFile := "pkg/minikube/translate/translations" + preferredLanguage.String() + ".json" t, err := ioutil.ReadFile(translationFile) if err != nil { glog.Infof("Failed to load transalation file for %s: %s", preferredLanguage.String(), err) @@ -81,6 +78,7 @@ func DetermineLocale() { glog.Infof("Failed to populate translation map: %s", err) } } + } // SetPreferredLanguageTag configures which language future messages should use. diff --git a/pkg/minikube/translate/translations/fr-FR.json b/pkg/minikube/translate/translations/fr-FR.json new file mode 100644 index 000000000000..195ed02073c3 --- /dev/null +++ b/pkg/minikube/translate/translations/fr-FR.json @@ -0,0 +1,91 @@ +{ + "\"%s: %v\"": " ", + "\"Advice: %s\"": " ", + "\"Alternatively, you may delete the existing VM using `minikube delete -p %s`\"": " ", + "\"Configuring environment for Kubernetes %s on %s %s\"": " ", + "\"Configuring local host environment ...\"": " ", + "\"Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...\"": " ", + "\"Creating mount %s ...\"": " ", + "\"Deleting %q from %s ...\"": " ", + "\"Documentation: %s\"": " ", + "\"Done! kubectl is now configured to use %q\"": " ", + "\"Download complete!\"": " ", + "\"Downloading %s %s\"": " ", + "\"Downloading Minikube ISO ...\"": " ", + "\"Error getting machine status\"": " ", + "\"Error restarting cluster\"": " ", + "\"Error starting cluster\"": " ", + "\"Error starting mount\"": " ", + "\"Error writing mount pid\"": " ", + "\"Error: [%s] %v\"": " ", + "\"Failed to cache ISO\"": " ", + "\"Failed to cache binaries\"": " ", + "\"Failed to cache images\"": " ", + "\"Failed to check if machine exists\"": " ", + "\"Failed to check main repository and mirrors for images for images\"": " ", + "\"Failed to chown %s: %v\"": " ", + "\"Failed to enable container runtime\"": " ", + "\"Failed to generate config\"": " ", + "\"Failed to get bootstrapper\"": " ", + "\"Failed to get command runner\"": " ", + "\"Failed to get driver URL\"": " ", + "\"Failed to get machine client\"": " ", + "\"Failed to save config\"": " ", + "\"Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.\"": " ", + "\"Failed to setup certs\"": " ", + "\"Failed to setup kubeconfig\"": " ", + "\"Failed to update cluster\"": " ", + "\"For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/\"": " ", + "\"For more information, see:\"": " ", + "\"If the above advice does not help, please let us know: \"": " ", + "\"Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.\"": " ", + "\"Kubernetes downgrade is not supported, will continue to use %v\"": " ", + "\"Launching Kubernetes ... \"": " ", + "\"None of known repositories in your location is accessible. Use %s as fallback.\"": " ", + "\"None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag\"": " ", + "\"Please enter a value:\"": " ", + "\"Powering off %q via SSH ...\"": " ", + "\"Pulling images ...\"": " ", + "\"Re-using the currently running %s VM for %q ...\"": " ", + "\"Related issues:\"": " ", + "\"Relaunching Kubernetes %s using %s ... \"": " ", + "\"Requested disk size (%dMB) is less than minimum of %dMB\"": " ", + "\"Restarting existing %s VM for %q ...\"": " ", + "\"Sorry that minikube crashed. If this was unexpected, we would love to hear from you:\"": " ", + "\"Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2\"": " ", + "\"Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2\"": " ", + "\"Stopping %q in %s ...\"": " ", + "\"The 'none' driver provides limited isolation and may reduce system security and reliability.\"": " ", + "\"These changes will take effect upon a minikube delete and then a minikube start\"": " ", + "\"This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true\"": " ", + "\"Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.\"": " ", + "\"To connect to this cluster, use: kubectl --context=%s\"": " ", + "\"To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`\"": " ", + "\"To use kubectl or minikube commands as your own user, you may\"": " ", + "\"Unable to bind flags\"": " ", + "\"Unable to get VM IP address\"": " ", + "\"Unable to load cached images from config file.\"": " ", + "\"Unable to load cached images: %v\"": " ", + "\"Unable to load config: %v\"": " ", + "\"Unable to parse %q: %v\"": " ", + "\"Unable to pull images, which may be OK: %v\"": " ", + "\"Unable to start VM\"": " ", + "\"Verifying:\"": " ", + "\"Wait failed\"": " ", + "\"Waiting for SSH access ...\"": " ", + "\"checking main repository and mirrors for images\"": " ", + "\"error getting driver\"": " ", + "\"kubectl and minikube configuration will be stored in %s\"": " ", + "\"minikube %s on %s (%s)\"": " ", + "\"minikube is not running, so the service cannot be accessed\"": " ", + "\"minikube will upgrade the local cluster from Kubernetes %s to %s\"": " ", + "\"need to relocate them. For example, to overwrite your own settings:\"": " ", + "\"sudo chown -R $USER $HOME/.kube $HOME/.minikube\"": " ", + "\"sudo mv %s/.kube %s/.minikube $HOME\"": " ", + "\"unable to bind flags\"": " ", + "\"unable to set logtostderr\"": " ", + "\"unsupported driver: %s\"": " ", + "\"using image repository %s\"": " ", + "Waiting for SSH access ...": "Attendant acces SSH ...", + "`There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\t\t\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n\t\t`": " " +} \ No newline at end of file From 3447499a33e814d15135dfda3070e0841b309ecd Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 10 Jun 2019 11:45:14 -0700 Subject: [PATCH 06/25] Robust extraction yaaaaaaaay --- hack/extract.go | 63 ++++--- .../translate/translations/fr-FR.json | 175 +++++++++--------- 2 files changed, 126 insertions(+), 112 deletions(-) diff --git a/hack/extract.go b/hack/extract.go index d950faca54a1..e641664f2719 100644 --- a/hack/extract.go +++ b/hack/extract.go @@ -31,9 +31,10 @@ func main() { funcStack.Push(f) } + fmt.Println("Compiling translation strings...") for funcStack.Len() > 0 { f := funcStack.Pop().(string) - fmt.Printf("-----%s------\n", f) + //fmt.Printf("-----%s------\n", f) for _, root := range paths { err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if shouldCheckFile(path) { @@ -48,12 +49,22 @@ func main() { } } + err := writeStringsToFiles() + + if err != nil { + panic(err) + } + + fmt.Println("Done!") +} + +func writeStringsToFiles() error { translationsFiles := "../pkg/minikube/translate/translations" err := filepath.Walk(translationsFiles, func(path string, info os.FileInfo, err error) error { if info.Mode().IsDir() { return nil } - fmt.Println(path) + fmt.Printf("Writing to %s\n", filepath.Base(path)) var currentTranslations map[string]interface{} f, err := ioutil.ReadFile(path) if err != nil { @@ -64,10 +75,10 @@ func main() { return err } - fmt.Println(currentTranslations) + //fmt.Println(currentTranslations) for k := range translations { - fmt.Println(k) + //fmt.Println(k) if _, ok := currentTranslations[k]; !ok { currentTranslations[k] = " " } @@ -81,11 +92,7 @@ func main() { return err }) - if err != nil { - panic(err) - } - - fmt.Println("Done!") + return err } func addFuncToList(f string) { @@ -193,30 +200,38 @@ func checkCallExpression(t *ast.ExprStmt, parentFunc string, f string) { if i.Obj != nil { if as, ok := i.Obj.Decl.(*ast.AssignStmt); ok { if rhs, ok := as.Rhs[0].(*ast.BasicLit); ok { - fmt.Printf(" %s\n", rhs.Value) - translations[rhs.Value] = "" - break + if addStringToList(rhs.Value) { + break + } } } } } // Find string arguments if argString, ok := arg.(*ast.BasicLit); ok { - stringToTranslate := argString.Value - // Don't translate integers - if _, err := strconv.Atoi(stringToTranslate); err != nil { - //Don't translate URLs - if u, err := url.Parse(stringToTranslate[1 : len(stringToTranslate)-1]); err != nil || u.Scheme == "" || u.Host == "" { - // Don't translate empty strings - if len(stringToTranslate) > 2 { - translations[stringToTranslate] = "" - fmt.Printf(" %s\n", stringToTranslate) - break - } - } + if addStringToList(argString.Value) { + break } } } } } } + +func addStringToList(s string) bool { + // Don't translate empty strings + if len(s) > 2 { + // Parse out quote marks + stringToTranslate := s[1 : len(s)-1] + // Don't translate integers + if _, err := strconv.Atoi(stringToTranslate); err != nil { + //Don't translate URLs + if u, err := url.Parse(stringToTranslate); err != nil || u.Scheme == "" || u.Host == "" { + translations[stringToTranslate] = "" + //fmt.Printf(" %s\n", stringToTranslate) + return true + } + } + } + return false +} diff --git a/pkg/minikube/translate/translations/fr-FR.json b/pkg/minikube/translate/translations/fr-FR.json index 195ed02073c3..f39cdc88b163 100644 --- a/pkg/minikube/translate/translations/fr-FR.json +++ b/pkg/minikube/translate/translations/fr-FR.json @@ -1,91 +1,90 @@ { - "\"%s: %v\"": " ", - "\"Advice: %s\"": " ", - "\"Alternatively, you may delete the existing VM using `minikube delete -p %s`\"": " ", - "\"Configuring environment for Kubernetes %s on %s %s\"": " ", - "\"Configuring local host environment ...\"": " ", - "\"Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...\"": " ", - "\"Creating mount %s ...\"": " ", - "\"Deleting %q from %s ...\"": " ", - "\"Documentation: %s\"": " ", - "\"Done! kubectl is now configured to use %q\"": " ", - "\"Download complete!\"": " ", - "\"Downloading %s %s\"": " ", - "\"Downloading Minikube ISO ...\"": " ", - "\"Error getting machine status\"": " ", - "\"Error restarting cluster\"": " ", - "\"Error starting cluster\"": " ", - "\"Error starting mount\"": " ", - "\"Error writing mount pid\"": " ", - "\"Error: [%s] %v\"": " ", - "\"Failed to cache ISO\"": " ", - "\"Failed to cache binaries\"": " ", - "\"Failed to cache images\"": " ", - "\"Failed to check if machine exists\"": " ", - "\"Failed to check main repository and mirrors for images for images\"": " ", - "\"Failed to chown %s: %v\"": " ", - "\"Failed to enable container runtime\"": " ", - "\"Failed to generate config\"": " ", - "\"Failed to get bootstrapper\"": " ", - "\"Failed to get command runner\"": " ", - "\"Failed to get driver URL\"": " ", - "\"Failed to get machine client\"": " ", - "\"Failed to save config\"": " ", - "\"Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.\"": " ", - "\"Failed to setup certs\"": " ", - "\"Failed to setup kubeconfig\"": " ", - "\"Failed to update cluster\"": " ", - "\"For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/\"": " ", - "\"For more information, see:\"": " ", - "\"If the above advice does not help, please let us know: \"": " ", - "\"Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.\"": " ", - "\"Kubernetes downgrade is not supported, will continue to use %v\"": " ", - "\"Launching Kubernetes ... \"": " ", - "\"None of known repositories in your location is accessible. Use %s as fallback.\"": " ", - "\"None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag\"": " ", - "\"Please enter a value:\"": " ", - "\"Powering off %q via SSH ...\"": " ", - "\"Pulling images ...\"": " ", - "\"Re-using the currently running %s VM for %q ...\"": " ", - "\"Related issues:\"": " ", - "\"Relaunching Kubernetes %s using %s ... \"": " ", - "\"Requested disk size (%dMB) is less than minimum of %dMB\"": " ", - "\"Restarting existing %s VM for %q ...\"": " ", - "\"Sorry that minikube crashed. If this was unexpected, we would love to hear from you:\"": " ", - "\"Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2\"": " ", - "\"Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2\"": " ", - "\"Stopping %q in %s ...\"": " ", - "\"The 'none' driver provides limited isolation and may reduce system security and reliability.\"": " ", - "\"These changes will take effect upon a minikube delete and then a minikube start\"": " ", - "\"This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true\"": " ", - "\"Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.\"": " ", - "\"To connect to this cluster, use: kubectl --context=%s\"": " ", - "\"To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`\"": " ", - "\"To use kubectl or minikube commands as your own user, you may\"": " ", - "\"Unable to bind flags\"": " ", - "\"Unable to get VM IP address\"": " ", - "\"Unable to load cached images from config file.\"": " ", - "\"Unable to load cached images: %v\"": " ", - "\"Unable to load config: %v\"": " ", - "\"Unable to parse %q: %v\"": " ", - "\"Unable to pull images, which may be OK: %v\"": " ", - "\"Unable to start VM\"": " ", - "\"Verifying:\"": " ", - "\"Wait failed\"": " ", - "\"Waiting for SSH access ...\"": " ", - "\"checking main repository and mirrors for images\"": " ", - "\"error getting driver\"": " ", - "\"kubectl and minikube configuration will be stored in %s\"": " ", - "\"minikube %s on %s (%s)\"": " ", - "\"minikube is not running, so the service cannot be accessed\"": " ", - "\"minikube will upgrade the local cluster from Kubernetes %s to %s\"": " ", - "\"need to relocate them. For example, to overwrite your own settings:\"": " ", - "\"sudo chown -R $USER $HOME/.kube $HOME/.minikube\"": " ", - "\"sudo mv %s/.kube %s/.minikube $HOME\"": " ", - "\"unable to bind flags\"": " ", - "\"unable to set logtostderr\"": " ", - "\"unsupported driver: %s\"": " ", - "\"using image repository %s\"": " ", + "%s: %v": " ", + "Advice: %s": " ", + "Alternatively, you may delete the existing VM using `minikube delete -p %s`": " ", + "Configuring environment for Kubernetes %s on %s %s": " ", + "Configuring local host environment ...": " ", + "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": " ", + "Creating mount %s ...": " ", + "Deleting %q from %s ...": " ", + "Documentation: %s": " ", + "Done! kubectl is now configured to use %q": " ", + "Download complete!": " ", + "Downloading %s %s": " ", + "Downloading Minikube ISO ...": " ", + "Error getting machine status": " ", + "Error restarting cluster": " ", + "Error starting cluster": " ", + "Error starting mount": " ", + "Error writing mount pid": " ", + "Error: [%s] %v": " ", + "Failed to cache ISO": " ", + "Failed to cache binaries": " ", + "Failed to cache images": " ", + "Failed to check if machine exists": " ", + "Failed to check main repository and mirrors for images for images": " ", + "Failed to chown %s: %v": " ", + "Failed to enable container runtime": " ", + "Failed to generate config": " ", + "Failed to get bootstrapper": " ", + "Failed to get command runner": " ", + "Failed to get driver URL": " ", + "Failed to get machine client": " ", + "Failed to save config": " ", + "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.": " ", + "Failed to setup certs": " ", + "Failed to setup kubeconfig": " ", + "Failed to update cluster": " ", + "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/": " ", + "For more information, see:": " ", + "If the above advice does not help, please let us know: ": " ", + "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": " ", + "Kubernetes downgrade is not supported, will continue to use %v": " ", + "Launching Kubernetes ... ": " ", + "None of known repositories in your location is accessible. Use %s as fallback.": " ", + "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": " ", + "Please enter a value:": " ", + "Powering off %q via SSH ...": " ", + "Pulling images ...": " ", + "Re-using the currently running %s VM for %q ...": " ", + "Related issues:": " ", + "Relaunching Kubernetes %s using %s ... ": " ", + "Requested disk size (%dMB) is less than minimum of %dMB": " ", + "Restarting existing %s VM for %q ...": " ", + "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": " ", + "Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2": " ", + "Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2": " ", + "Stopping %q in %s ...": " ", + "The 'none' driver provides limited isolation and may reduce system security and reliability.": " ", + "There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\t\t\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n\t\t": " ", + "These changes will take effect upon a minikube delete and then a minikube start": " ", + "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true": " ", + "Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.": " ", + "To connect to this cluster, use: kubectl --context=%s": " ", + "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`": " ", + "To use kubectl or minikube commands as your own user, you may": " ", + "Unable to bind flags": " ", + "Unable to get VM IP address": " ", + "Unable to load cached images from config file.": " ", + "Unable to load cached images: %v": " ", + "Unable to load config: %v": " ", + "Unable to parse %q: %v": " ", + "Unable to pull images, which may be OK: %v": " ", + "Unable to start VM": " ", + "Verifying:": " ", + "Wait failed": " ", "Waiting for SSH access ...": "Attendant acces SSH ...", - "`There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\t\t\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n\t\t`": " " + "checking main repository and mirrors for images": " ", + "error getting driver": " ", + "kubectl and minikube configuration will be stored in %s": " ", + "minikube %s on %s (%s)": " ", + "minikube is not running, so the service cannot be accessed": " ", + "minikube will upgrade the local cluster from Kubernetes %s to %s": " ", + "need to relocate them. For example, to overwrite your own settings:": " ", + "sudo chown -R $USER $HOME/.kube $HOME/.minikube": " ", + "sudo mv %s/.kube %s/.minikube $HOME": " ", + "unable to bind flags": " ", + "unable to set logtostderr": " ", + "unsupported driver: %s": " ", + "using image repository %s": " " } \ No newline at end of file From 4630cccca4949f78ea59f39e7ef8abf77ffa3cc0 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 10 Jun 2019 13:11:49 -0700 Subject: [PATCH 07/25] linting --- hack/extract.go | 22 +++++++++++++++++++--- pkg/minikube/translate/translate.go | 8 ++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/hack/extract.go b/hack/extract.go index e641664f2719..b2b1fa115bd0 100644 --- a/hack/extract.go +++ b/hack/extract.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package main import ( @@ -60,7 +76,7 @@ func main() { func writeStringsToFiles() error { translationsFiles := "../pkg/minikube/translate/translations" - err := filepath.Walk(translationsFiles, func(path string, info os.FileInfo, err error) error { + e := filepath.Walk(translationsFiles, func(path string, info os.FileInfo, err error) error { if info.Mode().IsDir() { return nil } @@ -92,7 +108,7 @@ func writeStringsToFiles() error { return err }) - return err + return e } func addFuncToList(f string) { @@ -152,7 +168,7 @@ func checkStmt(stmt ast.Stmt, parentFunc string, f string) { checkCallExpression(t, parentFunc, f) } - // If this line is the beginning of an if statment, then check of the body of the block + // If this line is the beginning of an if statement, then check of the body of the block if b, ok := stmt.(*ast.IfStmt); ok { checkIfStmt(b, parentFunc, f) } diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go index 933e8d029210..ee0b96f3a567 100644 --- a/pkg/minikube/translate/translate.go +++ b/pkg/minikube/translate/translate.go @@ -37,7 +37,7 @@ var ( Translations map[string]interface{} ) -// Translate translates the given string to the supplied langauge. +// Translate translates the given string to the supplied language. func Translate(s string) string { if preferredLanguage == defaultLanguage { return s @@ -62,7 +62,11 @@ func DetermineLocale() { glog.Warningf("Getting system locale failed: %s", err) locale = "" } - SetPreferredLanguage(locale) + err = SetPreferredLanguage(locale) + if err != nil { + glog.Warningf("Setting locale failed: %s", err) + locale = "" + } // Load translations for preferred language into memory. if preferredLanguage != defaultLanguage { From 0c437316719d981587e84cd40285a9f5150bb5a4 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 10 Jun 2019 14:14:38 -0700 Subject: [PATCH 08/25] Small fixes to make things work --- pkg/minikube/notify/notify.go | 4 ++-- pkg/minikube/problem/problem.go | 3 ++- pkg/minikube/translate/translate.go | 7 +++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pkg/minikube/notify/notify.go b/pkg/minikube/notify/notify.go index 2a10ad81e5e8..d657786d602e 100644 --- a/pkg/minikube/notify/notify.go +++ b/pkg/minikube/notify/notify.go @@ -68,10 +68,10 @@ func MaybePrintUpdateText(url string, lastUpdatePath string) { } console.ErrStyle(console.WarningType, `There is a newer version of minikube available (%s%s). Download it here: %s%s - + To disable this notification, run the following: minikube config set WantUpdateNotification false - `, +`, version.VersionPrefix, latestVersion, updateLinkPrefix, latestVersion) } } diff --git a/pkg/minikube/problem/problem.go b/pkg/minikube/problem/problem.go index ff126e7eacef..b21809e32f70 100644 --- a/pkg/minikube/problem/problem.go +++ b/pkg/minikube/problem/problem.go @@ -21,6 +21,7 @@ import ( "regexp" "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/translate" ) const issueBase = "https://github.com/kubernetes/minikube/issues" @@ -52,7 +53,7 @@ type match struct { // Display problem metadata to the console func (p *Problem) Display() { console.ErrStyle(console.FailureType, "Error: [%s] %v", p.ID, p.Err) - console.ErrStyle(console.Tip, "Advice: %s", p.Advice) + console.ErrStyle(console.Tip, "Advice: %s", translate.Translate(p.Advice)) if p.URL != "" { console.ErrStyle(console.Documentation, "Documentation: %s", p.URL) } diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go index ee0b96f3a567..52d8e07df1a7 100644 --- a/pkg/minikube/translate/translate.go +++ b/pkg/minikube/translate/translate.go @@ -48,7 +48,10 @@ func Translate(s string) string { } if translation, ok := Translations[s]; ok { - return translation.(string) + t := translation.(string) + if len(t) > 0 && t != " " { + return t + } } return s @@ -70,7 +73,7 @@ func DetermineLocale() { // Load translations for preferred language into memory. if preferredLanguage != defaultLanguage { - translationFile := "pkg/minikube/translate/translations" + preferredLanguage.String() + ".json" + translationFile := "pkg/minikube/translate/translations/" + preferredLanguage.String() + ".json" t, err := ioutil.ReadFile(translationFile) if err != nil { glog.Infof("Failed to load transalation file for %s: %s", preferredLanguage.String(), err) From aabce5867fbc815e92e9e565208859447337e9da Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Tue, 11 Jun 2019 13:54:01 -0700 Subject: [PATCH 09/25] Refactor extract to not use global variables --- hack/extract.go | 253 ------------------ .../translate/translations/fr-FR.json | 173 ++++++------ 2 files changed, 85 insertions(+), 341 deletions(-) delete mode 100644 hack/extract.go diff --git a/hack/extract.go b/hack/extract.go deleted file mode 100644 index b2b1fa115bd0..000000000000 --- a/hack/extract.go +++ /dev/null @@ -1,253 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "encoding/json" - "fmt" - "go/ast" - "go/parser" - "go/token" - "io/ioutil" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/golang-collections/collections/stack" -) - -var funcs map[string]struct{} -var funcStack *stack.Stack -var translations map[string]interface{} - -func main() { - translations = make(map[string]interface{}) - paths := []string{"../cmd", "../pkg"} - //paths := []string{"../cmd/minikube/cmd/delete.go"} - //paths := []string{"../pkg/minikube/cluster/cluster.go"} - funcs = map[string]struct{}{"Translate": {}} - funcStack = stack.New() - for f := range funcs { - funcStack.Push(f) - } - - fmt.Println("Compiling translation strings...") - for funcStack.Len() > 0 { - f := funcStack.Pop().(string) - //fmt.Printf("-----%s------\n", f) - for _, root := range paths { - err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if shouldCheckFile(path) { - return inspectFile(path, f) - } - return nil - }) - - if err != nil { - panic(err) - } - } - } - - err := writeStringsToFiles() - - if err != nil { - panic(err) - } - - fmt.Println("Done!") -} - -func writeStringsToFiles() error { - translationsFiles := "../pkg/minikube/translate/translations" - e := filepath.Walk(translationsFiles, func(path string, info os.FileInfo, err error) error { - if info.Mode().IsDir() { - return nil - } - fmt.Printf("Writing to %s\n", filepath.Base(path)) - var currentTranslations map[string]interface{} - f, err := ioutil.ReadFile(path) - if err != nil { - return err - } - err = json.Unmarshal(f, ¤tTranslations) - if err != nil { - return err - } - - //fmt.Println(currentTranslations) - - for k := range translations { - //fmt.Println(k) - if _, ok := currentTranslations[k]; !ok { - currentTranslations[k] = " " - } - } - - c, err := json.MarshalIndent(currentTranslations, "", "\t") - if err != nil { - return err - } - err = ioutil.WriteFile(path, c, info.Mode()) - return err - }) - - return e -} - -func addFuncToList(f string) { - if _, ok := funcs[f]; !ok { - funcs[f] = struct{}{} - funcStack.Push(f) - } -} - -func shouldCheckFile(path string) bool { - return strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") -} - -func inspectFile(filename string, f string) error { - fset := token.NewFileSet() - r, err := ioutil.ReadFile(filename) - if err != nil { - return err - } - //fmt.Printf(" Parsing %s\n", filename) - file, err := parser.ParseFile(fset, "", r, parser.ParseComments) - if err != nil { - return err - } - - ast.Inspect(file, func(x ast.Node) bool { - fd, ok := x.(*ast.FuncDecl) - if !ok { - /*gd, ok := x.(*ast.GenDecl) - if !ok { - return true - } - for _, spec := range gd.Specs { - if vs, ok := spec.(*ast.ValueSpec); ok { - for _, v := range vs.Values { - if ue, ok := v.(*ast.UnaryExpr); ok { - fmt.Printf("%s: %s\n", ue.X, reflect.TypeOf(ue.X)) - } - } - } - }*/ - return true - } - - for _, stmt := range fd.Body.List { - checkStmt(stmt, fd.Name.String(), f) - } - return true - }) - - return nil -} - -func checkStmt(stmt ast.Stmt, parentFunc string, f string) { - // If this line is an expression, see if it's a function call - if t, ok := stmt.(*ast.ExprStmt); ok { - checkCallExpression(t, parentFunc, f) - } - - // If this line is the beginning of an if statement, then check of the body of the block - if b, ok := stmt.(*ast.IfStmt); ok { - checkIfStmt(b, parentFunc, f) - } - - // Same for loops - if b, ok := stmt.(*ast.ForStmt); ok { - for _, s := range b.Body.List { - checkStmt(s, parentFunc, f) - } - } -} - -func checkIfStmt(stmt *ast.IfStmt, parentFunc string, f string) { - for _, s := range stmt.Body.List { - checkStmt(s, parentFunc, f) - } - if stmt.Else != nil { - // A straight else - if block, ok := stmt.Else.(*ast.BlockStmt); ok { - for _, s := range block.List { - checkStmt(s, parentFunc, f) - } - } - - // An else if - if elseif, ok := stmt.Else.(*ast.IfStmt); ok { - checkIfStmt(elseif, parentFunc, f) - } - - } -} - -func checkCallExpression(t *ast.ExprStmt, parentFunc string, f string) { - if s, ok := t.X.(*ast.CallExpr); ok { - sf, ok := s.Fun.(*ast.SelectorExpr) - if !ok { - addFuncToList(parentFunc) - return - } - if f == sf.Sel.Name && len(s.Args) > 0 { - addFuncToList(parentFunc) - for _, arg := range s.Args { - // Find references to strings - if i, ok := arg.(*ast.Ident); ok { - if i.Obj != nil { - if as, ok := i.Obj.Decl.(*ast.AssignStmt); ok { - if rhs, ok := as.Rhs[0].(*ast.BasicLit); ok { - if addStringToList(rhs.Value) { - break - } - } - } - } - } - // Find string arguments - if argString, ok := arg.(*ast.BasicLit); ok { - if addStringToList(argString.Value) { - break - } - } - } - } - } -} - -func addStringToList(s string) bool { - // Don't translate empty strings - if len(s) > 2 { - // Parse out quote marks - stringToTranslate := s[1 : len(s)-1] - // Don't translate integers - if _, err := strconv.Atoi(stringToTranslate); err != nil { - //Don't translate URLs - if u, err := url.Parse(stringToTranslate); err != nil || u.Scheme == "" || u.Host == "" { - translations[stringToTranslate] = "" - //fmt.Printf(" %s\n", stringToTranslate) - return true - } - } - } - return false -} diff --git a/pkg/minikube/translate/translations/fr-FR.json b/pkg/minikube/translate/translations/fr-FR.json index f39cdc88b163..bd9757c0d28c 100644 --- a/pkg/minikube/translate/translations/fr-FR.json +++ b/pkg/minikube/translate/translations/fr-FR.json @@ -1,90 +1,87 @@ { - "%s: %v": " ", - "Advice: %s": " ", - "Alternatively, you may delete the existing VM using `minikube delete -p %s`": " ", - "Configuring environment for Kubernetes %s on %s %s": " ", - "Configuring local host environment ...": " ", - "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": " ", - "Creating mount %s ...": " ", - "Deleting %q from %s ...": " ", - "Documentation: %s": " ", - "Done! kubectl is now configured to use %q": " ", - "Download complete!": " ", - "Downloading %s %s": " ", - "Downloading Minikube ISO ...": " ", - "Error getting machine status": " ", - "Error restarting cluster": " ", - "Error starting cluster": " ", - "Error starting mount": " ", - "Error writing mount pid": " ", - "Error: [%s] %v": " ", - "Failed to cache ISO": " ", - "Failed to cache binaries": " ", - "Failed to cache images": " ", - "Failed to check if machine exists": " ", - "Failed to check main repository and mirrors for images for images": " ", - "Failed to chown %s: %v": " ", - "Failed to enable container runtime": " ", - "Failed to generate config": " ", - "Failed to get bootstrapper": " ", - "Failed to get command runner": " ", - "Failed to get driver URL": " ", - "Failed to get machine client": " ", - "Failed to save config": " ", - "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.": " ", - "Failed to setup certs": " ", - "Failed to setup kubeconfig": " ", - "Failed to update cluster": " ", - "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/": " ", - "For more information, see:": " ", - "If the above advice does not help, please let us know: ": " ", - "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": " ", - "Kubernetes downgrade is not supported, will continue to use %v": " ", - "Launching Kubernetes ... ": " ", - "None of known repositories in your location is accessible. Use %s as fallback.": " ", - "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": " ", - "Please enter a value:": " ", - "Powering off %q via SSH ...": " ", - "Pulling images ...": " ", - "Re-using the currently running %s VM for %q ...": " ", - "Related issues:": " ", - "Relaunching Kubernetes %s using %s ... ": " ", - "Requested disk size (%dMB) is less than minimum of %dMB": " ", - "Restarting existing %s VM for %q ...": " ", - "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": " ", - "Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2": " ", - "Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2": " ", - "Stopping %q in %s ...": " ", - "The 'none' driver provides limited isolation and may reduce system security and reliability.": " ", - "There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\t\t\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n\t\t": " ", - "These changes will take effect upon a minikube delete and then a minikube start": " ", - "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true": " ", - "Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.": " ", - "To connect to this cluster, use: kubectl --context=%s": " ", - "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`": " ", - "To use kubectl or minikube commands as your own user, you may": " ", - "Unable to bind flags": " ", - "Unable to get VM IP address": " ", - "Unable to load cached images from config file.": " ", - "Unable to load cached images: %v": " ", - "Unable to load config: %v": " ", - "Unable to parse %q: %v": " ", - "Unable to pull images, which may be OK: %v": " ", - "Unable to start VM": " ", - "Verifying:": " ", - "Wait failed": " ", - "Waiting for SSH access ...": "Attendant acces SSH ...", - "checking main repository and mirrors for images": " ", - "error getting driver": " ", - "kubectl and minikube configuration will be stored in %s": " ", - "minikube %s on %s (%s)": " ", - "minikube is not running, so the service cannot be accessed": " ", - "minikube will upgrade the local cluster from Kubernetes %s to %s": " ", - "need to relocate them. For example, to overwrite your own settings:": " ", - "sudo chown -R $USER $HOME/.kube $HOME/.minikube": " ", - "sudo mv %s/.kube %s/.minikube $HOME": " ", - "unable to bind flags": " ", - "unable to set logtostderr": " ", - "unsupported driver: %s": " ", - "using image repository %s": " " + "Advice: %s": "", + "Alternatively, you may delete the existing VM using `minikube delete -p %s`": "", + "Configuring environment for Kubernetes %s on %s %s": "Configurant l'environment pour Kubernetes %s sur %s %s", + "Configuring local host environment ...": "", + "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "Créant un VM %s (CPUs=%d, Mémoire=%dMB, Disque=%dMB)", + "Creating mount %s ...": "", + "Deleting %q from %s ...": "", + "Documentation: %s": "", + "Done! kubectl is now configured to use %q": "Fini! kubectl est maintenant configuré pour utiliser %s.", + "Download complete!": "", + "Downloading %s %s": "", + "Downloading Minikube ISO ...": "", + "Error getting machine status": "", + "Error restarting cluster": "", + "Error starting cluster": "", + "Error starting mount": "", + "Error writing mount pid": "", + "Error: [%s] %v": "", + "Failed to cache ISO": "", + "Failed to cache binaries": "", + "Failed to cache images": "", + "Failed to check if machine exists": "", + "Failed to check main repository and mirrors for images for images": "", + "Failed to chown %s: %v": "", + "Failed to enable container runtime": "", + "Failed to generate config": "", + "Failed to get bootstrapper": "", + "Failed to get command runner": "", + "Failed to get driver URL": "", + "Failed to get machine client": "", + "Failed to save config": "", + "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.": "", + "Failed to setup certs": "", + "Failed to setup kubeconfig": "", + "Failed to update cluster": "", + "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", + "For more information, see:": "", + "If the above advice does not help, please let us know: ": "", + "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": "", + "Kubernetes downgrade is not supported, will continue to use %v": "", + "Launching Kubernetes ... ": "Lançant Kubernetes ...", + "None of known repositories in your location is accessible. Use %s as fallback.": "", + "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "", + "Please enter a value:": "", + "Powering off %q via SSH ...": "", + "Pulling images ...": "Extrayant les images ... ", + "Re-using the currently running %s VM for %q ...": "", + "Related issues:": "", + "Relaunching Kubernetes %s using %s ... ": "", + "Requested disk size (%dMB) is less than minimum of %dMB": "", + "Restarting existing %s VM for %q ...": "", + "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": "", + "Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2": "", + "Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2": "", + "Stopping %q in %s ...": "", + "The 'none' driver provides limited isolation and may reduce system security and reliability.": "", + "There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n": "", + "These changes will take effect upon a minikube delete and then a minikube start": "", + "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true": "", + "Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.": "", + "To connect to this cluster, use: kubectl --context=%s": "", + "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`": "", + "To use kubectl or minikube commands as your own user, you may": "", + "Unable to bind flags": "", + "Unable to get VM IP address": "", + "Unable to load cached images from config file.": "", + "Unable to load cached images: %v": "", + "Unable to load config: %v": "", + "Unable to parse %q: %v": "", + "Unable to pull images, which may be OK: %v": "", + "Unable to start VM": "", + "Verifying:": "Vérifiant:", + "Wait failed": "", + "Waiting for SSH access ...": "Attendant l'accès SSH ...", + "checking main repository and mirrors for images": "", + "error getting driver": "", + "kubectl and minikube configuration will be stored in %s": "", + "minikube %s on %s (%s)": "minikube %s sur %s (%s)", + "minikube is not running, so the service cannot be accessed": "", + "minikube will upgrade the local cluster from Kubernetes %s to %s": "", + "need to relocate them. For example, to overwrite your own settings:": "", + "unable to bind flags": "", + "unable to set logtostderr": "", + "unsupported driver: %s": "", + "using image repository %s": "" } \ No newline at end of file From aa5c2ecdfd01c33aa13ee04da4918a51404d4a74 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Tue, 11 Jun 2019 14:50:05 -0700 Subject: [PATCH 10/25] adding back extract --- hack/extract/extract.go | 298 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 hack/extract/extract.go diff --git a/hack/extract/extract.go b/hack/extract/extract.go new file mode 100644 index 000000000000..893c34686a14 --- /dev/null +++ b/hack/extract/extract.go @@ -0,0 +1,298 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "encoding/json" + "fmt" + "go/ast" + "go/parser" + "go/token" + "io/ioutil" + "net/url" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/golang-collections/collections/stack" + "github.com/pkg/errors" +) + +var Blacklist []string = []string{"%s: %v"} + +type Extractor struct { + funcs map[string]struct{} + fs *stack.Stack + translations map[string]interface{} + currentFunc string + parentFunc string + filename string +} + +func main() { + cwd, err := os.Getwd() + if err != nil { + panic(err) + } + if !strings.HasSuffix(cwd, "minikube") { + fmt.Println("Please run extractor from top level minikube directory.") + fmt.Println("Usage: go run hack/extract/extract.go") + os.Exit(1) + } + + paths := []string{"cmd", "pkg"} + //paths := []string{"../cmd/minikube/cmd/delete.go"} + //paths := []string{"../pkg/minikube/cluster/cluster.go"} + extractor := newExtractor("Translate") + + fmt.Println("Compiling translation strings...") + for extractor.fs.Len() > 0 { + f := extractor.fs.Pop().(string) + extractor.currentFunc = f + //fmt.Printf("-----%s------\n", f) + for _, root := range paths { + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if shouldCheckFile(path) { + extractor.filename = path + return inspectFile(extractor) + } + return nil + }) + + if err != nil { + panic(err) + } + } + } + + err = writeStringsToFiles(extractor) + + if err != nil { + panic(err) + } + + fmt.Println("Done!") +} + +func newExtractor(functionsToCheck ...string) *Extractor { + funcs := make(map[string]struct{}) + fs := stack.New() + + for _, f := range functionsToCheck { + funcs[f] = struct{}{} + fs.Push(f) + } + + return &Extractor{ + funcs: funcs, + fs: fs, + translations: make(map[string]interface{}), + } +} + +func writeStringsToFiles(e *Extractor) error { + translationsFiles := "pkg/minikube/translate/translations" + err := filepath.Walk(translationsFiles, func(path string, info os.FileInfo, err error) error { + if info.Mode().IsDir() { + return nil + } + fmt.Printf("Writing to %s\n", filepath.Base(path)) + var currentTranslations map[string]interface{} + f, err := ioutil.ReadFile(path) + if err != nil { + return errors.Wrap(err, "reading translation file") + } + err = json.Unmarshal(f, ¤tTranslations) + if err != nil { + return errors.Wrap(err, "unmarshalling current translations") + } + + //fmt.Println(currentTranslations) + + for k := range e.translations { + //fmt.Println(k) + if _, ok := currentTranslations[k]; !ok { + currentTranslations[k] = "" + } + } + + c, err := json.MarshalIndent(currentTranslations, "", "\t") + if err != nil { + return errors.Wrap(err, "marshalling translations") + } + err = ioutil.WriteFile(path, c, info.Mode()) + if err != nil { + return errors.Wrap(err, "writing translation file") + } + return nil + }) + + return err +} + +func addParentFuncToList(e *Extractor) { + if _, ok := e.funcs[e.parentFunc]; !ok { + e.funcs[e.parentFunc] = struct{}{} + e.fs.Push(e.parentFunc) + } +} + +func shouldCheckFile(path string) bool { + return strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") +} + +func inspectFile(e *Extractor) error { + fset := token.NewFileSet() + r, err := ioutil.ReadFile(e.filename) + if err != nil { + return err + } + //fmt.Printf(" Parsing %s\n", filename) + file, err := parser.ParseFile(fset, "", r, parser.ParseComments) + if err != nil { + return err + } + + ast.Inspect(file, func(x ast.Node) bool { + fd, ok := x.(*ast.FuncDecl) + if !ok { + /*gd, ok := x.(*ast.GenDecl) + if !ok { + return true + } + for _, spec := range gd.Specs { + if vs, ok := spec.(*ast.ValueSpec); ok { + for _, v := range vs.Values { + if ue, ok := v.(*ast.UnaryExpr); ok { + fmt.Printf("%s: %s\n", ue.X, reflect.TypeOf(ue.X)) + } + } + } + }*/ + return true + } + + e.parentFunc = fd.Name.String() + + for _, stmt := range fd.Body.List { + checkStmt(stmt, e) + } + return true + }) + + return nil +} + +func checkStmt(stmt ast.Stmt, e *Extractor) { + // If this line is an expression, see if it's a function call + if t, ok := stmt.(*ast.ExprStmt); ok { + checkCallExpression(t, e) + } + + // If this line is the beginning of an if statement, then check of the body of the block + if b, ok := stmt.(*ast.IfStmt); ok { + checkIfStmt(b, e) + } + + // Same for loops + if b, ok := stmt.(*ast.ForStmt); ok { + for _, s := range b.Body.List { + checkStmt(s, e) + } + } +} + +func checkIfStmt(stmt *ast.IfStmt, e *Extractor) { + for _, s := range stmt.Body.List { + checkStmt(s, e) + } + if stmt.Else != nil { + // A straight else + if block, ok := stmt.Else.(*ast.BlockStmt); ok { + for _, s := range block.List { + checkStmt(s, e) + } + } + + // An else if + if elseif, ok := stmt.Else.(*ast.IfStmt); ok { + checkIfStmt(elseif, e) + } + + } +} + +func checkCallExpression(t *ast.ExprStmt, e *Extractor) { + if s, ok := t.X.(*ast.CallExpr); ok { + sf, ok := s.Fun.(*ast.SelectorExpr) + if !ok { + addParentFuncToList(e) + return + } + if e.currentFunc == sf.Sel.Name && len(s.Args) > 0 { + addParentFuncToList(e) + for _, arg := range s.Args { + // Find references to strings + if i, ok := arg.(*ast.Ident); ok { + if i.Obj != nil { + if as, ok := i.Obj.Decl.(*ast.AssignStmt); ok { + if rhs, ok := as.Rhs[0].(*ast.BasicLit); ok { + if addStringToList(rhs.Value, e) { + break + } + } + } + } + } + // Find string arguments + if argString, ok := arg.(*ast.BasicLit); ok { + if addStringToList(argString.Value, e) { + break + } + } + } + } + } +} + +func addStringToList(s string, e *Extractor) bool { + // Don't translate empty strings + if len(s) > 2 { + // Parse out quote marks + stringToTranslate := s[1 : len(s)-1] + // Don't translate integers + if _, err := strconv.Atoi(stringToTranslate); err != nil { + //Don't translate URLs + if u, err := url.Parse(stringToTranslate); err != nil || u.Scheme == "" || u.Host == "" { + // Don't translate commands + if !strings.HasPrefix(stringToTranslate, "sudo ") { + // Don't translate blacklisted strings + for _, b := range Blacklist { + if b == stringToTranslate { + return false + } + } + e.translations[stringToTranslate] = "" + //fmt.Printf(" %s\n", stringToTranslate) + return true + } + } + } + } + return false +} From 3ce070c6ece5b74312de9b3364aa1afe1fbd78da Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Wed, 12 Jun 2019 18:11:34 -0700 Subject: [PATCH 11/25] extract is now a command --- {hack => pkg/minikube}/extract/extract.go | 221 ++++++++++-------- .../translate/translations/fr-FR.json | 3 + 2 files changed, 131 insertions(+), 93 deletions(-) rename {hack => pkg/minikube}/extract/extract.go (53%) diff --git a/hack/extract/extract.go b/pkg/minikube/extract/extract.go similarity index 53% rename from hack/extract/extract.go rename to pkg/minikube/extract/extract.go index 893c34686a14..5f7739e1388e 100644 --- a/hack/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package extract import ( "encoding/json" @@ -30,12 +30,15 @@ import ( "strings" "github.com/golang-collections/collections/stack" + "github.com/golang/glog" "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/exit" ) -var Blacklist []string = []string{"%s: %v"} +var blacklist []string = []string{"%s: %v"} -type Extractor struct { +type extractor struct { funcs map[string]struct{} fs *stack.Stack translations map[string]interface{} @@ -44,27 +47,14 @@ type Extractor struct { filename string } -func main() { - cwd, err := os.Getwd() - if err != nil { - panic(err) - } - if !strings.HasSuffix(cwd, "minikube") { - fmt.Println("Please run extractor from top level minikube directory.") - fmt.Println("Usage: go run hack/extract/extract.go") - os.Exit(1) - } - - paths := []string{"cmd", "pkg"} - //paths := []string{"../cmd/minikube/cmd/delete.go"} - //paths := []string{"../pkg/minikube/cluster/cluster.go"} - extractor := newExtractor("Translate") +func ExtractTranslatableStrings(paths []string, functions []string, output string) { + extractor := newExtractor(functions) - fmt.Println("Compiling translation strings...") + console.OutStyle(console.Waiting, "Compiling translation strings...") for extractor.fs.Len() > 0 { f := extractor.fs.Pop().(string) extractor.currentFunc = f - //fmt.Printf("-----%s------\n", f) + glog.Infof("Checking function: %s\n", f) for _, root := range paths { err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if shouldCheckFile(path) { @@ -75,21 +65,21 @@ func main() { }) if err != nil { - panic(err) + exit.WithError("Extracting strings", err) } } } - err = writeStringsToFiles(extractor) + err := writeStringsToFiles(extractor, output) if err != nil { - panic(err) + exit.WithError("Writing translation files", err) } - fmt.Println("Done!") + console.OutStyle(console.Ready, "Done!") } -func newExtractor(functionsToCheck ...string) *Extractor { +func newExtractor(functionsToCheck []string) *extractor { funcs := make(map[string]struct{}) fs := stack.New() @@ -98,20 +88,19 @@ func newExtractor(functionsToCheck ...string) *Extractor { fs.Push(f) } - return &Extractor{ + return &extractor{ funcs: funcs, fs: fs, translations: make(map[string]interface{}), } } -func writeStringsToFiles(e *Extractor) error { - translationsFiles := "pkg/minikube/translate/translations" - err := filepath.Walk(translationsFiles, func(path string, info os.FileInfo, err error) error { +func writeStringsToFiles(e *extractor, output string) error { + err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error { if info.Mode().IsDir() { return nil } - fmt.Printf("Writing to %s\n", filepath.Base(path)) + console.OutStyle(console.Check, "Writing to %s", filepath.Base(path)) var currentTranslations map[string]interface{} f, err := ioutil.ReadFile(path) if err != nil { @@ -122,8 +111,6 @@ func writeStringsToFiles(e *Extractor) error { return errors.Wrap(err, "unmarshalling current translations") } - //fmt.Println(currentTranslations) - for k := range e.translations { //fmt.Println(k) if _, ok := currentTranslations[k]; !ok { @@ -145,7 +132,7 @@ func writeStringsToFiles(e *Extractor) error { return err } -func addParentFuncToList(e *Extractor) { +func addParentFuncToList(e *extractor) { if _, ok := e.funcs[e.parentFunc]; !ok { e.funcs[e.parentFunc] = struct{}{} e.fs.Push(e.parentFunc) @@ -156,13 +143,14 @@ func shouldCheckFile(path string) bool { return strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") } -func inspectFile(e *Extractor) error { +func inspectFile(e *extractor) error { fset := token.NewFileSet() r, err := ioutil.ReadFile(e.filename) if err != nil { return err } - //fmt.Printf(" Parsing %s\n", filename) + glog.Infof("Parsing %s\n", e.filename) + fmt.Printf("Parsing %s\n", e.filename) file, err := parser.ParseFile(fset, "", r, parser.ParseComments) if err != nil { return err @@ -170,7 +158,12 @@ func inspectFile(e *Extractor) error { ast.Inspect(file, func(x ast.Node) bool { fd, ok := x.(*ast.FuncDecl) + + // Only check functions for now. if !ok { + // Deal with Solutions text here + + // Deal with Cobra stuff here /*gd, ok := x.(*ast.GenDecl) if !ok { return true @@ -189,6 +182,7 @@ func inspectFile(e *Extractor) error { e.parentFunc = fd.Name.String() + // Check line inside the function for _, stmt := range fd.Body.List { checkStmt(stmt, e) } @@ -198,26 +192,26 @@ func inspectFile(e *Extractor) error { return nil } -func checkStmt(stmt ast.Stmt, e *Extractor) { +func checkStmt(stmt ast.Stmt, e *extractor) { // If this line is an expression, see if it's a function call - if t, ok := stmt.(*ast.ExprStmt); ok { - checkCallExpression(t, e) + if expr, ok := stmt.(*ast.ExprStmt); ok { + checkCallExpression(expr, e) } // If this line is the beginning of an if statement, then check of the body of the block - if b, ok := stmt.(*ast.IfStmt); ok { - checkIfStmt(b, e) + if ifstmt, ok := stmt.(*ast.IfStmt); ok { + checkIfStmt(ifstmt, e) } // Same for loops - if b, ok := stmt.(*ast.ForStmt); ok { - for _, s := range b.Body.List { + if forloop, ok := stmt.(*ast.ForStmt); ok { + for _, s := range forloop.Body.List { checkStmt(s, e) } } } -func checkIfStmt(stmt *ast.IfStmt, e *Extractor) { +func checkIfStmt(stmt *ast.IfStmt, e *extractor) { for _, s := range stmt.Body.List { checkStmt(s, e) } @@ -237,62 +231,103 @@ func checkIfStmt(stmt *ast.IfStmt, e *Extractor) { } } -func checkCallExpression(t *ast.ExprStmt, e *Extractor) { - if s, ok := t.X.(*ast.CallExpr); ok { - sf, ok := s.Fun.(*ast.SelectorExpr) - if !ok { - addParentFuncToList(e) - return +func checkCallExpression(expr *ast.ExprStmt, e *extractor) { + s, ok := expr.X.(*ast.CallExpr) + + // This line isn't a function call + if !ok { + return + } + + sf, ok := s.Fun.(*ast.SelectorExpr) + if !ok { + addParentFuncToList(e) + return + } + + // Wrong function or called with no arguments. + if e.currentFunc != sf.Sel.Name || len(s.Args) == 0 { + return + } + + for _, arg := range s.Args { + // This argument is an identifier. + if i, ok := arg.(*ast.Ident); ok { + if checkIdentForStringValue(i, e) { + break + } } - if e.currentFunc == sf.Sel.Name && len(s.Args) > 0 { - addParentFuncToList(e) - for _, arg := range s.Args { - // Find references to strings - if i, ok := arg.(*ast.Ident); ok { - if i.Obj != nil { - if as, ok := i.Obj.Decl.(*ast.AssignStmt); ok { - if rhs, ok := as.Rhs[0].(*ast.BasicLit); ok { - if addStringToList(rhs.Value, e) { - break - } - } - } - } - } - // Find string arguments - if argString, ok := arg.(*ast.BasicLit); ok { - if addStringToList(argString.Value, e) { - break - } - } + + // This argument is a string. + if argString, ok := arg.(*ast.BasicLit); ok { + if addStringToList(argString.Value, e) { + break } } } + } -func addStringToList(s string, e *Extractor) bool { - // Don't translate empty strings - if len(s) > 2 { - // Parse out quote marks - stringToTranslate := s[1 : len(s)-1] - // Don't translate integers - if _, err := strconv.Atoi(stringToTranslate); err != nil { - //Don't translate URLs - if u, err := url.Parse(stringToTranslate); err != nil || u.Scheme == "" || u.Host == "" { - // Don't translate commands - if !strings.HasPrefix(stringToTranslate, "sudo ") { - // Don't translate blacklisted strings - for _, b := range Blacklist { - if b == stringToTranslate { - return false - } - } - e.translations[stringToTranslate] = "" - //fmt.Printf(" %s\n", stringToTranslate) - return true - } - } - } +func checkIdentForStringValue(i *ast.Ident, e *extractor) bool { + // This identifier is nil + if i.Obj == nil { + return false } + + as, ok := i.Obj.Decl.(*ast.AssignStmt) + + // This identifier wasn't assigned anything + if !ok { + return false + } + + rhs, ok := as.Rhs[0].(*ast.BasicLit) + + // This identifier was not assigned a string/basic value + if !ok { + return false + } + + if addStringToList(rhs.Value, e) { + return true + } + return false } + +func addStringToList(s string, e *extractor) bool { + // Empty strings don't need translating + if len(s) <= 2 { + return false + } + + // Parse out quote marks + stringToTranslate := s[1 : len(s)-1] + + // Don't translate integers + if _, err := strconv.Atoi(stringToTranslate); err == nil { + return false + } + + // Don't translate URLs + if u, err := url.Parse(stringToTranslate); err == nil && u.Scheme != "" && u.Host != "" { + return false + } + + // Don't translate commands + if strings.HasPrefix(stringToTranslate, "sudo ") { + return false + } + + // Don't translate blacklisted strings + for _, b := range blacklist { + if b == stringToTranslate { + return false + } + } + + // Hooray, we can translate the string! + e.translations[stringToTranslate] = "" + //fmt.Printf(" %s\n", stringToTranslate) + return true +} diff --git a/pkg/minikube/translate/translations/fr-FR.json b/pkg/minikube/translate/translations/fr-FR.json index bd9757c0d28c..e69b9ba30442 100644 --- a/pkg/minikube/translate/translations/fr-FR.json +++ b/pkg/minikube/translate/translations/fr-FR.json @@ -1,12 +1,14 @@ { "Advice: %s": "", "Alternatively, you may delete the existing VM using `minikube delete -p %s`": "", + "Compiling translation strings...": "", "Configuring environment for Kubernetes %s on %s %s": "Configurant l'environment pour Kubernetes %s sur %s %s", "Configuring local host environment ...": "", "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "Créant un VM %s (CPUs=%d, Mémoire=%dMB, Disque=%dMB)", "Creating mount %s ...": "", "Deleting %q from %s ...": "", "Documentation: %s": "", + "Done!": "", "Done! kubectl is now configured to use %q": "Fini! kubectl est maintenant configuré pour utiliser %s.", "Download complete!": "", "Downloading %s %s": "", @@ -73,6 +75,7 @@ "Verifying:": "Vérifiant:", "Wait failed": "", "Waiting for SSH access ...": "Attendant l'accès SSH ...", + "Writing translation files": "", "checking main repository and mirrors for images": "", "error getting driver": "", "kubectl and minikube configuration will be stored in %s": "", From b573cb8a2189fb1a7f4d58a7b06c4b011d84129b Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Thu, 13 Jun 2019 11:18:23 -0700 Subject: [PATCH 12/25] adding extract cmd file --- cmd/minikube/cmd/extract.go | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 cmd/minikube/cmd/extract.go diff --git a/cmd/minikube/cmd/extract.go b/cmd/minikube/cmd/extract.go new file mode 100644 index 000000000000..10ebd2458644 --- /dev/null +++ b/cmd/minikube/cmd/extract.go @@ -0,0 +1,60 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "github.com/spf13/cobra" + "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/extract" +) + +const ( + paths = "paths" + functions = "functions" + output = "output" +) + +var extractCmd = &cobra.Command{ + Use: "extract", + Short: "Extracts all translatable strings and adds them to all translations files.", + Long: "Extracts all translatable strings and adds them to all translations files.", + Run: func(cmd *cobra.Command, args []string) { + p, err := cmd.Flags().GetStringSlice(paths) + if err != nil { + exit.WithError("Invalid paths parameter", err) + } + + f, err := cmd.Flags().GetStringSlice(functions) + if err != nil { + exit.WithError("Invalid functions parameter", err) + } + + o, err := cmd.Flags().GetString(output) + if err != nil { + exit.WithError("Invalid output parameter", err) + } + + extract.ExtractTranslatableStrings(p, f, o) + }, +} + +func init() { + extractCmd.Flags().StringSlice(paths, []string{"cmd", "pkg"}, "The paths to check for translatable strings.") + extractCmd.Flags().StringSlice(functions, []string{"Translate"}, "The functions that translate strings.") + extractCmd.Flags().String(output, "pkg/minikube/translate/translations", "The path where translation files are.") + RootCmd.AddCommand(extractCmd) +} From dae9425aa06ee78272f62fb8e75544c384728850 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Fri, 14 Jun 2019 10:17:05 -0700 Subject: [PATCH 13/25] small changes --- cmd/minikube/cmd/extract.go | 2 +- pkg/minikube/extract/extract.go | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cmd/minikube/cmd/extract.go b/cmd/minikube/cmd/extract.go index 10ebd2458644..65fba96cfe90 100644 --- a/cmd/minikube/cmd/extract.go +++ b/cmd/minikube/cmd/extract.go @@ -48,7 +48,7 @@ var extractCmd = &cobra.Command{ exit.WithError("Invalid output parameter", err) } - extract.ExtractTranslatableStrings(p, f, o) + extract.TranslatableStrings(p, f, o) }, } diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index 5f7739e1388e..efb16ea292f9 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -26,6 +26,7 @@ import ( "net/url" "os" "path/filepath" + "reflect" "strconv" "strings" @@ -36,7 +37,7 @@ import ( "k8s.io/minikube/pkg/minikube/exit" ) -var blacklist []string = []string{"%s: %v"} +var blacklist = []string{"%s: %v"} type extractor struct { funcs map[string]struct{} @@ -47,7 +48,7 @@ type extractor struct { filename string } -func ExtractTranslatableStrings(paths []string, functions []string, output string) { +func TranslatableStrings(paths []string, functions []string, output string) { extractor := newExtractor(functions) console.OutStyle(console.Waiting, "Compiling translation strings...") @@ -150,7 +151,6 @@ func inspectFile(e *extractor) error { return err } glog.Infof("Parsing %s\n", e.filename) - fmt.Printf("Parsing %s\n", e.filename) file, err := parser.ParseFile(fset, "", r, parser.ParseComments) if err != nil { return err @@ -182,7 +182,7 @@ func inspectFile(e *extractor) error { e.parentFunc = fd.Name.String() - // Check line inside the function + // Check each line inside the function for _, stmt := range fd.Body.List { checkStmt(stmt, e) } @@ -193,6 +193,8 @@ func inspectFile(e *extractor) error { } func checkStmt(stmt ast.Stmt, e *extractor) { + //fmt.Printf("%s: %s\n", stmt, reflect.TypeOf(stmt)) + // If this line is an expression, see if it's a function call if expr, ok := stmt.(*ast.ExprStmt); ok { checkCallExpression(expr, e) @@ -239,6 +241,16 @@ func checkCallExpression(expr *ast.ExprStmt, e *extractor) { return } + for _, arg := range s.Args { + // This argument is a function literal, check its body. + if fl, ok := arg.(*ast.FuncLit); ok { + for _, stmt := range fl.Body.List { + fmt.Printf("%s: %s\n", stmt, reflect.TypeOf(stmt)) + checkStmt(stmt, e) + } + } + } + sf, ok := s.Fun.(*ast.SelectorExpr) if !ok { addParentFuncToList(e) From 5ef94b4c5ea134c488476c5a8a917676da2b96fa Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Fri, 14 Jun 2019 15:02:17 -0700 Subject: [PATCH 14/25] Adding comments for clarity --- pkg/minikube/extract/extract.go | 134 +++++++++++++++------------- pkg/minikube/translate/translate.go | 10 +-- 2 files changed, 76 insertions(+), 68 deletions(-) diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index efb16ea292f9..9807d5fd5bd7 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -18,7 +18,6 @@ package extract import ( "encoding/json" - "fmt" "go/ast" "go/parser" "go/token" @@ -26,7 +25,6 @@ import ( "net/url" "os" "path/filepath" - "reflect" "strconv" "strings" @@ -48,6 +46,22 @@ type extractor struct { filename string } +func newExtractor(functionsToCheck []string) *extractor { + funcs := make(map[string]struct{}) + fs := stack.New() + + for _, f := range functionsToCheck { + funcs[f] = struct{}{} + fs.Push(f) + } + + return &extractor{ + funcs: funcs, + fs: fs, + translations: make(map[string]interface{}), + } +} + func TranslatableStrings(paths []string, functions []string, output string) { extractor := newExtractor(functions) @@ -80,70 +94,11 @@ func TranslatableStrings(paths []string, functions []string, output string) { console.OutStyle(console.Ready, "Done!") } -func newExtractor(functionsToCheck []string) *extractor { - funcs := make(map[string]struct{}) - fs := stack.New() - - for _, f := range functionsToCheck { - funcs[f] = struct{}{} - fs.Push(f) - } - - return &extractor{ - funcs: funcs, - fs: fs, - translations: make(map[string]interface{}), - } -} - -func writeStringsToFiles(e *extractor, output string) error { - err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error { - if info.Mode().IsDir() { - return nil - } - console.OutStyle(console.Check, "Writing to %s", filepath.Base(path)) - var currentTranslations map[string]interface{} - f, err := ioutil.ReadFile(path) - if err != nil { - return errors.Wrap(err, "reading translation file") - } - err = json.Unmarshal(f, ¤tTranslations) - if err != nil { - return errors.Wrap(err, "unmarshalling current translations") - } - - for k := range e.translations { - //fmt.Println(k) - if _, ok := currentTranslations[k]; !ok { - currentTranslations[k] = "" - } - } - - c, err := json.MarshalIndent(currentTranslations, "", "\t") - if err != nil { - return errors.Wrap(err, "marshalling translations") - } - err = ioutil.WriteFile(path, c, info.Mode()) - if err != nil { - return errors.Wrap(err, "writing translation file") - } - return nil - }) - - return err -} - -func addParentFuncToList(e *extractor) { - if _, ok := e.funcs[e.parentFunc]; !ok { - e.funcs[e.parentFunc] = struct{}{} - e.fs.Push(e.parentFunc) - } -} - func shouldCheckFile(path string) bool { return strings.HasSuffix(path, ".go") && !strings.HasSuffix(path, "_test.go") } +// inspectFile goes through the given file line by line looking for translatable strings func inspectFile(e *extractor) error { fset := token.NewFileSet() r, err := ioutil.ReadFile(e.filename) @@ -192,6 +147,7 @@ func inspectFile(e *extractor) error { return nil } +// checkStmt checks each line to see if it's a call to print a string out to the console func checkStmt(stmt ast.Stmt, e *extractor) { //fmt.Printf("%s: %s\n", stmt, reflect.TypeOf(stmt)) @@ -213,6 +169,7 @@ func checkStmt(stmt ast.Stmt, e *extractor) { } } +// checkIfStmt does if-statement-specific checks, especially relating to else stmts func checkIfStmt(stmt *ast.IfStmt, e *extractor) { for _, s := range stmt.Body.List { checkStmt(s, e) @@ -233,6 +190,7 @@ func checkIfStmt(stmt *ast.IfStmt, e *extractor) { } } +// checkCallExpression takes a function call, and checks its arguments for strings func checkCallExpression(expr *ast.ExprStmt, e *extractor) { s, ok := expr.X.(*ast.CallExpr) @@ -245,7 +203,6 @@ func checkCallExpression(expr *ast.ExprStmt, e *extractor) { // This argument is a function literal, check its body. if fl, ok := arg.(*ast.FuncLit); ok { for _, stmt := range fl.Body.List { - fmt.Printf("%s: %s\n", stmt, reflect.TypeOf(stmt)) checkStmt(stmt, e) } } @@ -280,6 +237,7 @@ func checkCallExpression(expr *ast.ExprStmt, e *extractor) { } +// checkIdentForStringValye takes a identifier and sees if it's a variable assigned to a string func checkIdentForStringValue(i *ast.Ident, e *extractor) bool { // This identifier is nil if i.Obj == nil { @@ -307,6 +265,7 @@ func checkIdentForStringValue(i *ast.Ident, e *extractor) bool { return false } +// addStringToList takes a string, makes sure it's meant to be translated then adds it to the list if yes func addStringToList(s string, e *extractor) bool { // Empty strings don't need translating if len(s) <= 2 { @@ -343,3 +302,52 @@ func addStringToList(s string, e *extractor) bool { //fmt.Printf(" %s\n", stringToTranslate) return true } + +// writeStringsToFiles writes translations to all translation files in output +func writeStringsToFiles(e *extractor, output string) error { + err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error { + if err != nil { + return errors.Wrap(err, "accessing path") + } + if info.Mode().IsDir() { + return nil + } + console.OutStyle(console.Check, "Writing to %s", filepath.Base(path)) + var currentTranslations map[string]interface{} + f, err := ioutil.ReadFile(path) + if err != nil { + return errors.Wrap(err, "reading translation file") + } + err = json.Unmarshal(f, ¤tTranslations) + if err != nil { + return errors.Wrap(err, "unmarshalling current translations") + } + + // Make sure to not overwrite already translated strings + for k := range e.translations { + //fmt.Println(k) + if _, ok := currentTranslations[k]; !ok { + currentTranslations[k] = "" + } + } + + c, err := json.MarshalIndent(currentTranslations, "", "\t") + if err != nil { + return errors.Wrap(err, "marshalling translations") + } + err = ioutil.WriteFile(path, c, info.Mode()) + if err != nil { + return errors.Wrap(err, "writing translation file") + } + return nil + }) + + return err +} + +func addParentFuncToList(e *extractor) { + if _, ok := e.funcs[e.parentFunc]; !ok { + e.funcs[e.parentFunc] = struct{}{} + e.fs.Push(e.parentFunc) + } +} diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go index 52d8e07df1a7..82ae84c00aa3 100644 --- a/pkg/minikube/translate/translate.go +++ b/pkg/minikube/translate/translate.go @@ -68,7 +68,7 @@ func DetermineLocale() { err = SetPreferredLanguage(locale) if err != nil { glog.Warningf("Setting locale failed: %s", err) - locale = "" + preferredLanguage = defaultLanguage } // Load translations for preferred language into memory. @@ -88,8 +88,8 @@ func DetermineLocale() { } -// SetPreferredLanguageTag configures which language future messages should use. -func SetPreferredLanguageTag(l language.Tag) { +// setPreferredLanguageTag configures which language future messages should use. +func setPreferredLanguageTag(l language.Tag) { glog.Infof("Setting Language to %s ...", l) preferredLanguage = l } @@ -98,7 +98,7 @@ func SetPreferredLanguageTag(l language.Tag) { func SetPreferredLanguage(s string) error { // "C" is commonly used to denote a neutral POSIX locale. See http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html#tag_07_02 if s == "" || s == "C" { - SetPreferredLanguageTag(defaultLanguage) + setPreferredLanguageTag(defaultLanguage) return nil } // Handles "de_DE" or "de_DE.utf8" @@ -108,7 +108,7 @@ func SetPreferredLanguage(s string) error { if err != nil { return err } - SetPreferredLanguageTag(l) + setPreferredLanguageTag(l) return nil } From b4992265977ba47131b7c3171f6e1ee5d6e56019 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 17 Jun 2019 10:58:16 -0700 Subject: [PATCH 15/25] shorten name of translate function --- pkg/minikube/console/console_test.go | 10 +++++----- pkg/minikube/console/style.go | 2 +- pkg/minikube/extract/extract.go | 1 + pkg/minikube/problem/problem.go | 2 +- pkg/minikube/translate/translate.go | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pkg/minikube/console/console_test.go b/pkg/minikube/console/console_test.go index bc513e247d32..bcf5cd59fa7f 100644 --- a/pkg/minikube/console/console_test.go +++ b/pkg/minikube/console/console_test.go @@ -76,18 +76,18 @@ func TestOut(t *testing.T) { var testCases = []struct { format string - lang language.Tag + lang string arg interface{} want string }{ {format: "xyz123", want: "xyz123"}, - {format: "Installing Kubernetes version %s ...", lang: language.Arabic, arg: "v1.13", want: "... v1.13 تثبيت Kubernetes الإصدار"}, - {format: "Installing Kubernetes version %s ...", lang: language.AmericanEnglish, arg: "v1.13", want: "Installing Kubernetes version v1.13 ..."}, + {format: "Installing Kubernetes version %s ...", lang: "ar", arg: "v1.13", want: "... v1.13 تثبيت Kubernetes الإصدار"}, + {format: "Installing Kubernetes version %s ...", lang: "en-us", arg: "v1.13", want: "Installing Kubernetes version v1.13 ..."}, {format: "Parameter encoding: %s", arg: "%s%%%d", want: "Parameter encoding: %s%%%d"}, } for _, tc := range testCases { t.Run(tc.format, func(t *testing.T) { - translate.SetPreferredLanguageTag(tc.lang) + translate.SetPreferredLanguage(tc.lang) f := tests.NewFakeFile() SetOutFile(f) ErrLn("unrelated message") @@ -140,7 +140,7 @@ func TestSetPreferredLanguage(t *testing.T) { for _, tc := range tests { t.Run(tc.input, func(t *testing.T) { // Set something so that we can assert change. - translate.SetPreferredLanguageTag(language.Icelandic) + translate.SetPreferredLanguage("is") if err := translate.SetPreferredLanguage(tc.input); err != nil { t.Errorf("unexpected error: %q", err) } diff --git a/pkg/minikube/console/style.go b/pkg/minikube/console/style.go index eef452a4576b..245f18e6f89c 100644 --- a/pkg/minikube/console/style.go +++ b/pkg/minikube/console/style.go @@ -138,7 +138,7 @@ func applyStyle(style StyleEnum, useColor bool, format string, a ...interface{}) a[i] = number.Decimal(x, number.NoSeparator()) } } - format = translate.Translate(format) + format = translate.T(format) out := p.Sprintf(format, a...) s, ok := styles[style] diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index 9807d5fd5bd7..fc808a06bdcb 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -35,6 +35,7 @@ import ( "k8s.io/minikube/pkg/minikube/exit" ) +// A list of strings to explicitly omit from translation files. var blacklist = []string{"%s: %v"} type extractor struct { diff --git a/pkg/minikube/problem/problem.go b/pkg/minikube/problem/problem.go index b21809e32f70..a20e09b12162 100644 --- a/pkg/minikube/problem/problem.go +++ b/pkg/minikube/problem/problem.go @@ -53,7 +53,7 @@ type match struct { // Display problem metadata to the console func (p *Problem) Display() { console.ErrStyle(console.FailureType, "Error: [%s] %v", p.ID, p.Err) - console.ErrStyle(console.Tip, "Advice: %s", translate.Translate(p.Advice)) + console.ErrStyle(console.Tip, "Advice: %s", translate.T(p.Advice)) if p.URL != "" { console.ErrStyle(console.Documentation, "Documentation: %s", p.URL) } diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go index 82ae84c00aa3..465c67320bd3 100644 --- a/pkg/minikube/translate/translate.go +++ b/pkg/minikube/translate/translate.go @@ -37,8 +37,8 @@ var ( Translations map[string]interface{} ) -// Translate translates the given string to the supplied language. -func Translate(s string) string { +// T translates the given string to the supplied language. +func T(s string) string { if preferredLanguage == defaultLanguage { return s } From 6cd86b7ca748db976b84aef5e50f335801b2b310 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 17 Jun 2019 11:43:05 -0700 Subject: [PATCH 16/25] don't make extract an end-user command --- cmd/extract/extract.go | 28 +++++++++++++++ cmd/minikube/cmd/extract.go | 60 --------------------------------- pkg/minikube/extract/extract.go | 9 ++--- 3 files changed, 33 insertions(+), 64 deletions(-) create mode 100644 cmd/extract/extract.go delete mode 100644 cmd/minikube/cmd/extract.go diff --git a/cmd/extract/extract.go b/cmd/extract/extract.go new file mode 100644 index 000000000000..312705d592b2 --- /dev/null +++ b/cmd/extract/extract.go @@ -0,0 +1,28 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "k8s.io/minikube/pkg/minikube/extract" +) + +func main() { + paths := []string{"cmd", "pkg"} + functions := []string{"Translate"} + output := "pkg/minikube/translate/translations" + extract.TranslatableStrings(paths, functions, output) +} diff --git a/cmd/minikube/cmd/extract.go b/cmd/minikube/cmd/extract.go deleted file mode 100644 index 65fba96cfe90..000000000000 --- a/cmd/minikube/cmd/extract.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package cmd - -import ( - "github.com/spf13/cobra" - "k8s.io/minikube/pkg/minikube/exit" - "k8s.io/minikube/pkg/minikube/extract" -) - -const ( - paths = "paths" - functions = "functions" - output = "output" -) - -var extractCmd = &cobra.Command{ - Use: "extract", - Short: "Extracts all translatable strings and adds them to all translations files.", - Long: "Extracts all translatable strings and adds them to all translations files.", - Run: func(cmd *cobra.Command, args []string) { - p, err := cmd.Flags().GetStringSlice(paths) - if err != nil { - exit.WithError("Invalid paths parameter", err) - } - - f, err := cmd.Flags().GetStringSlice(functions) - if err != nil { - exit.WithError("Invalid functions parameter", err) - } - - o, err := cmd.Flags().GetString(output) - if err != nil { - exit.WithError("Invalid output parameter", err) - } - - extract.TranslatableStrings(p, f, o) - }, -} - -func init() { - extractCmd.Flags().StringSlice(paths, []string{"cmd", "pkg"}, "The paths to check for translatable strings.") - extractCmd.Flags().StringSlice(functions, []string{"Translate"}, "The functions that translate strings.") - extractCmd.Flags().String(output, "pkg/minikube/translate/translations", "The path where translation files are.") - RootCmd.AddCommand(extractCmd) -} diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index fc808a06bdcb..1b74b1fc228f 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -18,6 +18,7 @@ package extract import ( "encoding/json" + "fmt" "go/ast" "go/parser" "go/token" @@ -31,7 +32,6 @@ import ( "github.com/golang-collections/collections/stack" "github.com/golang/glog" "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/exit" ) @@ -66,7 +66,7 @@ func newExtractor(functionsToCheck []string) *extractor { func TranslatableStrings(paths []string, functions []string, output string) { extractor := newExtractor(functions) - console.OutStyle(console.Waiting, "Compiling translation strings...") + fmt.Println("Compiling translation strings...") for extractor.fs.Len() > 0 { f := extractor.fs.Pop().(string) extractor.currentFunc = f @@ -92,7 +92,7 @@ func TranslatableStrings(paths []string, functions []string, output string) { exit.WithError("Writing translation files", err) } - console.OutStyle(console.Ready, "Done!") + fmt.Println("Done!") } func shouldCheckFile(path string) bool { @@ -313,7 +313,7 @@ func writeStringsToFiles(e *extractor, output string) error { if info.Mode().IsDir() { return nil } - console.OutStyle(console.Check, "Writing to %s", filepath.Base(path)) + fmt.Printf("Writing to %s\n", filepath.Base(path)) var currentTranslations map[string]interface{} f, err := ioutil.ReadFile(path) if err != nil { @@ -346,6 +346,7 @@ func writeStringsToFiles(e *extractor, output string) error { return err } +// addParentFuncToList adds the current parent function to the list of functions to inspect more closely. func addParentFuncToList(e *extractor) { if _, ok := e.funcs[e.parentFunc]; !ok { e.funcs[e.parentFunc] = struct{}{} From 8da5f2b4a6467e78a9c74c132a729b6c9598be59 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Mon, 17 Jun 2019 13:28:10 -0700 Subject: [PATCH 17/25] General cleanup for clarity --- pkg/minikube/extract/extract.go | 62 ++++++++++++++++++----------- pkg/minikube/translate/translate.go | 34 ++++++++-------- 2 files changed, 55 insertions(+), 41 deletions(-) diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index 1b74b1fc228f..2629a73dfd9f 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -38,16 +38,29 @@ import ( // A list of strings to explicitly omit from translation files. var blacklist = []string{"%s: %v"} -type extractor struct { - funcs map[string]struct{} - fs *stack.Stack +// currentState is a struct that represent the current state of the extraction process +type currentState struct { + // The list of functions to check for + funcs map[string]struct{} + + // A stack representation of funcs for easy iteration + fs *stack.Stack + + // The list of translatable strings, in map form for easy json marhsalling translations map[string]interface{} - currentFunc string - parentFunc string - filename string + + // The function call we're currently checking for + currentFunc string + + // The function we're currently parsing + parentFunc string + + // The file we're currently checking + filename string } -func newExtractor(functionsToCheck []string) *extractor { +// newExtractor initializes state for extraction +func newExtractor(functionsToCheck []string) *currentState { funcs := make(map[string]struct{}) fs := stack.New() @@ -56,26 +69,27 @@ func newExtractor(functionsToCheck []string) *extractor { fs.Push(f) } - return &extractor{ + return ¤tState{ funcs: funcs, fs: fs, translations: make(map[string]interface{}), } } +// TranslatableStrings finds all strings to that need to be translated in paths and prints them out to all json files in output func TranslatableStrings(paths []string, functions []string, output string) { - extractor := newExtractor(functions) + e := newExtractor(functions) fmt.Println("Compiling translation strings...") - for extractor.fs.Len() > 0 { - f := extractor.fs.Pop().(string) - extractor.currentFunc = f + for e.fs.Len() > 0 { + f := e.fs.Pop().(string) + e.currentFunc = f glog.Infof("Checking function: %s\n", f) for _, root := range paths { err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if shouldCheckFile(path) { - extractor.filename = path - return inspectFile(extractor) + e.filename = path + return inspectFile(e) } return nil }) @@ -86,7 +100,7 @@ func TranslatableStrings(paths []string, functions []string, output string) { } } - err := writeStringsToFiles(extractor, output) + err := writeStringsToFiles(e, output) if err != nil { exit.WithError("Writing translation files", err) @@ -100,7 +114,7 @@ func shouldCheckFile(path string) bool { } // inspectFile goes through the given file line by line looking for translatable strings -func inspectFile(e *extractor) error { +func inspectFile(e *currentState) error { fset := token.NewFileSet() r, err := ioutil.ReadFile(e.filename) if err != nil { @@ -149,7 +163,7 @@ func inspectFile(e *extractor) error { } // checkStmt checks each line to see if it's a call to print a string out to the console -func checkStmt(stmt ast.Stmt, e *extractor) { +func checkStmt(stmt ast.Stmt, e *currentState) { //fmt.Printf("%s: %s\n", stmt, reflect.TypeOf(stmt)) // If this line is an expression, see if it's a function call @@ -171,7 +185,7 @@ func checkStmt(stmt ast.Stmt, e *extractor) { } // checkIfStmt does if-statement-specific checks, especially relating to else stmts -func checkIfStmt(stmt *ast.IfStmt, e *extractor) { +func checkIfStmt(stmt *ast.IfStmt, e *currentState) { for _, s := range stmt.Body.List { checkStmt(s, e) } @@ -192,7 +206,7 @@ func checkIfStmt(stmt *ast.IfStmt, e *extractor) { } // checkCallExpression takes a function call, and checks its arguments for strings -func checkCallExpression(expr *ast.ExprStmt, e *extractor) { +func checkCallExpression(expr *ast.ExprStmt, e *currentState) { s, ok := expr.X.(*ast.CallExpr) // This line isn't a function call @@ -239,7 +253,7 @@ func checkCallExpression(expr *ast.ExprStmt, e *extractor) { } // checkIdentForStringValye takes a identifier and sees if it's a variable assigned to a string -func checkIdentForStringValue(i *ast.Ident, e *extractor) bool { +func checkIdentForStringValue(i *ast.Ident, e *currentState) bool { // This identifier is nil if i.Obj == nil { return false @@ -266,8 +280,8 @@ func checkIdentForStringValue(i *ast.Ident, e *extractor) bool { return false } -// addStringToList takes a string, makes sure it's meant to be translated then adds it to the list if yes -func addStringToList(s string, e *extractor) bool { +// addStringToList takes a string, makes sure it's meant to be translated then adds it to the list if so +func addStringToList(s string, e *currentState) bool { // Empty strings don't need translating if len(s) <= 2 { return false @@ -305,7 +319,7 @@ func addStringToList(s string, e *extractor) bool { } // writeStringsToFiles writes translations to all translation files in output -func writeStringsToFiles(e *extractor, output string) error { +func writeStringsToFiles(e *currentState, output string) error { err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error { if err != nil { return errors.Wrap(err, "accessing path") @@ -347,7 +361,7 @@ func writeStringsToFiles(e *extractor, output string) error { } // addParentFuncToList adds the current parent function to the list of functions to inspect more closely. -func addParentFuncToList(e *extractor) { +func addParentFuncToList(e *currentState) { if _, ok := e.funcs[e.parentFunc]; !ok { e.funcs[e.parentFunc] = struct{}{} e.fs.Push(e.parentFunc) diff --git a/pkg/minikube/translate/translate.go b/pkg/minikube/translate/translate.go index 465c67320bd3..6dd262e40c00 100644 --- a/pkg/minikube/translate/translate.go +++ b/pkg/minikube/translate/translate.go @@ -47,18 +47,16 @@ func T(s string) string { return s } - if translation, ok := Translations[s]; ok { - t := translation.(string) - if len(t) > 0 && t != " " { - return t + if t, ok := Translations[s]; ok { + if len(t.(string)) > 0 && t.(string) != " " { + return t.(string) } } return s } -// DetermineLocale finds the system locale and sets the preferred language -// for output appropriately. +// DetermineLocale finds the system locale and sets the preferred language for output appropriately. func DetermineLocale() { locale, err := jibber_jabber.DetectIETF() if err != nil { @@ -71,19 +69,21 @@ func DetermineLocale() { preferredLanguage = defaultLanguage } + if preferredLanguage == defaultLanguage { + return + } + // Load translations for preferred language into memory. - if preferredLanguage != defaultLanguage { - translationFile := "pkg/minikube/translate/translations/" + preferredLanguage.String() + ".json" - t, err := ioutil.ReadFile(translationFile) - if err != nil { - glog.Infof("Failed to load transalation file for %s: %s", preferredLanguage.String(), err) - return - } + translationFile := "pkg/minikube/translate/translations/" + preferredLanguage.String() + ".json" + t, err := ioutil.ReadFile(translationFile) + if err != nil { + glog.Errorf("Failed to load transalation file for %s: %s", preferredLanguage.String(), err) + return + } - err = json.Unmarshal(t, &Translations) - if err != nil { - glog.Infof("Failed to populate translation map: %s", err) - } + err = json.Unmarshal(t, &Translations) + if err != nil { + glog.Errorf("Failed to populate translation map: %s", err) } } From 8308aa51560dd6092668b80900e2183aeee57e2f Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Tue, 18 Jun 2019 11:19:05 -0700 Subject: [PATCH 18/25] adding test --- pkg/minikube/extract/extract.go | 39 ++++++++++------ pkg/minikube/extract/extract_test.go | 42 +++++++++++++++++ pkg/minikube/extract/testdata/en-US.json | 4 ++ pkg/minikube/extract/testdata/sample_file.go | 48 ++++++++++++++++++++ 4 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 pkg/minikube/extract/extract_test.go create mode 100644 pkg/minikube/extract/testdata/en-US.json create mode 100644 pkg/minikube/extract/testdata/sample_file.go diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index 2629a73dfd9f..f88cd031f6f7 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -38,8 +38,8 @@ import ( // A list of strings to explicitly omit from translation files. var blacklist = []string{"%s: %v"} -// currentState is a struct that represent the current state of the extraction process -type currentState struct { +// state is a struct that represent the current state of the extraction process +type state struct { // The list of functions to check for funcs map[string]struct{} @@ -60,7 +60,7 @@ type currentState struct { } // newExtractor initializes state for extraction -func newExtractor(functionsToCheck []string) *currentState { +func newExtractor(functionsToCheck []string) *state { funcs := make(map[string]struct{}) fs := stack.New() @@ -69,7 +69,7 @@ func newExtractor(functionsToCheck []string) *currentState { fs.Push(f) } - return ¤tState{ + return &state{ funcs: funcs, fs: fs, translations: make(map[string]interface{}), @@ -78,6 +78,16 @@ func newExtractor(functionsToCheck []string) *currentState { // TranslatableStrings finds all strings to that need to be translated in paths and prints them out to all json files in output func TranslatableStrings(paths []string, functions []string, output string) { + cwd, err := os.Getwd() + if err != nil { + exit.WithError("Getting current working directory", err) + } + + if strings.Contains(cwd, "cmd") { + fmt.Println("Run extract.go from the minikube root directory.") + os.Exit(1) + } + e := newExtractor(functions) fmt.Println("Compiling translation strings...") @@ -100,7 +110,7 @@ func TranslatableStrings(paths []string, functions []string, output string) { } } - err := writeStringsToFiles(e, output) + err = writeStringsToFiles(e, output) if err != nil { exit.WithError("Writing translation files", err) @@ -114,7 +124,7 @@ func shouldCheckFile(path string) bool { } // inspectFile goes through the given file line by line looking for translatable strings -func inspectFile(e *currentState) error { +func inspectFile(e *state) error { fset := token.NewFileSet() r, err := ioutil.ReadFile(e.filename) if err != nil { @@ -163,7 +173,7 @@ func inspectFile(e *currentState) error { } // checkStmt checks each line to see if it's a call to print a string out to the console -func checkStmt(stmt ast.Stmt, e *currentState) { +func checkStmt(stmt ast.Stmt, e *state) { //fmt.Printf("%s: %s\n", stmt, reflect.TypeOf(stmt)) // If this line is an expression, see if it's a function call @@ -185,7 +195,7 @@ func checkStmt(stmt ast.Stmt, e *currentState) { } // checkIfStmt does if-statement-specific checks, especially relating to else stmts -func checkIfStmt(stmt *ast.IfStmt, e *currentState) { +func checkIfStmt(stmt *ast.IfStmt, e *state) { for _, s := range stmt.Body.List { checkStmt(s, e) } @@ -206,7 +216,7 @@ func checkIfStmt(stmt *ast.IfStmt, e *currentState) { } // checkCallExpression takes a function call, and checks its arguments for strings -func checkCallExpression(expr *ast.ExprStmt, e *currentState) { +func checkCallExpression(expr *ast.ExprStmt, e *state) { s, ok := expr.X.(*ast.CallExpr) // This line isn't a function call @@ -253,7 +263,7 @@ func checkCallExpression(expr *ast.ExprStmt, e *currentState) { } // checkIdentForStringValye takes a identifier and sees if it's a variable assigned to a string -func checkIdentForStringValue(i *ast.Ident, e *currentState) bool { +func checkIdentForStringValue(i *ast.Ident, e *state) bool { // This identifier is nil if i.Obj == nil { return false @@ -281,7 +291,7 @@ func checkIdentForStringValue(i *ast.Ident, e *currentState) bool { } // addStringToList takes a string, makes sure it's meant to be translated then adds it to the list if so -func addStringToList(s string, e *currentState) bool { +func addStringToList(s string, e *state) bool { // Empty strings don't need translating if len(s) <= 2 { return false @@ -319,7 +329,7 @@ func addStringToList(s string, e *currentState) bool { } // writeStringsToFiles writes translations to all translation files in output -func writeStringsToFiles(e *currentState, output string) error { +func writeStringsToFiles(e *state, output string) error { err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error { if err != nil { return errors.Wrap(err, "accessing path") @@ -327,6 +337,9 @@ func writeStringsToFiles(e *currentState, output string) error { if info.Mode().IsDir() { return nil } + if !strings.HasSuffix(path, ".json") { + return nil + } fmt.Printf("Writing to %s\n", filepath.Base(path)) var currentTranslations map[string]interface{} f, err := ioutil.ReadFile(path) @@ -361,7 +374,7 @@ func writeStringsToFiles(e *currentState, output string) error { } // addParentFuncToList adds the current parent function to the list of functions to inspect more closely. -func addParentFuncToList(e *currentState) { +func addParentFuncToList(e *state) { if _, ok := e.funcs[e.parentFunc]; !ok { e.funcs[e.parentFunc] = struct{}{} e.fs.Push(e.parentFunc) diff --git a/pkg/minikube/extract/extract_test.go b/pkg/minikube/extract/extract_test.go new file mode 100644 index 000000000000..e7ad52c489c1 --- /dev/null +++ b/pkg/minikube/extract/extract_test.go @@ -0,0 +1,42 @@ +package extract + +import ( + "encoding/json" + "io/ioutil" + "reflect" + "testing" +) + +func TestExtract(t *testing.T) { + // The file to scan + paths := []string{"testdata/sample_file.go"} + + // The function we care about + functions := []string{"PrintToScreen"} + + // The directory where the sample translation file is in + output := "testdata/" + + expected := map[string]interface{}{ + "Hint: This is not a URL, come on.": "", + "Holy cow I'm in a loop!": "Something else", + "This is a variable with a string assigned": "", + "This was a choice: %s": "Something", + "Wow another string: %s": "", + } + + TranslatableStrings(paths, functions, output) + + var got map[string]interface{} + f, err := ioutil.ReadFile("testdata/en-US.json") + if err != nil { + t.Fatalf("Reading json file: %s", err) + } + + json.Unmarshal(f, &got) + + if !reflect.DeepEqual(expected, got) { + t.Fatalf("Translation JSON not equal: expected %v, got %v", expected, got) + } + +} diff --git a/pkg/minikube/extract/testdata/en-US.json b/pkg/minikube/extract/testdata/en-US.json new file mode 100644 index 000000000000..c7a3cf31edd1 --- /dev/null +++ b/pkg/minikube/extract/testdata/en-US.json @@ -0,0 +1,4 @@ +{ + "Holy cow I'm in a loop!": "Something else", + "This was a choice: %s": "Something" +} \ No newline at end of file diff --git a/pkg/minikube/extract/testdata/sample_file.go b/pkg/minikube/extract/testdata/sample_file.go new file mode 100644 index 000000000000..1bbf98f3ea1d --- /dev/null +++ b/pkg/minikube/extract/testdata/sample_file.go @@ -0,0 +1,48 @@ +package extract + +import "fmt" + +func DoSomeStuff() { + // Test with a URL + PrintToScreenNoInterface("http://kubernetes.io") + + // Test with something that Go thinks looks like a URL + PrintToScreenNoInterface("Hint: This is not a URL, come on.") + + // Try with an integer + PrintToScreenNoInterface("5") + + // Try with a sudo command + path := "." + PrintToScreen("sudo ls %s", path) + + DoSomeOtherStuff(true, 4, "I think this should work") + + v := "This is a variable with a string assigned" + PrintToScreenNoInterface(v) +} + +func DoSomeOtherStuff(choice bool, i int, s string) { + + // Let's try an if statement + if choice { + PrintToScreen("This was a choice: %s", s) + } else if i > 5 { + PrintToScreen("Wow another string: %s", i) + } else { + for i > 10 { + PrintToScreenNoInterface("Holy cow I'm in a loop!") + i = i + 1 + } + } + +} + +func PrintToScreenNoInterface(s string) { + PrintToScreen(s, nil) +} + +// This will be the function we'll focus the extractor on +func PrintToScreen(s string, i interface{}) { + fmt.Printf(s, i) +} From 97e2cd11538cc3aedf5550a48553297620521331 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Wed, 19 Jun 2019 17:44:34 -0700 Subject: [PATCH 19/25] Simplifying and correcting the extract code. Test passes now. --- cmd/extract/extract.go | 8 +- pkg/minikube/extract/extract.go | 183 +++++++++--------- pkg/minikube/extract/extract_test.go | 2 +- pkg/minikube/extract/testdata/sample_file.go | 4 +- .../testdata/{en-US.json => test.json} | 0 .../translate/translations/fr-FR.json | 154 ++++++++++++++- 6 files changed, 249 insertions(+), 102 deletions(-) rename pkg/minikube/extract/testdata/{en-US.json => test.json} (100%) diff --git a/cmd/extract/extract.go b/cmd/extract/extract.go index 312705d592b2..845651557acf 100644 --- a/cmd/extract/extract.go +++ b/cmd/extract/extract.go @@ -22,7 +22,11 @@ import ( func main() { paths := []string{"cmd", "pkg"} - functions := []string{"Translate"} + functions := []string{"translate.T"} output := "pkg/minikube/translate/translations" - extract.TranslatableStrings(paths, functions, output) + err := extract.TranslatableStrings(paths, functions, output) + + if err != nil { + panic(err) + } } diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index f88cd031f6f7..7c534b602138 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -30,18 +30,16 @@ import ( "strings" "github.com/golang-collections/collections/stack" - "github.com/golang/glog" "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/exit" ) -// A list of strings to explicitly omit from translation files. +// blacklist is a list of strings to explicitly omit from translation files. var blacklist = []string{"%s: %v"} // state is a struct that represent the current state of the extraction process type state struct { // The list of functions to check for - funcs map[string]struct{} + funcs map[funcType]struct{} // A stack representation of funcs for easy iteration fs *stack.Stack @@ -50,21 +48,37 @@ type state struct { translations map[string]interface{} // The function call we're currently checking for - currentFunc string + currentFunc funcType // The function we're currently parsing - parentFunc string + parentFunc funcType // The file we're currently checking filename string + + // THe package we're currenly in + currentPackage string +} + +type funcType struct { + pack string // The package the function is in + name string // The name of the function } // newExtractor initializes state for extraction -func newExtractor(functionsToCheck []string) *state { - funcs := make(map[string]struct{}) +func newExtractor(functionsToCheck []string) (*state, error) { + funcs := make(map[funcType]struct{}) fs := stack.New() - for _, f := range functionsToCheck { + for _, t := range functionsToCheck { + t2 := strings.Split(t, ".") + if len(t2) < 2 { + return nil, errors.Wrap(nil, fmt.Sprintf("Invalid function string %s. Needs package name as well.", t)) + } + f := funcType{ + pack: t2[0], + name: t2[1], + } funcs[f] = struct{}{} fs.Push(f) } @@ -73,14 +87,22 @@ func newExtractor(functionsToCheck []string) *state { funcs: funcs, fs: fs, translations: make(map[string]interface{}), + }, nil +} + +// SetParentFunc Sets the current parent function, along with package information +func setParentFunc(e *state, f string) { + e.parentFunc = funcType{ + pack: e.currentPackage, + name: f, } } // TranslatableStrings finds all strings to that need to be translated in paths and prints them out to all json files in output -func TranslatableStrings(paths []string, functions []string, output string) { +func TranslatableStrings(paths []string, functions []string, output string) error { cwd, err := os.Getwd() if err != nil { - exit.WithError("Getting current working directory", err) + return errors.Wrap(err, "Getting current working directory") } if strings.Contains(cwd, "cmd") { @@ -88,13 +110,16 @@ func TranslatableStrings(paths []string, functions []string, output string) { os.Exit(1) } - e := newExtractor(functions) + e, err := newExtractor(functions) + + if err != nil { + return errors.Wrap(err, "Initializing") + } fmt.Println("Compiling translation strings...") for e.fs.Len() > 0 { - f := e.fs.Pop().(string) + f := e.fs.Pop().(funcType) e.currentFunc = f - glog.Infof("Checking function: %s\n", f) for _, root := range paths { err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if shouldCheckFile(path) { @@ -105,7 +130,7 @@ func TranslatableStrings(paths []string, functions []string, output string) { }) if err != nil { - exit.WithError("Extracting strings", err) + return errors.Wrap(err, "Extracting strings") } } } @@ -113,10 +138,11 @@ func TranslatableStrings(paths []string, functions []string, output string) { err = writeStringsToFiles(e, output) if err != nil { - exit.WithError("Writing translation files", err) + return errors.Wrap(err, "Writing translation files") } fmt.Println("Done!") + return nil } func shouldCheckFile(path string) bool { @@ -130,124 +156,86 @@ func inspectFile(e *state) error { if err != nil { return err } - glog.Infof("Parsing %s\n", e.filename) file, err := parser.ParseFile(fset, "", r, parser.ParseComments) if err != nil { return err } ast.Inspect(file, func(x ast.Node) bool { - fd, ok := x.(*ast.FuncDecl) - - // Only check functions for now. - if !ok { - // Deal with Solutions text here - - // Deal with Cobra stuff here - /*gd, ok := x.(*ast.GenDecl) - if !ok { - return true - } - for _, spec := range gd.Specs { - if vs, ok := spec.(*ast.ValueSpec); ok { - for _, v := range vs.Values { - if ue, ok := v.(*ast.UnaryExpr); ok { - fmt.Printf("%s: %s\n", ue.X, reflect.TypeOf(ue.X)) - } - } - } - }*/ + if fi, ok := x.(*ast.File); ok { + e.currentPackage = fi.Name.String() return true } - e.parentFunc = fd.Name.String() - - // Check each line inside the function - for _, stmt := range fd.Body.List { - checkStmt(stmt, e) + if fd, ok := x.(*ast.FuncDecl); ok { + setParentFunc(e, fd.Name.String()) + return true } + + checkNode(x, e) return true }) return nil } -// checkStmt checks each line to see if it's a call to print a string out to the console -func checkStmt(stmt ast.Stmt, e *state) { - //fmt.Printf("%s: %s\n", stmt, reflect.TypeOf(stmt)) - - // If this line is an expression, see if it's a function call - if expr, ok := stmt.(*ast.ExprStmt); ok { +// checkNode checks each node to see if it's a function call +func checkNode(stmt ast.Node, e *state) { + // This line is a function call, that's what we care about + if expr, ok := stmt.(*ast.CallExpr); ok { checkCallExpression(expr, e) } - - // If this line is the beginning of an if statement, then check of the body of the block - if ifstmt, ok := stmt.(*ast.IfStmt); ok { - checkIfStmt(ifstmt, e) - } - - // Same for loops - if forloop, ok := stmt.(*ast.ForStmt); ok { - for _, s := range forloop.Body.List { - checkStmt(s, e) - } - } -} - -// checkIfStmt does if-statement-specific checks, especially relating to else stmts -func checkIfStmt(stmt *ast.IfStmt, e *state) { - for _, s := range stmt.Body.List { - checkStmt(s, e) - } - if stmt.Else != nil { - // A straight else - if block, ok := stmt.Else.(*ast.BlockStmt); ok { - for _, s := range block.List { - checkStmt(s, e) - } - } - - // An else if - if elseif, ok := stmt.Else.(*ast.IfStmt); ok { - checkIfStmt(elseif, e) - } - - } } // checkCallExpression takes a function call, and checks its arguments for strings -func checkCallExpression(expr *ast.ExprStmt, e *state) { - s, ok := expr.X.(*ast.CallExpr) - - // This line isn't a function call - if !ok { - return - } - +func checkCallExpression(s *ast.CallExpr, e *state) { for _, arg := range s.Args { // This argument is a function literal, check its body. if fl, ok := arg.(*ast.FuncLit); ok { for _, stmt := range fl.Body.List { - checkStmt(stmt, e) + checkNode(stmt, e) } } } + var functionName string + var packageName string + + // SelectorExpr is a function call to a separate package sf, ok := s.Fun.(*ast.SelectorExpr) - if !ok { - addParentFuncToList(e) + if ok { + // Parse out the package of the call + sfi, ok := sf.X.(*ast.Ident) + if !ok { + return + } + packageName = sfi.Name + functionName = sf.Sel.Name + } + + // Ident is an identifier, in this case it's a function call in the same package + id, ok := s.Fun.(*ast.Ident) + if ok { + functionName = id.Name + packageName = e.currentPackage + } + + // This is not a function call. + if len(functionName) == 0 { return } - // Wrong function or called with no arguments. - if e.currentFunc != sf.Sel.Name || len(s.Args) == 0 { + // This is not the correct function call, or it was called with no arguments. + if e.currentFunc.name != functionName || e.currentFunc.pack != packageName || len(s.Args) == 0 { return } + matched := false for _, arg := range s.Args { // This argument is an identifier. if i, ok := arg.(*ast.Ident); ok { if checkIdentForStringValue(i, e) { + matched = true break } } @@ -255,11 +243,16 @@ func checkCallExpression(expr *ast.ExprStmt, e *state) { // This argument is a string. if argString, ok := arg.(*ast.BasicLit); ok { if addStringToList(argString.Value, e) { + matched = true break } } } + if !matched { + addParentFuncToList(e) + } + } // checkIdentForStringValye takes a identifier and sees if it's a variable assigned to a string @@ -324,7 +317,6 @@ func addStringToList(s string, e *state) bool { // Hooray, we can translate the string! e.translations[stringToTranslate] = "" - //fmt.Printf(" %s\n", stringToTranslate) return true } @@ -353,7 +345,6 @@ func writeStringsToFiles(e *state, output string) error { // Make sure to not overwrite already translated strings for k := range e.translations { - //fmt.Println(k) if _, ok := currentTranslations[k]; !ok { currentTranslations[k] = "" } diff --git a/pkg/minikube/extract/extract_test.go b/pkg/minikube/extract/extract_test.go index e7ad52c489c1..a35528876cc5 100644 --- a/pkg/minikube/extract/extract_test.go +++ b/pkg/minikube/extract/extract_test.go @@ -28,7 +28,7 @@ func TestExtract(t *testing.T) { TranslatableStrings(paths, functions, output) var got map[string]interface{} - f, err := ioutil.ReadFile("testdata/en-US.json") + f, err := ioutil.ReadFile("testdata/test.json") if err != nil { t.Fatalf("Reading json file: %s", err) } diff --git a/pkg/minikube/extract/testdata/sample_file.go b/pkg/minikube/extract/testdata/sample_file.go index 1bbf98f3ea1d..a6316ea5cae4 100644 --- a/pkg/minikube/extract/testdata/sample_file.go +++ b/pkg/minikube/extract/testdata/sample_file.go @@ -13,8 +13,7 @@ func DoSomeStuff() { PrintToScreenNoInterface("5") // Try with a sudo command - path := "." - PrintToScreen("sudo ls %s", path) + PrintToScreenNoInterface("sudo ls .") DoSomeOtherStuff(true, 4, "I think this should work") @@ -30,6 +29,7 @@ func DoSomeOtherStuff(choice bool, i int, s string) { } else if i > 5 { PrintToScreen("Wow another string: %s", i) } else { + // Also try a loop for i > 10 { PrintToScreenNoInterface("Holy cow I'm in a loop!") i = i + 1 diff --git a/pkg/minikube/extract/testdata/en-US.json b/pkg/minikube/extract/testdata/test.json similarity index 100% rename from pkg/minikube/extract/testdata/en-US.json rename to pkg/minikube/extract/testdata/test.json diff --git a/pkg/minikube/translate/translations/fr-FR.json b/pkg/minikube/translate/translations/fr-FR.json index e69b9ba30442..9e2636062c26 100644 --- a/pkg/minikube/translate/translations/fr-FR.json +++ b/pkg/minikube/translate/translations/fr-FR.json @@ -1,6 +1,28 @@ { + "%q VM does not exist, nothing to stop": "", + "%q cluster does not exist": "", + "%q host does not exist, unable to show an IP": "", + "%q profile does not exist": "", + "%q stopped.": "", + "%s IP has been updated to point at %s": "", + "%s IP was already correctly configured for %s": "", + "%s has no available configuration options": "", + "%s is not responding properly: %v": "", + "%s is not yet a supported filesystem. We will try anyways!": "", + "%s was successfully configured": "", + "%s was successfully disabled": "", + "%s was successfully enabled": "", + "%s.%s=%s": "", + "%s/%d": "", + "%s:%s is not running: %v": "", + "%s=%s": "", + "'none' driver does not support 'minikube docker-env' command": "", + "'none' driver does not support 'minikube mount' command": "", + "'none' driver does not support 'minikube ssh' command": "", "Advice: %s": "", "Alternatively, you may delete the existing VM using `minikube delete -p %s`": "", + "Cannot find directory %s for mount": "", + "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.": "", "Compiling translation strings...": "", "Configuring environment for Kubernetes %s on %s %s": "Configurant l'environment pour Kubernetes %s sur %s %s", "Configuring local host environment ...": "", @@ -13,78 +35,208 @@ "Download complete!": "", "Downloading %s %s": "", "Downloading Minikube ISO ...": "", + "ERROR creating `registry-creds-dpr` secret": "", + "ERROR creating `registry-creds-ecr` secret: %v": "", + "ERROR creating `registry-creds-gcr` secret: %v": "", + "Enabling dashboard ...": "", + "Error creating list template": "", + "Error creating minikube directory": "", + "Error creating status template": "", + "Error creating view template": "", + "Error executing list template": "", + "Error executing status template": "", + "Error executing template": "", + "Error executing view template": "", + "Error finding port for mount": "", + "Error getting IP": "", + "Error getting bootstrapper": "", + "Error getting client": "", + "Error getting client: %v": "", + "Error getting cluster": "", + "Error getting cluster bootstrapper": "", + "Error getting config": "", + "Error getting host": "", + "Error getting host status": "", + "Error getting machine logs": "", "Error getting machine status": "", + "Error getting service status": "", + "Error getting service with namespace: %s and labels %s:%s: %v": "", + "Error getting the host IP address to use from within the VM": "", + "Error host driver ip status": "", + "Error killing mount process": "", + "Error loading api": "", + "Error opening service": "", + "Error reading %s: %v": "", "Error restarting cluster": "", + "Error setting shell variables": "", "Error starting cluster": "", "Error starting mount": "", + "Error unsetting shell variables": "", "Error writing mount pid": "", "Error: [%s] %v": "", + "Exiting due to %s signal": "", "Failed to cache ISO": "", + "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images": "", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", "Failed to chown %s: %v": "", + "Failed to delete cluster": "", + "Failed to delete images": "", + "Failed to delete images from config": "", + "Failed to download kubectl": "", "Failed to enable container runtime": "", "Failed to generate config": "", "Failed to get bootstrapper": "", "Failed to get command runner": "", "Failed to get driver URL": "", + "Failed to get image map": "", "Failed to get machine client": "", + "Failed to get service URL: %v": "", + "Failed to kill mount process: %v": "", + "Failed to list cached images": "", + "Failed to remove profile": "", "Failed to save config": "", "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.": "", "Failed to setup certs": "", "Failed to setup kubeconfig": "", "Failed to update cluster": "", + "Failed to update config": "", + "Failed unmount: %v": "", + "Follow": "", "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", "For more information, see:": "", + "Found network options:": "", + "GID: %s": "", "If the above advice does not help, please let us know: ": "", "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": "", + "IsEnabled failed": "", "Kubernetes downgrade is not supported, will continue to use %v": "", "Launching Kubernetes ... ": "Lançant Kubernetes ...", + "Launching proxy ...": "", + "MSize: %d": "", + "Mode: %o (%s)": "", + "Mount options:": "", + "Mounting host path %s into VM as %s ...": "", + "NOTE: This process must stay alive for the mount to be accessible ...": "", "None of known repositories in your location is accessible. Use %s as fallback.": "", "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "", + "Opening %s in your default browser...": "", + "Opening kubernetes service %s/%s in default browser...": "", + "Options: %s": "", "Please enter a value:": "", + "Please specify the directory to be mounted: \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "", "Powering off %q via SSH ...": "", + "Problems detected in %q:": "", "Pulling images ...": "Extrayant les images ... ", "Re-using the currently running %s VM for %q ...": "", "Related issues:": "", "Relaunching Kubernetes %s using %s ... ": "", "Requested disk size (%dMB) is less than minimum of %dMB": "", "Restarting existing %s VM for %q ...": "", + "Set failed": "", "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": "", + "Sorry, completion support is not yet implemented for %q": "", "Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2": "", "Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2": "", + "Sorry, the kubeadm.%s parameter is currently not supported by --extra-config": "", "Stopping %q in %s ...": "", + "Successfully mounted %s to %s": "", + "Target directory %q must be an absolute path": "", + "The %q cluster has been deleted.": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "", + "The docker host is currently not running": "", + "The docker service is currently not active": "", + "The kvm driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the kvm2 driver, which is intended to replace the kvm driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", + "The value passed to --format is invalid": "", + "The value passed to --format is invalid: %s": "", + "The vmwarefusion driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", + "The xhyve driver is deprecated and support for it will be removed in a future release.\nPlease consider switching to the hyperkit driver, which is intended to replace the xhyve driver.\nSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver for more information.\nTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", "There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n": "", "These changes will take effect upon a minikube delete and then a minikube start": "", + "This addon does not have an endpoint defined for the 'addons open' command.\nYou can add one by annotating a service with the label %s:%s": "", "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true": "", "Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.": "", "To connect to this cluster, use: kubectl --context=%s": "", "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`": "", "To use kubectl or minikube commands as your own user, you may": "", + "Type: %s": "", + "UID: %s": "", "Unable to bind flags": "", + "Unable to enable dashboard": "", + "Unable to fetch latest version info": "", "Unable to get VM IP address": "", + "Unable to get runtime": "", + "Unable to kill mount process: %s": "", "Unable to load cached images from config file.": "", "Unable to load cached images: %v": "", "Unable to load config: %v": "", "Unable to parse %q: %v": "", "Unable to pull images, which may be OK: %v": "", "Unable to start VM": "", + "Unable to stop VM": "", + "Uninstalling Kubernetes %s using %s ...": "", + "Unmounting %s ...": "", + "Update server returned an empty list": "", + "Usage: minikube completion SHELL": "", + "Userspace file server is shutdown": "", + "Userspace file server: ": "", + "Verifying dashboard health ...": "", + "Verifying proxy health ...": "", "Verifying:": "Vérifiant:", + "Version: %s": "", "Wait failed": "", + "Wait failed: %v": "", "Waiting for SSH access ...": "Attendant l'accès SSH ...", "Writing translation files": "", + "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (%s). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details": "", + "You must specify a service name": "", + "addon '%s' is currently not enabled.\nTo enable this addon run:\nminikube addons enable %s": "", + "addon '%s' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "", + "addon list failed": "", + "api load": "", + "bash completion failed": "", "checking main repository and mirrors for images": "", + "command runner": "", + "config view failed": "", + "disable failed": "", + "enable failed: %v": "", + "env %s": "", + "error creating clientset": "", + "error creating machine client": "", "error getting driver": "", + "error parsing the input ip address for mount": "", + "error starting tunnel": "", + "failed to open browser: %v": "", "kubectl and minikube configuration will be stored in %s": "", + "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", + "kubectl proxy": "", + "logdir set failed": "", "minikube %s on %s (%s)": "minikube %s sur %s (%s)", "minikube is not running, so the service cannot be accessed": "", + "minikube profile was successfully set to %s": "", "minikube will upgrade the local cluster from Kubernetes %s to %s": "", + "mount argument %q must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", + "mount failed": "", "need to relocate them. For example, to overwrite your own settings:": "", + "opt %s": "", + "set failed": "", + "stat failed": "", "unable to bind flags": "", "unable to set logtostderr": "", + "unset failed": "", "unsupported driver: %s": "", - "using image repository %s": "" + "update config": "", + "usage: minikube addons configure ADDON_NAME": "", + "usage: minikube addons disable ADDON_NAME": "", + "usage: minikube addons enable ADDON_NAME": "", + "usage: minikube addons list": "", + "usage: minikube addons open ADDON_NAME": "", + "usage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", + "usage: minikube config unset PROPERTY_NAME": "", + "usage: minikube delete": "", + "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", + "using image repository %s": "", + "zsh completion failed": "" } \ No newline at end of file From 062a4539b3ec9ac47dcb01efe1a3d6bafb61e41f Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Wed, 19 Jun 2019 17:46:00 -0700 Subject: [PATCH 20/25] test actually passes now --- pkg/minikube/extract/extract_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/minikube/extract/extract_test.go b/pkg/minikube/extract/extract_test.go index a35528876cc5..3e42c3037d2f 100644 --- a/pkg/minikube/extract/extract_test.go +++ b/pkg/minikube/extract/extract_test.go @@ -12,7 +12,7 @@ func TestExtract(t *testing.T) { paths := []string{"testdata/sample_file.go"} // The function we care about - functions := []string{"PrintToScreen"} + functions := []string{"extract.PrintToScreen"} // The directory where the sample translation file is in output := "testdata/" From d1eea5343cefc49ca6762dff784d11e5bd785856 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Wed, 19 Jun 2019 17:58:52 -0700 Subject: [PATCH 21/25] add demo translation file for zh-CN --- pkg/minikube/extract/extract_test.go | 6 +++++- pkg/minikube/translate/translations/zh-CN.json | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 pkg/minikube/translate/translations/zh-CN.json diff --git a/pkg/minikube/extract/extract_test.go b/pkg/minikube/extract/extract_test.go index 3e42c3037d2f..e6feda401999 100644 --- a/pkg/minikube/extract/extract_test.go +++ b/pkg/minikube/extract/extract_test.go @@ -25,7 +25,11 @@ func TestExtract(t *testing.T) { "Wow another string: %s": "", } - TranslatableStrings(paths, functions, output) + err := TranslatableStrings(paths, functions, output) + + if err != nil { + t.Fatalf("Error translating strings: %v", err) + } var got map[string]interface{} f, err := ioutil.ReadFile("testdata/test.json") diff --git a/pkg/minikube/translate/translations/zh-CN.json b/pkg/minikube/translate/translations/zh-CN.json new file mode 100644 index 000000000000..14b15f6591e2 --- /dev/null +++ b/pkg/minikube/translate/translations/zh-CN.json @@ -0,0 +1,9 @@ +{ + "minikube %s on %s (%s)": "", + "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "", + "Configuring environment for Kubernetes %s on %s %s": "", + "Pulling images ...": "", + "Launching Kubernetes ...": "", + "Verifying:": "", + "Done! kubectl is now configured to use %q": "" +} \ No newline at end of file From 7fc7b245e1bd29878b7dbfa3ca1c4aa53ab432bd Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Wed, 19 Jun 2019 18:21:39 -0700 Subject: [PATCH 22/25] fix linting errors --- go.mod | 1 - go.sum | 1 + pkg/minikube/console/console_test.go | 8 ++++++-- pkg/minikube/extract/extract.go | 3 ++- pkg/minikube/extract/extract_test.go | 21 +++++++++++++++++++- pkg/minikube/extract/testdata/sample_file.go | 16 +++++++++++++++ 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 8fa59aefa8d1..56bb77c28651 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,6 @@ require ( github.com/moby/hyperkit v0.0.0-20171020124204-a12cd7250bcd github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect - github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.7 github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd github.com/onsi/ginkgo v1.8.0 // indirect github.com/onsi/gomega v1.5.0 // indirect diff --git a/go.sum b/go.sum index 89183a68a7ef..b336602e112e 100644 --- a/go.sum +++ b/go.sum @@ -208,6 +208,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= diff --git a/pkg/minikube/console/console_test.go b/pkg/minikube/console/console_test.go index bcf5cd59fa7f..b1c3e86fec1c 100644 --- a/pkg/minikube/console/console_test.go +++ b/pkg/minikube/console/console_test.go @@ -87,7 +87,9 @@ func TestOut(t *testing.T) { } for _, tc := range testCases { t.Run(tc.format, func(t *testing.T) { - translate.SetPreferredLanguage(tc.lang) + if err := translate.SetPreferredLanguage(tc.lang); err != nil { + t.Errorf("unexpected error: %q", err) + } f := tests.NewFakeFile() SetOutFile(f) ErrLn("unrelated message") @@ -140,7 +142,9 @@ func TestSetPreferredLanguage(t *testing.T) { for _, tc := range tests { t.Run(tc.input, func(t *testing.T) { // Set something so that we can assert change. - translate.SetPreferredLanguage("is") + if err := translate.SetPreferredLanguage("is"); err != nil { + t.Errorf("unexpected error: %q", err) + } if err := translate.SetPreferredLanguage(tc.input); err != nil { t.Errorf("unexpected error: %q", err) } diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index 7c534b602138..d275738db7f9 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -56,7 +56,7 @@ type state struct { // The file we're currently checking filename string - // THe package we're currenly in + // The package we're currently in currentPackage string } @@ -71,6 +71,7 @@ func newExtractor(functionsToCheck []string) (*state, error) { fs := stack.New() for _, t := range functionsToCheck { + // Functions must be of the form "package.function" t2 := strings.Split(t, ".") if len(t2) < 2 { return nil, errors.Wrap(nil, fmt.Sprintf("Invalid function string %s. Needs package name as well.", t)) diff --git a/pkg/minikube/extract/extract_test.go b/pkg/minikube/extract/extract_test.go index e6feda401999..135e430fea80 100644 --- a/pkg/minikube/extract/extract_test.go +++ b/pkg/minikube/extract/extract_test.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package extract import ( @@ -37,7 +53,10 @@ func TestExtract(t *testing.T) { t.Fatalf("Reading json file: %s", err) } - json.Unmarshal(f, &got) + err = json.Unmarshal(f, &got) + if err != nil { + t.Fatalf("Error unmarshalling json: %v", err) + } if !reflect.DeepEqual(expected, got) { t.Fatalf("Translation JSON not equal: expected %v, got %v", expected, got) diff --git a/pkg/minikube/extract/testdata/sample_file.go b/pkg/minikube/extract/testdata/sample_file.go index a6316ea5cae4..2f28cd0d38c3 100644 --- a/pkg/minikube/extract/testdata/sample_file.go +++ b/pkg/minikube/extract/testdata/sample_file.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package extract import "fmt" From 3be580c97cce15c0ee4edeab56a9a04c78000577 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Thu, 20 Jun 2019 09:55:29 -0700 Subject: [PATCH 23/25] add comment for top level command and add chinese transkations --- cmd/extract/extract.go | 7 +++++++ pkg/minikube/translate/translations/zh-CN.json | 14 +++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cmd/extract/extract.go b/cmd/extract/extract.go index 845651557acf..f4ebf0a5d8b2 100644 --- a/cmd/extract/extract.go +++ b/cmd/extract/extract.go @@ -14,6 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ +/* This file scans all of minikube's code and finds all strings that need to be able to be translated. +It uses the more generic extract.TranslatableStringd, and prints all the translations +into every json file it can find in pkg/minikube/translate/translations. + +Usage: from the root minikube directory, go run cmd/extract/extract.go +*/ + package main import ( diff --git a/pkg/minikube/translate/translations/zh-CN.json b/pkg/minikube/translate/translations/zh-CN.json index 14b15f6591e2..8361e41caf3f 100644 --- a/pkg/minikube/translate/translations/zh-CN.json +++ b/pkg/minikube/translate/translations/zh-CN.json @@ -1,9 +1,9 @@ { - "minikube %s on %s (%s)": "", - "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "", - "Configuring environment for Kubernetes %s on %s %s": "", - "Pulling images ...": "", - "Launching Kubernetes ...": "", - "Verifying:": "", - "Done! kubectl is now configured to use %q": "" + "minikube %s on %s (%s)": "您正在使用minikube %s, 运行平台:%s (%s)", + "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "正在创建%s虚拟机(CPU =%d,内存=%dMB,磁盘=%dMB)...", + "Configuring environment for Kubernetes %s on %s %s": "开始为Kubernetes %s,%s %s 配置环境变量", + "Pulling images ...": "拉取镜像 ...", + "Launching Kubernetes ...": "正在启动 Kubernetes ...", + "Verifying:": "正在验证:", + "Done! kubectl is now configured to use %q": "完成!kubectl已经配置至%q" } \ No newline at end of file From 7a8fb7d489b2a018d43145b78b465a432041974c Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Thu, 20 Jun 2019 13:52:57 -0700 Subject: [PATCH 24/25] add more entries to the blacklist and clean up translation files --- pkg/minikube/extract/extract.go | 15 +- .../translate/translations/fr-FR.json | 9 +- .../translate/translations/zh-CN.json | 243 +++++++++++++++++- 3 files changed, 252 insertions(+), 15 deletions(-) diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index d275738db7f9..4005b729fb33 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -34,7 +34,13 @@ import ( ) // blacklist is a list of strings to explicitly omit from translation files. -var blacklist = []string{"%s: %v"} +var blacklist = []string{ + "%s: %v", + "%s.%s=%s", + "%s/%d", + "%s=%s", + "%v", +} // state is a struct that represent the current state of the extraction process type state struct { @@ -351,6 +357,13 @@ func writeStringsToFiles(e *state, output string) error { } } + // Remove translations from the file that are empty and were not extracted + for k, v := range currentTranslations { + if _, ok := e.translations[k]; !ok && len(v.(string)) == 0 { + delete(currentTranslations, k) + } + } + c, err := json.MarshalIndent(currentTranslations, "", "\t") if err != nil { return errors.Wrap(err, "marshalling translations") diff --git a/pkg/minikube/translate/translations/fr-FR.json b/pkg/minikube/translate/translations/fr-FR.json index 9e2636062c26..f0135e1afac0 100644 --- a/pkg/minikube/translate/translations/fr-FR.json +++ b/pkg/minikube/translate/translations/fr-FR.json @@ -12,10 +12,7 @@ "%s was successfully configured": "", "%s was successfully disabled": "", "%s was successfully enabled": "", - "%s.%s=%s": "", - "%s/%d": "", "%s:%s is not running: %v": "", - "%s=%s": "", "'none' driver does not support 'minikube docker-env' command": "", "'none' driver does not support 'minikube mount' command": "", "'none' driver does not support 'minikube ssh' command": "", @@ -23,14 +20,12 @@ "Alternatively, you may delete the existing VM using `minikube delete -p %s`": "", "Cannot find directory %s for mount": "", "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.": "", - "Compiling translation strings...": "", "Configuring environment for Kubernetes %s on %s %s": "Configurant l'environment pour Kubernetes %s sur %s %s", "Configuring local host environment ...": "", "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "Créant un VM %s (CPUs=%d, Mémoire=%dMB, Disque=%dMB)", "Creating mount %s ...": "", "Deleting %q from %s ...": "", "Documentation: %s": "", - "Done!": "", "Done! kubectl is now configured to use %q": "Fini! kubectl est maintenant configuré pour utiliser %s.", "Download complete!": "", "Downloading %s %s": "", @@ -136,6 +131,8 @@ "Requested disk size (%dMB) is less than minimum of %dMB": "", "Restarting existing %s VM for %q ...": "", "Set failed": "", + "Setting profile failed": "", + "Skipped switching kubectl context for %s , because --keep-context": "", "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": "", "Sorry, completion support is not yet implemented for %q": "", "Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2": "", @@ -189,7 +186,6 @@ "Wait failed": "", "Wait failed: %v": "", "Waiting for SSH access ...": "Attendant l'accès SSH ...", - "Writing translation files": "", "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (%s). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details": "", "You must specify a service name": "", "addon '%s' is currently not enabled.\nTo enable this addon run:\nminikube addons enable %s": "", @@ -221,7 +217,6 @@ "mount failed": "", "need to relocate them. For example, to overwrite your own settings:": "", "opt %s": "", - "set failed": "", "stat failed": "", "unable to bind flags": "", "unable to set logtostderr": "", diff --git a/pkg/minikube/translate/translations/zh-CN.json b/pkg/minikube/translate/translations/zh-CN.json index 8361e41caf3f..8779aceb5fca 100644 --- a/pkg/minikube/translate/translations/zh-CN.json +++ b/pkg/minikube/translate/translations/zh-CN.json @@ -1,9 +1,238 @@ { - "minikube %s on %s (%s)": "您正在使用minikube %s, 运行平台:%s (%s)", - "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "正在创建%s虚拟机(CPU =%d,内存=%dMB,磁盘=%dMB)...", - "Configuring environment for Kubernetes %s on %s %s": "开始为Kubernetes %s,%s %s 配置环境变量", - "Pulling images ...": "拉取镜像 ...", - "Launching Kubernetes ...": "正在启动 Kubernetes ...", - "Verifying:": "正在验证:", - "Done! kubectl is now configured to use %q": "完成!kubectl已经配置至%q" + "%q VM does not exist, nothing to stop": "", + "%q cluster does not exist": "", + "%q host does not exist, unable to show an IP": "", + "%q profile does not exist": "", + "%q stopped.": "", + "%s IP has been updated to point at %s": "", + "%s IP was already correctly configured for %s": "", + "%s has no available configuration options": "", + "%s is not responding properly: %v": "", + "%s is not yet a supported filesystem. We will try anyways!": "", + "%s was successfully configured": "", + "%s was successfully disabled": "", + "%s was successfully enabled": "", + "%s:%s is not running: %v": "", + "'none' driver does not support 'minikube docker-env' command": "", + "'none' driver does not support 'minikube mount' command": "", + "'none' driver does not support 'minikube ssh' command": "", + "Advice: %s": "", + "Alternatively, you may delete the existing VM using `minikube delete -p %s`": "", + "Cannot find directory %s for mount": "", + "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.": "", + "Configuring environment for Kubernetes %s on %s %s": "开始为Kubernetes %s,%s %s 配置环境变量", + "Configuring local host environment ...": "", + "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "正在创建%s虚拟机(CPU =%d,内存=%dMB,磁盘=%dMB)...", + "Creating mount %s ...": "", + "Deleting %q from %s ...": "", + "Documentation: %s": "", + "Done! kubectl is now configured to use %q": "完成!kubectl已经配置至%q", + "Download complete!": "", + "Downloading %s %s": "", + "Downloading Minikube ISO ...": "", + "ERROR creating `registry-creds-dpr` secret": "", + "ERROR creating `registry-creds-ecr` secret: %v": "", + "ERROR creating `registry-creds-gcr` secret: %v": "", + "Enabling dashboard ...": "", + "Error creating list template": "", + "Error creating minikube directory": "", + "Error creating status template": "", + "Error creating view template": "", + "Error executing list template": "", + "Error executing status template": "", + "Error executing template": "", + "Error executing view template": "", + "Error finding port for mount": "", + "Error getting IP": "", + "Error getting bootstrapper": "", + "Error getting client": "", + "Error getting client: %v": "", + "Error getting cluster": "", + "Error getting cluster bootstrapper": "", + "Error getting config": "", + "Error getting host": "", + "Error getting host status": "", + "Error getting machine logs": "", + "Error getting machine status": "", + "Error getting service status": "", + "Error getting service with namespace: %s and labels %s:%s: %v": "", + "Error getting the host IP address to use from within the VM": "", + "Error host driver ip status": "", + "Error killing mount process": "", + "Error loading api": "", + "Error opening service": "", + "Error reading %s: %v": "", + "Error restarting cluster": "", + "Error setting shell variables": "", + "Error starting cluster": "", + "Error starting mount": "", + "Error unsetting shell variables": "", + "Error writing mount pid": "", + "Error: [%s] %v": "", + "Exiting due to %s signal": "", + "Failed to cache ISO": "", + "Failed to cache and load images": "", + "Failed to cache binaries": "", + "Failed to cache images": "", + "Failed to check if machine exists": "", + "Failed to check main repository and mirrors for images for images": "", + "Failed to chown %s: %v": "", + "Failed to delete cluster": "", + "Failed to delete images": "", + "Failed to delete images from config": "", + "Failed to download kubectl": "", + "Failed to enable container runtime": "", + "Failed to generate config": "", + "Failed to get bootstrapper": "", + "Failed to get command runner": "", + "Failed to get driver URL": "", + "Failed to get image map": "", + "Failed to get machine client": "", + "Failed to get service URL: %v": "", + "Failed to kill mount process: %v": "", + "Failed to list cached images": "", + "Failed to remove profile": "", + "Failed to save config": "", + "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,%s`.": "", + "Failed to setup certs": "", + "Failed to setup kubeconfig": "", + "Failed to update cluster": "", + "Failed to update config": "", + "Failed unmount: %v": "", + "Follow": "", + "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", + "For more information, see:": "", + "Found network options:": "", + "GID: %s": "", + "If the above advice does not help, please let us know: ": "", + "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": "", + "IsEnabled failed": "", + "Kubernetes downgrade is not supported, will continue to use %v": "", + "Launching Kubernetes ...": "正在启动 Kubernetes ...", + "Launching Kubernetes ... ": "", + "Launching proxy ...": "", + "MSize: %d": "", + "Mode: %o (%s)": "", + "Mount options:": "", + "Mounting host path %s into VM as %s ...": "", + "NOTE: This process must stay alive for the mount to be accessible ...": "", + "None of known repositories in your location is accessible. Use %s as fallback.": "", + "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "", + "Opening %s in your default browser...": "", + "Opening kubernetes service %s/%s in default browser...": "", + "Options: %s": "", + "Please enter a value:": "", + "Please specify the directory to be mounted: \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "", + "Powering off %q via SSH ...": "", + "Problems detected in %q:": "", + "Pulling images ...": "拉取镜像 ...", + "Re-using the currently running %s VM for %q ...": "", + "Related issues:": "", + "Relaunching Kubernetes %s using %s ... ": "", + "Requested disk size (%dMB) is less than minimum of %dMB": "", + "Restarting existing %s VM for %q ...": "", + "Set failed": "", + "Setting profile failed": "", + "Skipped switching kubectl context for %s , because --keep-context": "", + "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": "", + "Sorry, completion support is not yet implemented for %q": "", + "Sorry, the --gpu feature is currently only supported with --vm-driver=kvm2": "", + "Sorry, the --hidden feature is currently only supported with --vm-driver=kvm2": "", + "Sorry, the kubeadm.%s parameter is currently not supported by --extra-config": "", + "Stopping %q in %s ...": "", + "Successfully mounted %s to %s": "", + "Target directory %q must be an absolute path": "", + "The %q cluster has been deleted.": "", + "The 'none' driver provides limited isolation and may reduce system security and reliability.": "", + "The docker host is currently not running": "", + "The docker service is currently not active": "", + "The kvm driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the kvm2 driver, which is intended to replace the kvm driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", + "The value passed to --format is invalid": "", + "The value passed to --format is invalid: %s": "", + "The vmwarefusion driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", + "The xhyve driver is deprecated and support for it will be removed in a future release.\nPlease consider switching to the hyperkit driver, which is intended to replace the xhyve driver.\nSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver for more information.\nTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", + "There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n": "", + "These changes will take effect upon a minikube delete and then a minikube start": "", + "This addon does not have an endpoint defined for the 'addons open' command.\nYou can add one by annotating a service with the label %s:%s": "", + "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true": "", + "Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.": "", + "To connect to this cluster, use: kubectl --context=%s": "", + "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`": "", + "To use kubectl or minikube commands as your own user, you may": "", + "Type: %s": "", + "UID: %s": "", + "Unable to bind flags": "", + "Unable to enable dashboard": "", + "Unable to fetch latest version info": "", + "Unable to get VM IP address": "", + "Unable to get runtime": "", + "Unable to kill mount process: %s": "", + "Unable to load cached images from config file.": "", + "Unable to load cached images: %v": "", + "Unable to load config: %v": "", + "Unable to parse %q: %v": "", + "Unable to pull images, which may be OK: %v": "", + "Unable to start VM": "", + "Unable to stop VM": "", + "Uninstalling Kubernetes %s using %s ...": "", + "Unmounting %s ...": "", + "Update server returned an empty list": "", + "Usage: minikube completion SHELL": "", + "Userspace file server is shutdown": "", + "Userspace file server: ": "", + "Verifying dashboard health ...": "", + "Verifying proxy health ...": "", + "Verifying:": "正在验证:", + "Version: %s": "", + "Wait failed": "", + "Wait failed: %v": "", + "Waiting for SSH access ...": "", + "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (%s). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details": "", + "You must specify a service name": "", + "addon '%s' is currently not enabled.\nTo enable this addon run:\nminikube addons enable %s": "", + "addon '%s' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "", + "addon list failed": "", + "api load": "", + "bash completion failed": "", + "checking main repository and mirrors for images": "", + "command runner": "", + "config view failed": "", + "disable failed": "", + "enable failed: %v": "", + "env %s": "", + "error creating clientset": "", + "error creating machine client": "", + "error getting driver": "", + "error parsing the input ip address for mount": "", + "error starting tunnel": "", + "failed to open browser: %v": "", + "kubectl and minikube configuration will be stored in %s": "", + "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", + "kubectl proxy": "", + "logdir set failed": "", + "minikube %s on %s (%s)": "您正在使用minikube %s, 运行平台:%s (%s)", + "minikube is not running, so the service cannot be accessed": "", + "minikube profile was successfully set to %s": "", + "minikube will upgrade the local cluster from Kubernetes %s to %s": "", + "mount argument %q must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", + "mount failed": "", + "need to relocate them. For example, to overwrite your own settings:": "", + "opt %s": "", + "stat failed": "", + "unable to bind flags": "", + "unable to set logtostderr": "", + "unset failed": "", + "unsupported driver: %s": "", + "update config": "", + "usage: minikube addons configure ADDON_NAME": "", + "usage: minikube addons disable ADDON_NAME": "", + "usage: minikube addons enable ADDON_NAME": "", + "usage: minikube addons list": "", + "usage: minikube addons open ADDON_NAME": "", + "usage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", + "usage: minikube config unset PROPERTY_NAME": "", + "usage: minikube delete": "", + "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", + "using image repository %s": "", + "zsh completion failed": "" } \ No newline at end of file From 8f5026db9134773049b0ea7a639646356e271504 Mon Sep 17 00:00:00 2001 From: Sharif Elgamal Date: Thu, 20 Jun 2019 14:23:53 -0700 Subject: [PATCH 25/25] small fix --- pkg/minikube/translate/translations/zh-CN.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/minikube/translate/translations/zh-CN.json b/pkg/minikube/translate/translations/zh-CN.json index 8779aceb5fca..258e24b44e9f 100644 --- a/pkg/minikube/translate/translations/zh-CN.json +++ b/pkg/minikube/translate/translations/zh-CN.json @@ -108,8 +108,7 @@ "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": "", "IsEnabled failed": "", "Kubernetes downgrade is not supported, will continue to use %v": "", - "Launching Kubernetes ...": "正在启动 Kubernetes ...", - "Launching Kubernetes ... ": "", + "Launching Kubernetes ... ": "正在启动 Kubernetes ... ", "Launching proxy ...": "", "MSize: %d": "", "Mode: %o (%s)": "",