提交 f2d6f455 编写于 作者: T Thomas Stromberg

More console work

上级 cf938ee5
......@@ -655,12 +655,20 @@
revision = "95c6576299259db960f6c5b9b69ea52422860fce"
[[projects]]
digest = "1:5b12278b98e82aecd7d0b84e0b5fba67f37aba8fde89fa86d51e30556d381a4c"
branch = "master"
digest = "1:11d290de3457882172ce8d9ffe930999cfb62929b58e486e1ff1b6adcf3c52bc"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"feature/plural",
"internal",
"internal/catmsg",
"internal/colltab",
"internal/format",
"internal/gen",
"internal/language",
"internal/language/compact",
"internal/number",
"internal/stringset",
"internal/tag",
......@@ -677,7 +685,7 @@
"unicode/rangetable",
]
pruneopts = "NUT"
revision = "b19bf474d317b857955b12035d2c5acb57ce8b01"
revision = "e6919f6577db79269a6443b9dc46d18f2238fb5d"
[[projects]]
digest = "1:d37b0ef2944431fe9e8ef35c6fffc8990d9e2ca300588df94a6890f3649ae365"
......
......@@ -113,3 +113,4 @@
[[constraint]]
name = "golang.org/x/text"
branch = "master"
......@@ -19,6 +19,8 @@ package cmd
import (
"os"
"github.com/docker/machine/libmachine/mcnerror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cmdUtil "k8s.io/minikube/cmd/util"
......@@ -40,8 +42,8 @@ associated files.`,
console.ErrStyle("usage", "usage: minikube delete")
os.Exit(1)
}
console.OutStyle("stopping", "Deleting local Kubernetes cluster ...")
profile := viper.GetString(pkg_config.MachineProfile)
console.OutStyle("deleting-vm", "Deleting %q Kubernetes cluster ...", profile)
api, err := machine.NewAPIClient()
if err != nil {
console.Fatal("Error getting client: %v", err)
......@@ -50,19 +52,30 @@ associated files.`,
defer api.Close()
if err = cluster.DeleteHost(api); err != nil {
console.Fatal("Errors occurred deleting machine: %v", err)
os.Exit(1)
switch err := errors.Cause(err).(type) {
case mcnerror.ErrHostDoesNotExist:
console.OutStyle("meh", "%q VM does not exist", profile)
default:
console.Fatal("Failed to delete VM: %v", err)
os.Exit(1)
}
} else {
console.Success("VM deleted.")
}
console.Success("Machine deleted.")
if err := cmdUtil.KillMountProcess(); err != nil {
console.Fatal("Errors occurred deleting mount process: %v", err)
console.Fatal("Failed to kill mount process: %v", err)
}
if err := os.Remove(constants.GetProfileFile(viper.GetString(pkg_config.MachineProfile))); err != nil {
console.Fatal("Error deleting machine profile config: %v", err)
if os.IsNotExist(err) {
console.OutStyle("meh", "%q profile does not exist", profile)
os.Exit(0)
}
console.Fatal("Failed to remove profile: %v", err)
os.Exit(1)
}
console.Success("Removed %q profile!", profile)
},
}
......
......@@ -199,25 +199,35 @@ func runStart(cmd *cobra.Command, args []string) {
fatalExit("Error saving profile cluster configuration: %v", err)
}
console.OutStyle("starting-vm", "Starting local Kubernetes %s cluster ...", viper.GetString(kubernetesVersion))
// TODO(tstromberg): Include version of VM software in output
if config.VMDriver == constants.DriverNone {
console.OutStyle("starting-none", "Configuring local host environment ...")
} else {
console.OutStyle("starting-vm", "Starting %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...", viper.GetString(vmDriver), config.CPUs, config.Memory, config.DiskSize)
}
var host *host.Host
start := func() (err error) {
host, err = cluster.StartHost(api, config)
if err != nil {
glog.Errorf("StartHost: %v", err)
glog.Infof("StartHost: %v", err)
}
return err
}
err = pkgutil.RetryAfter(5, start, 2*time.Second)
if err != nil {
reportAndExit("Error starting host: ", err)
reportErrAndExit("Unable to start VM", err)
}
console.OutStyle("connectivity", "Verifying connectivity ...")
for _, k := range []string{"HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY"} {
if v := os.Getenv(k); v != "" {
console.OutStyle("options", "%s=%s", k, v)
}
}
ip, err := host.Driver.GetIP()
if err != nil {
reportAndExit("Unable to get VM IP address", err)
reportErrAndExit("Unable to get VM IP address", err)
}
// common config (currently none)
......@@ -229,7 +239,7 @@ func runStart(cmd *cobra.Command, args []string) {
_, err = host.RunSSHCommand(command)
}
if err != nil {
reportAndExit("Error writing crictl config", err)
reportErrAndExit("Error writing crictl config", err)
}
}
......@@ -256,6 +266,9 @@ func runStart(cmd *cobra.Command, args []string) {
selectedKubernetesVersion = version.VersionPrefix + oldKubernetesVersion.String()
console.ErrStyle("conflict", "Kubernetes downgrade is not supported, will continue to use %v", selectedKubernetesVersion)
}
if newKubernetesVersion.GT(oldKubernetesVersion) {
console.OutStyle("thumbs-up", "Will upgrade local cluster from Kubernetes %s to %s", oldKubernetesVersion, newKubernetesVersion)
}
}
}
......@@ -277,10 +290,9 @@ func runStart(cmd *cobra.Command, args []string) {
ShouldLoadCachedImages: shouldCacheImages,
EnableDefaultCNI: viper.GetBool(enableDefaultCNI),
}
k8sBootstrapper, err := GetClusterBootstrapper(api, clusterBootstrapper)
if err != nil {
reportAndExit("Error getting cluster bootstrapper", err)
reportErrAndExit("Error getting cluster bootstrapper", err)
}
// Write profile cluster configuration to file
......@@ -290,7 +302,7 @@ func runStart(cmd *cobra.Command, args []string) {
}
if err := saveConfig(clusterConfig); err != nil {
reportAndExit("Error saving profile cluster configuration", err)
reportErrAndExit("Error saving profile cluster configuration", err)
}
if shouldCacheImages {
......@@ -300,19 +312,23 @@ func runStart(cmd *cobra.Command, args []string) {
}
}
console.OutStyle("copying", "Copying files into VM ...")
console.OutStyle("copying", "Configuring minikube VM environment ...")
for _, eo := range extraOptions {
console.OutStyle("options", "%s.%s=%s", eo.Component, eo.Key, eo.Value)
}
if err := k8sBootstrapper.UpdateCluster(kubernetesConfig); err != nil {
reportAndExit("Failed to update cluster", err)
reportErrAndExit("Failed to update cluster", err)
}
if err := k8sBootstrapper.SetupCerts(kubernetesConfig); err != nil {
reportAndExit("Failed to setup certs", err)
reportErrAndExit("Failed to setup certs", err)
}
kubeHost, err := host.Driver.GetURL()
if err != nil {
reportAndExit("Failed to get driver URL", err)
reportErrAndExit("Failed to get driver URL", err)
}
kubeHost = strings.Replace(kubeHost, "tcp://", "https://", -1)
kubeHost = strings.Replace(kubeHost, ":2376", ":"+strconv.Itoa(kubernetesConfig.NodePort), -1)
......@@ -329,24 +345,33 @@ func runStart(cmd *cobra.Command, args []string) {
kubeCfgSetup.SetKubeConfigFile(kubeConfigFile)
if err := kubeconfig.SetupKubeConfig(kubeCfgSetup); err != nil {
reportAndExit("Failed to setup kubeconfig", err)
reportErrAndExit("Failed to setup kubeconfig", err)
}
// TODO(tstromberg): use cruntime.Manager.Name() once PR is merged
rname := viper.GetString(containerRuntime)
if rname == "" {
rname = "Docker"
}
console.OutStyle("container-runtime", "Configuring %s within VM ...", rname)
for _, v := range dockerOpt {
console.OutStyle("options", "opt %s", v)
}
for _, v := range dockerEnv {
console.OutStyle("options", "env %s", v)
}
if config.VMDriver != constants.DriverNone && selectedContainerRuntime != "" {
if _, err := host.RunSSHCommand("sudo systemctl stop docker"); err == nil {
_, err = host.RunSSHCommand("sudo systemctl stop docker.socket")
}
if err != nil {
reportAndExit("Failed to stop docker", err)
reportErrAndExit("Failed to stop docker", err)
}
}
if config.VMDriver != constants.DriverNone && (selectedContainerRuntime != constants.CrioRuntime && selectedContainerRuntime != constants.Cri_oRuntime) {
if _, err := host.RunSSHCommand("sudo systemctl stop crio"); err != nil {
reportAndExit("Failed to stop CRIO", err)
reportErrAndExit("Failed to stop CRIO", err)
}
}
if config.VMDriver != constants.DriverNone && selectedContainerRuntime != constants.RktRuntime {
......@@ -354,19 +379,19 @@ func runStart(cmd *cobra.Command, args []string) {
_, err = host.RunSSHCommand("sudo systemctl stop rkt-metadata")
}
if err != nil {
reportAndExit("Failed to stop rkt", err)
reportErrAndExit("Failed to stop rkt", err)
}
}
if config.VMDriver != constants.DriverNone && selectedContainerRuntime != constants.ContainerdRuntime {
if _, err = host.RunSSHCommand("sudo systemctl stop containerd"); err != nil {
reportAndExit("Failed to stop containerd", err)
reportErrAndExit("Failed to stop containerd", err)
}
}
if config.VMDriver != constants.DriverNone && (selectedContainerRuntime == constants.CrioRuntime || selectedContainerRuntime == constants.Cri_oRuntime) {
// restart crio so that it can monitor all hook dirs
if _, err := host.RunSSHCommand("sudo systemctl restart crio"); err != nil {
reportAndExit("Failed to restart crio", err)
reportErrAndExit("Failed to restart crio", err)
}
}
......@@ -374,7 +399,7 @@ func runStart(cmd *cobra.Command, args []string) {
console.Fatal("Restarting containerd runtime...")
// restart containerd so that it can install all plugins
if _, err := host.RunSSHCommand("sudo systemctl restart containerd"); err != nil {
reportAndExit("Failed to restart containerd", err)
reportErrAndExit("Failed to restart containerd", err)
}
}
......@@ -404,51 +429,53 @@ This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_
}
}
// TODO(tstromberg): Add call to bootstrapper.PullImages once PR is merged.
if !exists || config.VMDriver == constants.DriverNone {
console.OutStyle("launch", "Launching Kubernetes %s with %s ... ", kubernetesConfig.KubernetesVersion, clusterBootstrapper)
console.OutStyle("launch", "Launching Kubernetes %s using %s ... ", kubernetesConfig.KubernetesVersion, clusterBootstrapper)
if err := k8sBootstrapper.StartCluster(kubernetesConfig); err != nil {
reportAndExit("Error starting cluster", err)
reportErrAndExit("Error starting cluster", err)
}
} else {
console.OutStyle("restarting", "Relaunching Kubernetes %s with %s ... ", kubernetesConfig.KubernetesVersion, clusterBootstrapper)
console.OutStyle("restarting", "Reconfiguring Kubernetes %s with %s ... ", kubernetesConfig.KubernetesVersion, clusterBootstrapper)
if err := k8sBootstrapper.RestartCluster(kubernetesConfig); err != nil {
reportAndExit("Error restarting cluster", err)
reportErrAndExit("Error restarting cluster", err)
}
}
// Block until the cluster is healthy.
console.OutStyle("verifying", "Verifying component health ...")
console.OutStyle("verifying-noline", "Verifying component health ...")
// TODO(tstromberg): Display pod health.
kStat := func() (err error) {
st, err := k8sBootstrapper.GetKubeletStatus()
console.Out(".")
if err != nil || st != state.Running.String() {
console.Out(".")
return &pkgutil.RetriableError{Err: fmt.Errorf("kubelet unhealthy: %v: %s", err, st)}
}
return nil
}
err = pkgutil.RetryAfter(20, kStat, 3*time.Second)
if err != nil {
reportAndExit("kubelet checks failed", err)
reportErrAndExit("kubelet checks failed", err)
}
aStat := func() (err error) {
st, err := k8sBootstrapper.GetApiServerStatus(net.ParseIP(ip))
console.Out(".")
if err != nil || st != state.Running.String() {
console.Out(".")
return &pkgutil.RetriableError{Err: fmt.Errorf("apiserver status=%s err=%v", st, err)}
}
return nil
}
err = pkgutil.RetryAfter(30, aStat, 10*time.Second)
// End the dots.
console.OutLn("")
if err != nil {
reportAndExit("apiserver checks failed", err)
reportErrAndExit("apiserver checks failed", err)
}
console.OutLn("")
// start 9p server mount
if viper.GetBool(createMount) {
console.OutStyle("mount", "Setting up mount on %s ...", viper.GetString(mountString))
console.OutStyle("mount", "Creating mount %s ...", viper.GetString(mountString))
path := os.Args[0]
mountDebugVal := 0
......@@ -484,8 +511,7 @@ This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_
if err != nil {
console.Failure("Unable to load cached images from config file.")
}
console.OutStyle("ready", "Your local Kubernetes cluster is ready! Thank you for using minikube!")
return
console.OutStyle("ready", "Done! Thank you for using minikube!")
}
func init() {
......@@ -585,15 +611,15 @@ func saveConfigToFile(data []byte, file string) error {
// fatalExit is a shortcut for outputting a failure message and exiting.
func fatalExit(format string, a ...interface{}) {
glog.Errorf(format, a...)
// use Warning because Error will display a duplicate message
glog.Warningf(format, a...)
console.Fatal(format, a...)
os.Exit(1)
}
// reportFatalExit is a shortcut for outputting an error, reporting it, and exiting.
func reportAndExit(msg string, err error) {
func reportErrAndExit(msg string, err error) {
console.Fatal(msg+": %v", err)
glog.Errorf("%s: %v", msg, err)
cmdutil.MaybeReportErrorAndExit(err)
os.Exit(1)
}
......@@ -20,9 +20,13 @@ import (
"os"
"time"
"github.com/docker/machine/libmachine/mcnerror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
pkg_config "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/console"
"k8s.io/minikube/pkg/minikube/machine"
pkgutil "k8s.io/minikube/pkg/util"
......@@ -35,7 +39,9 @@ var stopCmd = &cobra.Command{
Long: `Stops a local kubernetes cluster running in Virtualbox. This command stops the VM
itself, leaving all files intact. The cluster can be started again with the "start" command.`,
Run: func(cmd *cobra.Command, args []string) {
console.OutStyle("stopping", "Stopping local Kubernetes cluster...")
profile := viper.GetString(pkg_config.MachineProfile)
console.OutStyle("stopping", "Stopping %q Kubernetes cluster...", profile)
api, err := machine.NewAPIClient()
if err != nil {
console.Fatal("Error getting client: %v", err)
......@@ -43,17 +49,29 @@ itself, leaving all files intact. The cluster can be started again with the "sta
}
defer api.Close()
nonexistent := false
stop := func() (err error) {
return cluster.StopHost(api)
err = cluster.StopHost(api)
switch err := errors.Cause(err).(type) {
case mcnerror.ErrHostDoesNotExist:
console.OutStyle("meh", "%q VM does not exist, nothing to stop", profile)
nonexistent = true
return nil
default:
return err
}
}
if err := pkgutil.RetryAfter(5, stop, 1*time.Second); err != nil {
console.Fatal("Error stopping machine: %v", err)
console.Fatal("Unable to stop VM: %v", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
console.OutStyle("stopped", "Machine stopped.")
if !nonexistent {
console.OutStyle("stopped", "%q stopped.", profile)
}
if err := cmdUtil.KillMountProcess(); err != nil {
console.Fatal("Errors occurred deleting mount process: %v", err)
console.Fatal("Unable to kill mount process: %v", err)
}
},
}
......
......@@ -40,7 +40,7 @@ func main() {
}
console.SetOutFile(os.Stdout)
console.SetErrFile(os.Stderr)
err := console.SetLanguage(os.Getenv("LANG"))
err := console.SetPreferredLanguage(os.Getenv("LANG"))
if err != nil {
glog.Warningf("unable to detect language: %v", err)
}
......
......@@ -159,7 +159,6 @@ To disable this prompt, run: 'minikube config set WantReportErrorPrompt false'
if err != nil {
glog.Infof("report error failed: %v", err)
}
console.ErrStyle("embarassed", "minikube failed, exiting with error code %d", returnCode)
os.Exit(returnCode)
}
......
......@@ -383,10 +383,10 @@ func (k *KubeadmBootstrapper) UpdateCluster(cfg config.KubernetesConfig) error {
}
f, err := assets.NewFileAsset(path, "/usr/bin", bin, "0641")
if err != nil {
return errors.Wrap(err, "making new file asset")
return errors.Wrap(err, "new file asset")
}
if err := k.c.Copy(f); err != nil {
return errors.Wrapf(err, "transferring kubeadm file: %+v", f)
return errors.Wrapf(err, "copy")
}
return nil
})
......@@ -396,15 +396,16 @@ func (k *KubeadmBootstrapper) UpdateCluster(cfg config.KubernetesConfig) error {
}
if err := addAddons(&files); err != nil {
return errors.Wrap(err, "adding addons to copyable files")
return errors.Wrap(err, "adding addons")
}
for _, f := range files {
if err := k.c.Copy(f); err != nil {
return errors.Wrapf(err, "transferring kubeadm file: %+v", f)
return errors.Wrapf(err, "copy")
}
}
console.OutStyle("celebrate", "Starting kubelet %s ...", cfg.KubernetesVersion)
err = k.c.Run(`
sudo systemctl daemon-reload &&
sudo systemctl enable kubelet &&
......
......@@ -64,7 +64,7 @@ func init() {
func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) {
exists, err := api.Exists(cfg.GetMachineName())
if err != nil {
return nil, errors.Wrapf(err, "Error checking if host exists: %s", cfg.GetMachineName())
return nil, errors.Wrapf(err, "machine name: %s", cfg.GetMachineName())
}
if !exists {
glog.Infoln("Machine does not exist... provisioning new machine")
......@@ -91,10 +91,10 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error)
if s != state.Running {
if err := h.Driver.Start(); err != nil {
return nil, errors.Wrap(err, "Error starting stopped host")
return nil, errors.Wrap(err, "start")
}
if err := api.Save(h); err != nil {
return nil, errors.Wrap(err, "Error saving started host")
return nil, errors.Wrap(err, "save")
}
}
......@@ -122,7 +122,7 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error)
func StopHost(api libmachine.API) error {
host, err := api.Load(cfg.GetMachineName())
if err != nil {
return errors.Wrapf(err, "Load: %s", cfg.GetMachineName())
return errors.Wrapf(err, "load")
}
if err := host.Stop(); err != nil {
alreadyInStateError, ok := err.(mcnerror.ErrHostAlreadyInState)
......@@ -138,19 +138,22 @@ func StopHost(api libmachine.API) error {
func DeleteHost(api libmachine.API) error {
host, err := api.Load(cfg.GetMachineName())
if err != nil {
return errors.Wrapf(err, "Load: %s", cfg.GetMachineName())
return errors.Wrap(err, "load")
}
m := util.MultiError{}
m.Collect(host.Driver.Remove())
m.Collect(api.Remove(cfg.GetMachineName()))
return m.ToError()
if err := host.Driver.Remove(); err != nil {
return errors.Wrap(err, "host remove")
}
if err := api.Remove(cfg.GetMachineName()); err != nil {
return errors.Wrap(err, "api remove")
}
return nil
}
// GetHostStatus gets the status of the host VM.
func GetHostStatus(api libmachine.API) (string, error) {
exists, err := api.Exists(cfg.GetMachineName())
if err != nil {
return "", errors.Wrapf(err, "Error checking that api exists for: %s", cfg.GetMachineName())
return "", errors.Wrapf(err, "%s exists", cfg.GetMachineName())
}
if !exists {
return state.None.String(), nil
......@@ -158,12 +161,12 @@ func GetHostStatus(api libmachine.API) (string, error) {
host, err := api.Load(cfg.GetMachineName())
if err != nil {
return "", errors.Wrapf(err, "Error loading api for: %s", cfg.GetMachineName())
return "", errors.Wrapf(err, "load")
}
s, err := host.Driver.GetState()
if err != nil {
return "", errors.Wrap(err, "Error getting host state")
return "", errors.Wrap(err, "state")
}
return s.String(), nil
}
......@@ -177,11 +180,11 @@ func GetHostDriverIP(api libmachine.API, machineName string) (net.IP, error) {
ipStr, err := host.Driver.GetIP()
if err != nil {
return nil, errors.Wrap(err, "Error getting IP")
return nil, errors.Wrap(err, "getting IP")
}
ip := net.ParseIP(ipStr)
if ip == nil {
return nil, fmt.Errorf("error parsing IP: %s", ipStr)
return nil, fmt.Errorf("parsing IP: %s", ipStr)
}
return ip, nil
}
......@@ -249,12 +252,12 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error
data, err := json.Marshal(driver)
if err != nil {
return nil, errors.Wrap(err, "Error marshalling json")
return nil, errors.Wrap(err, "marshal")
}
h, err := api.NewHost(config.VMDriver, data)
if err != nil {
return nil, errors.Wrap(err, "Error creating new host")
return nil, errors.Wrap(err, "new host")
}
h.HostOptions.AuthOptions.CertDir = constants.GetMinipath()
......@@ -264,11 +267,11 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error
if err := api.Create(h); err != nil {
// Wait for all the logs to reach the client
time.Sleep(2 * time.Second)
return nil, errors.Wrap(err, "Error creating host")
return nil, errors.Wrap(err, "create")
}
if err := api.Save(h); err != nil {
return nil, errors.Wrap(err, "Error attempting to save")
return nil, errors.Wrap(err, "save")
}
return h, nil
}
......@@ -310,11 +313,11 @@ func MountHost(api libmachine.API, ip net.IP, path, port, mountVersion string, u
host.RunSSHCommand(GetMountCleanupCommand(path))
mountCmd, err := GetMountCommand(ip, path, port, mountVersion, uid, gid, msize)
if err != nil {
return errors.Wrap(err, "Error getting mount command")
return errors.Wrap(err, "mount command")
}
_, err = host.RunSSHCommand(mountCmd)
if err != nil {
return errors.Wrap(err, "running mount host command")
return errors.Wrap(err, "running mount")
}
return nil
}
......@@ -332,13 +335,13 @@ func GetVMHostIP(host *host.Host) (net.IP, error) {
hypervVirtualSwitch := re.FindStringSubmatch(string(host.RawDriver))[1]
ip, err := getIPForInterface(fmt.Sprintf("vEthernet (%s)", hypervVirtualSwitch))
if err != nil {
return []byte{}, errors.Wrap(err, "Error getting VM/Host IP address")
return []byte{}, errors.Wrap(err, fmt.Sprintf("ip for interface (%s)", hypervVirtualSwitch))
}
return ip, nil
case "virtualbox":
out, err := exec.Command(detectVBoxManageCmd(), "showvminfo", host.Name, "--machinereadable").Output()
if err != nil {
return []byte{}, errors.Wrap(err, "Error running vboxmanage command")
return []byte{}, errors.Wrap(err, "vboxmanage")
}
re := regexp.MustCompile(`hostonlyadapter2="(.*?)"`)
iface := re.FindStringSubmatch(string(out))[1]
......@@ -388,21 +391,21 @@ func CreateSSHShell(api libmachine.API, args []string) error {
machineName := cfg.GetMachineName()
host, err := CheckIfHostExistsAndLoad(api, machineName)
if err != nil {
return errors.Wrap(err, "Error checking if api exist and loading it")
return errors.Wrap(err, "host exists and load")
}
currentState, err := host.Driver.GetState()
if err != nil {
return errors.Wrap(err, "Error getting state of host")
return errors.Wrap(err, "state")
}
if currentState != state.Running {
return errors.Errorf("Error: Cannot run ssh command: Host %q is not running", machineName)
return errors.Errorf("%q is not running", machineName)
}
client, err := host.CreateSSHClient()
if err != nil {
return errors.Wrap(err, "Error creating ssh client")
return errors.Wrap(err, "Creating ssh client")
}
return client.Shell(args...)
}
......
/*
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 console provides a mechanism for sending localized, stylized output to the console.
package console
......
/*
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 console
import (
......@@ -30,7 +46,7 @@ func (f *fakeFile) String() string {
}
func TestOutStyle(t *testing.T) {
os.Setenv(OverrideEnv, "")
os.Setenv(OverrideEnv, "1")
f := newFakeFile()
SetOutFile(f)
if err := OutStyle("happy", "This is a happy message."); err != nil {
......
/*
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 console
import (
......@@ -15,39 +31,45 @@ type style struct {
}
// styles is a map of style name to style struct
// For consistency, ensure that emojis added render with the same width across platforms.
var styles = map[string]style{
// General purpose
"happy": style{Prefix: "😄"},
"success": style{Prefix: "✅ "},
"failure": style{Prefix: "❌"},
"conflict": style{Prefix: "💥"},
"fatal": style{Prefix: "💣"},
"notice": style{Prefix: "📌"},
"ready": style{Prefix: "🏄"},
"restarting": style{Prefix: "🔁"},
"stopping": style{Prefix: "🚦"},
"stopped": style{Prefix: "🛑"},
"warning": style{Prefix: "⚠️"},
"waiting": style{Prefix: "⌛"},
"usage": style{Prefix: "💡"},
"launch": style{Prefix: "🚀"},
"happy": {Prefix: "😄"},
"success": {Prefix: "✅"},
"failure": {Prefix: "❌"},
"conflict": {Prefix: "💥"},
"fatal": {Prefix: "💣"},
"notice": {Prefix: "📌"},
"ready": {Prefix: "🏄"},
"restarting": {Prefix: "🔄"},
"stopping": {Prefix: "✋"},
"stopped": {Prefix: "🛑"},
"warning": {Prefix: "⚠️"},
"waiting": {Prefix: "⌛"},
"usage": {Prefix: "💡"},
"launch": {Prefix: "🚀"},
"thumbs-up": {Prefix: "👍"},
"options": {Prefix: " ⚫"},
// Specialized purpose
"iso-download": style{Prefix: "💿"},
"file-download": style{Prefix: "💾"},
"caching": style{Prefix: "🤹"},
"starting-vm": style{Prefix: "🔥"},
"copying": style{Prefix: "✨"},
"connectivity": style{Prefix: "📡"},
"mounting": style{Prefix: "📁"},
"celebrate": style{Prefix: "🎉"},
"container-runtime": style{Prefix: "🎁"},
"enabling": style{Prefix: "🔌"},
"pulling": style{Prefix: "🚜"},
"verifying": style{Prefix: "🤔"},
"kubectl": style{Prefix: "❤️"},
"meh": style{Prefix: "🙄"},
"embarassed": style{Prefix: "🤦"},
// Specialized purpose styles
"iso-download": {Prefix: "💿"},
"file-download": {Prefix: "💾"},
"caching": {Prefix: "🤹"},
"starting-vm": {Prefix: "🔥"},
"starting-none": {Prefix: "🤹"},
"deleting-vm": {Prefix: "🔥"},
"copying": {Prefix: "✨"},
"connectivity": {Prefix: "📡"},
"mounting": {Prefix: "📁"},
"celebrate": {Prefix: "🎉"},
"container-runtime": {Prefix: "🎁"},
"enabling": {Prefix: "🔌"},
"pulling": {Prefix: "🚜"},
"verifying": {Prefix: "🤔"},
"verifying-noline": {Prefix: "🤔", OmitNewline: true},
"kubectl": {Prefix: "💗"},
"meh": {Prefix: "🙄"},
"embarassed": {Prefix: "🤦"},
"tip": {Prefix: "💡"},
}
// Add a prefix to a string
......
......@@ -19,7 +19,6 @@ package machine
import (
"crypto/tls"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
......@@ -121,7 +120,7 @@ func (api *LocalClient) NewHost(driverName string, rawDriver []byte) (*host.Host
func (api *LocalClient) Load(name string) (*host.Host, error) {
h, err := api.Filestore.Load(name)
if err != nil {
return nil, errors.Wrap(err, "Error loading host from store")
return nil, errors.Wrap(err, "filestore")
}
var def registry.DriverDef
......@@ -166,25 +165,25 @@ func (api *LocalClient) Create(h *host.Host) error {
f func() error
}{
{
"Bootstrapping certs.",
"bootstrapping certificates",
func() error { return cert.BootstrapCertificates(h.AuthOptions()) },
},
{
"Running precreate checks.",
"precreate",
h.Driver.PreCreateCheck,
},
{
"Saving driver.",
"saving",
func() error {
return api.Save(h)
},
},
{
"Creating VM.",
"creating",
h.Driver.Create,
},
{
"Waiting for VM to start.",
"waiting",
func() error {
if h.Driver.DriverName() == "none" {
return nil
......@@ -193,7 +192,7 @@ func (api *LocalClient) Create(h *host.Host) error {
},
},
{
"Provisioning VM.",
"provisioning",
func() error {
if h.Driver.DriverName() == "none" {
return nil
......@@ -206,7 +205,7 @@ func (api *LocalClient) Create(h *host.Host) error {
for _, step := range steps {
if err := step.f(); err != nil {
return errors.Wrap(err, fmt.Sprintf("Error executing step: %s\n", step.name))
return errors.Wrap(err, step.name)
}
}
......
......@@ -158,7 +158,7 @@ func TestRunDriver(t *testing.T) {
}
os.Stdout = old
fmt.Prinln(string(addr))
fmt.Println(string(addr))
// Now that we got the port, make sure we can connect.
if _, err := net.Dial("tcp", string(addr)); err != nil {
......
......@@ -74,8 +74,7 @@ type URLHandlerCorrect struct {
func (h *URLHandlerCorrect) ServeHTTP(w http.ResponseWriter, r *http.Request) {
b, err := json.Marshal(h.releases)
if err != nil {
// TODO(tstrombxerg): Do something else with this?
fmt.ErrLn(err)
fmt.Println(err)
return
}
w.Header().Set("Content-Type", "application/javascript")
......
......@@ -48,25 +48,43 @@ func NewCodeWriter() *CodeWriter {
}
// WriteGoFile appends the buffer with the total size of all created structures
// and writes it as a Go file to the the given file with the given package name.
// and writes it as a Go file to the given file with the given package name.
func (w *CodeWriter) WriteGoFile(filename, pkg string) {
f, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer f.Close()
if _, err = w.WriteGo(f, pkg); err != nil {
if _, err = w.WriteGo(f, pkg, ""); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteVersionedGoFile appends the buffer with the total size of all created
// structures and writes it as a Go file to the given file with the given
// package name and build tags for the current Unicode version,
func (w *CodeWriter) WriteVersionedGoFile(filename, pkg string) {
tags := buildTags()
if tags != "" {
filename = insertVersion(filename, UnicodeVersion())
}
f, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer f.Close()
if _, err = w.WriteGo(f, pkg, tags); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteGo appends the buffer with the total size of all created structures and
// writes it as a Go file to the the given writer with the given package name.
func (w *CodeWriter) WriteGo(out io.Writer, pkg string) (n int, err error) {
// writes it as a Go file to the given writer with the given package name.
func (w *CodeWriter) WriteGo(out io.Writer, pkg, tags string) (n int, err error) {
sz := w.Size
w.WriteComment("Total table size %d bytes (%dKiB); checksum: %X\n", sz, sz/1024, w.Hash.Sum32())
defer w.buf.Reset()
return WriteGo(out, pkg, w.buf.Bytes())
return WriteGo(out, pkg, tags, w.buf.Bytes())
}
func (w *CodeWriter) printf(f string, x ...interface{}) {
......@@ -181,7 +199,6 @@ func (w *CodeWriter) writeValue(v reflect.Value) {
// WriteString writes a string literal.
func (w *CodeWriter) WriteString(s string) {
s = strings.Replace(s, `\`, `\\`, -1)
io.WriteString(w.Hash, s) // content hash
w.Size += len(s)
......@@ -232,6 +249,9 @@ func (w *CodeWriter) WriteString(s string) {
out = fmt.Sprintf("\\U%08x", r)
}
chars = len(out)
} else if r == '\\' {
out = "\\" + string(r)
chars = 2
}
if n -= chars; n < 0 {
nLines++
......
......@@ -7,7 +7,7 @@
//
// This package defines command line flags that are common to most generation
// tools. The flags allow for specifying specific Unicode and CLDR versions
// in the public Unicode data repository (http://www.unicode.org/Public).
// in the public Unicode data repository (https://www.unicode.org/Public).
//
// A local Unicode data mirror can be set through the flag -local or the
// environment variable UNICODE_DIR. The former takes precedence. The local
......@@ -31,6 +31,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
"sync"
"unicode"
......@@ -39,7 +40,7 @@ import (
var (
url = flag.String("url",
"http://www.unicode.org/Public",
"https://www.unicode.org/Public",
"URL of Unicode database directory")
iana = flag.String("iana",
"http://www.iana.org",
......@@ -69,8 +70,6 @@ func Init() {
const header = `// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package %s
`
// UnicodeVersion reports the requested Unicode version.
......@@ -78,11 +77,33 @@ func UnicodeVersion() string {
return *unicodeVersion
}
// UnicodeVersion reports the requested CLDR version.
// CLDRVersion reports the requested CLDR version.
func CLDRVersion() string {
return *cldrVersion
}
var tags = []struct{ version, buildTags string }{
{"10.0.0", "go1.10"},
{"", "!go1.10"},
}
// buildTags reports the build tags used for the current Unicode version.
func buildTags() string {
v := UnicodeVersion()
for _, x := range tags {
// We should do a numeric comparison, but including the collate package
// would create an import cycle. We approximate it by assuming that
// longer version strings are later.
if len(x.version) <= len(v) {
return x.buildTags
}
if len(x.version) == len(v) && x.version <= v {
return x.buildTags
}
}
return tags[0].buildTags
}
// IsLocal reports whether data files are available locally.
func IsLocal() bool {
dir, err := localReadmeFile()
......@@ -243,15 +264,46 @@ func WriteGoFile(filename, pkg string, b []byte) {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer w.Close()
if _, err = WriteGo(w, pkg, b); err != nil {
if _, err = WriteGo(w, pkg, "", b); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
func insertVersion(filename, version string) string {
suffix := ".go"
if strings.HasSuffix(filename, "_test.go") {
suffix = "_test.go"
}
return fmt.Sprint(filename[:len(filename)-len(suffix)], version, suffix)
}
// WriteVersionedGoFile prepends a standard file comment, adds build tags to
// version the file for the current Unicode version, and package statement to
// the given bytes, applies gofmt, and writes them to a file with the given
// name. It will call log.Fatal if there are any errors.
func WriteVersionedGoFile(filename, pkg string, b []byte) {
tags := buildTags()
if tags != "" {
filename = insertVersion(filename, UnicodeVersion())
}
w, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer w.Close()
if _, err = WriteGo(w, pkg, tags, b); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteGo prepends a standard file comment and package statement to the given
// bytes, applies gofmt, and writes them to w.
func WriteGo(w io.Writer, pkg string, b []byte) (n int, err error) {
src := []byte(fmt.Sprintf(header, pkg))
func WriteGo(w io.Writer, pkg, tags string, b []byte) (n int, err error) {
src := []byte(header)
if tags != "" {
src = append(src, fmt.Sprintf("// +build %s\n\n", tags)...)
}
src = append(src, fmt.Sprintf("package %s\n\n", pkg)...)
src = append(src, b...)
formatted, err := format.Source(src)
if err != nil {
......
......@@ -53,7 +53,7 @@
// Indexes of starter blocks in case of multiple trie roots.
//
// It is recommended that users test the generated trie by checking the returned
// value for every rune. Such exhaustive tests are possible as the the number of
// value for every rune. Such exhaustive tests are possible as the number of
// runes in Unicode is limited.
package triegen // import "golang.org/x/text/internal/triegen"
......
......@@ -3,16 +3,16 @@
// license that can be found in the LICENSE file.
// Package ucd provides a parser for Unicode Character Database files, the
// format of which is defined in http://www.unicode.org/reports/tr44/. See
// http://www.unicode.org/Public/UCD/latest/ucd/ for example files.
// format of which is defined in https://www.unicode.org/reports/tr44/. See
// https://www.unicode.org/Public/UCD/latest/ucd/ for example files.
//
// It currently does not support substitutions of missing fields.
package ucd // import "golang.org/x/text/internal/ucd"
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"log"
"regexp"
......@@ -92,10 +92,11 @@ type Parser struct {
keepRanges bool // Don't expand rune ranges in field 0.
err error
comment []byte
field [][]byte
comment string
field []string
// parsedRange is needed in case Range(0) is called more than once for one
// field. In some cases this requires scanning ahead.
line int
parsedRange bool
rangeStart, rangeEnd rune
......@@ -103,15 +104,19 @@ type Parser struct {
commentHandler func(s string)
}
func (p *Parser) setError(err error) {
if p.err == nil {
p.err = err
func (p *Parser) setError(err error, msg string) {
if p.err == nil && err != nil {
if msg == "" {
p.err = fmt.Errorf("ucd:line:%d: %v", p.line, err)
} else {
p.err = fmt.Errorf("ucd:line:%d:%s: %v", p.line, msg, err)
}
}
}
func (p *Parser) getField(i int) []byte {
func (p *Parser) getField(i int) string {
if i >= len(p.field) {
return nil
return ""
}
return p.field[i]
}
......@@ -139,65 +144,66 @@ func (p *Parser) Next() bool {
p.rangeStart++
return true
}
p.comment = nil
p.comment = ""
p.field = p.field[:0]
p.parsedRange = false
for p.scanner.Scan() {
b := p.scanner.Bytes()
if len(b) == 0 {
for p.scanner.Scan() && p.err == nil {
p.line++
s := p.scanner.Text()
if s == "" {
continue
}
if b[0] == '#' {
if s[0] == '#' {
if p.commentHandler != nil {
p.commentHandler(strings.TrimSpace(string(b[1:])))
p.commentHandler(strings.TrimSpace(s[1:]))
}
continue
}
// Parse line
if i := bytes.IndexByte(b, '#'); i != -1 {
p.comment = bytes.TrimSpace(b[i+1:])
b = b[:i]
if i := strings.IndexByte(s, '#'); i != -1 {
p.comment = strings.TrimSpace(s[i+1:])
s = s[:i]
}
if b[0] == '@' {
if s[0] == '@' {
if p.partHandler != nil {
p.field = append(p.field, bytes.TrimSpace(b[1:]))
p.field = append(p.field, strings.TrimSpace(s[1:]))
p.partHandler(p)
p.field = p.field[:0]
}
p.comment = nil
p.comment = ""
continue
}
for {
i := bytes.IndexByte(b, ';')
i := strings.IndexByte(s, ';')
if i == -1 {
p.field = append(p.field, bytes.TrimSpace(b))
p.field = append(p.field, strings.TrimSpace(s))
break
}
p.field = append(p.field, bytes.TrimSpace(b[:i]))
b = b[i+1:]
p.field = append(p.field, strings.TrimSpace(s[:i]))
s = s[i+1:]
}
if !p.keepRanges {
p.rangeStart, p.rangeEnd = p.getRange(0)
}
return true
}
p.setError(p.scanner.Err())
p.setError(p.scanner.Err(), "scanner failed")
return false
}
func parseRune(b []byte) (rune, error) {
func parseRune(b string) (rune, error) {
if len(b) > 2 && b[0] == 'U' && b[1] == '+' {
b = b[2:]
}
x, err := strconv.ParseUint(string(b), 16, 32)
x, err := strconv.ParseUint(b, 16, 32)
return rune(x), err
}
func (p *Parser) parseRune(b []byte) rune {
x, err := parseRune(b)
p.setError(err)
func (p *Parser) parseRune(s string) rune {
x, err := parseRune(s)
p.setError(err, "failed to parse rune")
return x
}
......@@ -211,13 +217,13 @@ func (p *Parser) Rune(i int) rune {
// Runes interprets and returns field i as a sequence of runes.
func (p *Parser) Runes(i int) (runes []rune) {
add := func(b []byte) {
if b = bytes.TrimSpace(b); len(b) > 0 {
runes = append(runes, p.parseRune(b))
add := func(s string) {
if s = strings.TrimSpace(s); len(s) > 0 {
runes = append(runes, p.parseRune(s))
}
}
for b := p.getField(i); ; {
i := bytes.IndexByte(b, ' ')
i := strings.IndexByte(b, ' ')
if i == -1 {
add(b)
break
......@@ -247,7 +253,7 @@ func (p *Parser) Range(i int) (first, last rune) {
func (p *Parser) getRange(i int) (first, last rune) {
b := p.getField(i)
if k := bytes.Index(b, []byte("..")); k != -1 {
if k := strings.Index(b, ".."); k != -1 {
return p.parseRune(b[:k]), p.parseRune(b[k+2:])
}
// The first field may not be a rune, in which case we may ignore any error
......@@ -260,23 +266,24 @@ func (p *Parser) getRange(i int) (first, last rune) {
p.keepRanges = true
}
// Special case for UnicodeData that was retained for backwards compatibility.
if i == 0 && len(p.field) > 1 && bytes.HasSuffix(p.field[1], []byte("First>")) {
if i == 0 && len(p.field) > 1 && strings.HasSuffix(p.field[1], "First>") {
if p.parsedRange {
return p.rangeStart, p.rangeEnd
}
mf := reRange.FindStringSubmatch(p.scanner.Text())
p.line++
if mf == nil || !p.scanner.Scan() {
p.setError(errIncorrectLegacyRange)
p.setError(errIncorrectLegacyRange, "")
return x, x
}
// Using Bytes would be more efficient here, but Text is a lot easier
// and this is not a frequent case.
ml := reRange.FindStringSubmatch(p.scanner.Text())
if ml == nil || mf[2] != ml[2] || ml[3] != "Last" || mf[4] != ml[4] {
p.setError(errIncorrectLegacyRange)
p.setError(errIncorrectLegacyRange, "")
return x, x
}
p.rangeStart, p.rangeEnd = x, p.parseRune(p.scanner.Bytes()[:len(ml[1])])
p.rangeStart, p.rangeEnd = x, p.parseRune(p.scanner.Text()[:len(ml[1])])
p.parsedRange = true
return p.rangeStart, p.rangeEnd
}
......@@ -298,34 +305,34 @@ var bools = map[string]bool{
// Bool parses and returns field i as a boolean value.
func (p *Parser) Bool(i int) bool {
b := p.getField(i)
f := p.getField(i)
for s, v := range bools {
if bstrEq(b, s) {
if f == s {
return v
}
}
p.setError(strconv.ErrSyntax)
p.setError(strconv.ErrSyntax, "error parsing bool")
return false
}
// Int parses and returns field i as an integer value.
func (p *Parser) Int(i int) int {
x, err := strconv.ParseInt(string(p.getField(i)), 10, 64)
p.setError(err)
p.setError(err, "error parsing int")
return int(x)
}
// Uint parses and returns field i as an unsigned integer value.
func (p *Parser) Uint(i int) uint {
x, err := strconv.ParseUint(string(p.getField(i)), 10, 64)
p.setError(err)
p.setError(err, "error parsing uint")
return uint(x)
}
// Float parses and returns field i as a decimal value.
func (p *Parser) Float(i int) float64 {
x, err := strconv.ParseFloat(string(p.getField(i)), 64)
p.setError(err)
p.setError(err, "error parsing float")
return x
}
......@@ -353,24 +360,12 @@ var errUndefinedEnum = errors.New("ucd: undefined enum value")
// Enum interprets and returns field i as a value that must be one of the values
// in enum.
func (p *Parser) Enum(i int, enum ...string) string {
b := p.getField(i)
f := p.getField(i)
for _, s := range enum {
if bstrEq(b, s) {
if f == s {
return s
}
}
p.setError(errUndefinedEnum)
p.setError(errUndefinedEnum, "error parsing enum")
return ""
}
func bstrEq(b []byte, s string) bool {
if len(b) != len(s) {
return false
}
for i, c := range b {
if c != s[i] {
return false
}
}
return true
}
......@@ -155,6 +155,7 @@ func DirectionString(s string) bidi.Direction {
e, sz := bidi.LookupString(s[i:])
if sz == 0 {
i++
continue
}
c := e.Class()
if c == bidi.R || c == bidi.AL || c == bidi.AN {
......@@ -202,13 +203,6 @@ func (t *Transformer) isRTL() bool {
return t.seen&isRTL != 0
}
func (t *Transformer) isFinal() bool {
if !t.isRTL() {
return true
}
return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
}
// Reset implements transform.Transformer.
func (t *Transformer) Reset() { *t = Transformer{} }
......
......@@ -78,8 +78,8 @@ type SpanningTransformer interface {
// considering the error err.
//
// A nil error means that all input bytes are known to be identical to the
// output produced by the Transformer. A nil error can be be returned
// regardless of whether atEOF is true. If err is nil, then then n must
// output produced by the Transformer. A nil error can be returned
// regardless of whether atEOF is true. If err is nil, then n must
// equal len(src); the converse is not necessarily true.
//
// ErrEndOfSpan means that the Transformer output may differ from the
......
......@@ -6,7 +6,7 @@
// Package bidi contains functionality for bidirectional text support.
//
// See http://www.unicode.org/reports/tr9.
// See https://www.unicode.org/reports/tr9.
//
// NOTE: UNDER CONSTRUCTION. This API may change in backwards incompatible ways
// and without notice.
......
......@@ -12,7 +12,7 @@ import (
// This file contains a port of the reference implementation of the
// Bidi Parentheses Algorithm:
// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/BidiPBAReference.java
// https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/BidiPBAReference.java
//
// The implementation in this file covers definitions BD14-BD16 and rule N0
// of UAX#9.
......@@ -246,7 +246,7 @@ func (p *bracketPairer) getStrongTypeN0(index int) Class {
// assuming the given embedding direction.
//
// It returns ON if no strong type is found. If a single strong type is found,
// it returns this this type. Otherwise it returns the embedding direction.
// it returns this type. Otherwise it returns the embedding direction.
//
// TODO: use separate type for "strong" directionality.
func (p *bracketPairer) classifyPairContent(loc bracketPair, dirEmbed Class) Class {
......
......@@ -7,7 +7,7 @@ package bidi
import "log"
// This implementation is a port based on the reference implementation found at:
// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/
// https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/
//
// described in Unicode Bidirectional Algorithm (UAX #9).
//
......
......@@ -26,7 +26,7 @@ func main() {
}
// bidiClass names and codes taken from class "bc" in
// http://www.unicode.org/Public/8.0.0/ucd/PropertyValueAliases.txt
// https://www.unicode.org/Public/8.0.0/ucd/PropertyValueAliases.txt
var bidiClass = map[string]Class{
"AL": AL, // ArabicLetter
"AN": AN, // ArabicNumber
......@@ -59,7 +59,7 @@ func genTables() {
log.Fatalf("Too many Class constants (%#x > 0x0F).", numClass)
}
w := gen.NewCodeWriter()
defer w.WriteGoFile(*outputFile, "bidi")
defer w.WriteVersionedGoFile(*outputFile, "bidi")
gen.WriteUnicodeVersion(w)
......
......@@ -15,7 +15,7 @@ import (
)
// These tables are hand-extracted from:
// http://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedBidiClass.txt
// https://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedBidiClass.txt
func visitDefaults(fn func(r rune, c Class)) {
// first write default values for ranges listed above.
visitRunes(fn, AL, []rune{
......
......@@ -62,6 +62,11 @@ func (e *Common) Default() string {
return ""
}
// Element returns the XML element name.
func (e *Common) Element() string {
return e.name
}
// GetCommon returns e. It is provided such that Common implements Elem.
func (e *Common) GetCommon() *Common {
return e
......
......@@ -5,14 +5,15 @@
//go:generate go run makexml.go -output xml.go
// Package cldr provides a parser for LDML and related XML formats.
// This package is intended to be used by the table generation tools
// for the various internationalization-related packages.
// As the XML types are generated from the CLDR DTD, and as the CLDR standard
// is periodically amended, this package may change considerably over time.
// This mostly means that data may appear and disappear between versions.
// That is, old code should keep compiling for newer versions, but data
// may have moved or changed.
// CLDR version 22 is the first version supported by this package.
//
// This package is intended to be used by the table generation tools for the
// various packages in x/text and is not internal for historical reasons.
//
// As the XML types are generated from the CLDR DTD, and as the CLDR standard is
// periodically amended, this package may change considerably over time. This
// mostly means that data may appear and disappear between versions. That is,
// old code should keep compiling for newer versions, but data may have moved or
// changed. CLDR version 22 is the first version supported by this package.
// Older versions may not work.
package cldr // import "golang.org/x/text/unicode/cldr"
......@@ -94,6 +95,12 @@ func (cldr *CLDR) RawLDML(loc string) *LDML {
// LDML returns the fully resolved LDML XML for loc, which must be one of
// the strings returned by Locales.
//
// Deprecated: use RawLDML and implement inheritance manually or using the
// internal cldrtree package.
// Inheritance has changed quite a bit since the onset of this package and in
// practice data often represented in a way where knowledge of how it was
// inherited is relevant.
func (cldr *CLDR) LDML(loc string) (*LDML, error) {
return cldr.resolve(loc)
}
......
......@@ -27,7 +27,7 @@ const (
// cldrIndex is a Unicode-reserved sentinel value used to mark the start
// of a grouping within an index.
// We ignore any rule that starts with this rune.
// See http://unicode.org/reports/tr35/#Collation_Elements for details.
// See https://unicode.org/reports/tr35/#Collation_Elements for details.
cldrIndex = "\uFDD0"
// specialAnchor is the format in which to represent logical reset positions,
......@@ -51,7 +51,7 @@ func (c Collation) Process(p RuleProcessor) (err error) {
}
// processRules parses rules in the Collation Rule Syntax defined in
// http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Tailorings.
// https://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Tailorings.
func processRules(p RuleProcessor, s string) (err error) {
chk := func(s string, e error) string {
if err == nil {
......
......@@ -47,7 +47,7 @@ type Loader interface {
Reader(i int) (io.ReadCloser, error)
}
var fileRe = regexp.MustCompile(".*/(.*)/(.*)\\.xml")
var fileRe = regexp.MustCompile(`.*[/\\](.*)[/\\](.*)\.xml`)
// Decode loads and decodes the files represented by l.
func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) {
......@@ -58,9 +58,10 @@ func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) {
if len(d.dirFilter) > 0 && !in(d.dirFilter, m[1]) {
continue
}
var r io.Reader
var r io.ReadCloser
if r, err = l.Reader(i); err == nil {
err = d.decode(m[1], m[2], r)
r.Close()
}
if err != nil {
return nil, err
......@@ -100,7 +101,7 @@ func (d *Decoder) decode(dir, id string, r io.Reader) error {
if l.Identity == nil {
return fmt.Errorf("%s/%s: missing identity element", dir, id)
}
// TODO: verify when CLDR bug http://unicode.org/cldr/trac/ticket/8970
// TODO: verify when CLDR bug https://unicode.org/cldr/trac/ticket/8970
// is resolved.
// path := strings.Split(id, "_")
// if lang := l.Identity.Language.Type; lang != path[0] {
......
......@@ -153,7 +153,7 @@ var comments = map[string]string{
// Dates contains information regarding the format and parsing of dates and times.
`,
"localeDisplayNames": `
// LocaleDisplayNames specifies localized display names for for scripts, languages,
// LocaleDisplayNames specifies localized display names for scripts, languages,
// countries, currencies, and variants.
`,
"numbers": `
......
......@@ -5,7 +5,7 @@
package cldr
// This file implements the various inheritance constructs defined by LDML.
// See http://www.unicode.org/reports/tr35/#Inheritance_and_Validity
// See https://www.unicode.org/reports/tr35/#Inheritance_and_Validity
// for more details.
import (
......@@ -309,7 +309,7 @@ func in(set []string, s string) bool {
}
// attrKey computes a key based on the distinguishable attributes of
// an element and it's values.
// an element and its values.
func attrKey(v reflect.Value, exclude ...string) string {
parts := []string{}
ename := v.Interface().(Elem).GetCommon().name
......
......@@ -636,6 +636,13 @@ type SupplementalData struct {
Path string `xml:"path,attr"`
} `xml:"rgPath"`
} `xml:"rgScope"`
LanguageGroups *struct {
Common
LanguageGroup []*struct {
Common
Parent string `xml:"parent,attr"`
} `xml:"languageGroup"`
} `xml:"languageGroups"`
}
// LDML is the top-level type for locale-specific data.
......@@ -1230,7 +1237,7 @@ type TimeZoneNames struct {
} `xml:"metazone"`
}
// LocaleDisplayNames specifies localized display names for for scripts, languages,
// LocaleDisplayNames specifies localized display names for scripts, languages,
// countries, currencies, and variants.
type LocaleDisplayNames struct {
Common
......@@ -1484,4 +1491,4 @@ type Numbers struct {
}
// Version is the version of CLDR from which the XML definitions are generated.
const Version = "31"
const Version = "32"
......@@ -407,7 +407,7 @@ func decomposeHangul(buf []byte, r rune) int {
// decomposeHangul algorithmically decomposes a Hangul rune into
// its Jamo components.
// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
// See https://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
func (rb *reorderBuffer) decomposeHangul(r rune) {
r -= hangulBase
x := r % jamoTCount
......@@ -420,7 +420,7 @@ func (rb *reorderBuffer) decomposeHangul(r rune) {
}
// combineHangul algorithmically combines Jamo character components into Hangul.
// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
// See https://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
func (rb *reorderBuffer) combineHangul(s, i, k int) {
b := rb.rune[:]
bn := rb.nrune
......@@ -461,6 +461,10 @@ func (rb *reorderBuffer) combineHangul(s, i, k int) {
// It should only be used to recompose a single segment, as it will not
// handle alternations between Hangul and non-Hangul characters correctly.
func (rb *reorderBuffer) compose() {
// Lazily load the map used by the combine func below, but do
// it outside of the loop.
recompMapOnce.Do(buildRecompMap)
// UAX #15, section X5 , including Corrigendum #5
// "In any character sequence beginning with starter S, a character C is
// blocked from S if and only if there is some character B between S
......
......@@ -4,6 +4,8 @@
package norm
import "encoding/binary"
// This file contains Form-specific logic and wrappers for data in tables.go.
// Rune info is stored in a separate trie per composing form. A composing form
......@@ -178,6 +180,17 @@ func (p Properties) TrailCCC() uint8 {
return ccc[p.tccc]
}
func buildRecompMap() {
recompMap = make(map[uint32]rune, len(recompMapPacked)/8)
var buf [8]byte
for i := 0; i < len(recompMapPacked); i += 8 {
copy(buf[:], recompMapPacked[i:i+8])
key := binary.BigEndian.Uint32(buf[:4])
val := binary.BigEndian.Uint32(buf[4:])
recompMap[key] = rune(val)
}
}
// Recomposition
// We use 32-bit keys instead of 64-bit for the two codepoint keys.
// This clips off the bits of three entries, but we know this will not
......@@ -186,8 +199,14 @@ func (p Properties) TrailCCC() uint8 {
// Note that the recomposition map for NFC and NFKC are identical.
// combine returns the combined rune or 0 if it doesn't exist.
//
// The caller is responsible for calling
// recompMapOnce.Do(buildRecompMap) sometime before this is called.
func combine(a, b rune) rune {
key := uint32(uint16(a))<<16 + uint32(uint16(b))
if recompMap == nil {
panic("caller error") // see func comment
}
return recompMap[key]
}
......
......@@ -128,8 +128,9 @@ func (i *Iter) Next() []byte {
func nextASCIIBytes(i *Iter) []byte {
p := i.p + 1
if p >= i.rb.nsrc {
p0 := i.p
i.setDone()
return i.rb.src.bytes[i.p:p]
return i.rb.src.bytes[p0:p]
}
if i.rb.src.bytes[p] < utf8.RuneSelf {
p0 := i.p
......
......@@ -12,6 +12,7 @@ package main
import (
"bytes"
"encoding/binary"
"flag"
"fmt"
"io"
......@@ -261,7 +262,7 @@ func compactCCC() {
// CompositionExclusions.txt has form:
// 0958 # ...
// See http://unicode.org/reports/tr44/ for full explanation
// See https://unicode.org/reports/tr44/ for full explanation
func loadCompositionExclusions() {
f := gen.OpenUCDFile("CompositionExclusions.txt")
defer f.Close()
......@@ -735,6 +736,8 @@ func makeTables() {
max = n
}
}
fmt.Fprintln(w, `import "sync"`)
fmt.Fprintln(w)
fmt.Fprintln(w, "const (")
fmt.Fprintln(w, "\t// Version is the Unicode edition from which the tables are derived.")
......@@ -782,20 +785,27 @@ func makeTables() {
sz := nrentries * 8
size += sz
fmt.Fprintf(w, "// recompMap: %d bytes (entries only)\n", sz)
fmt.Fprintln(w, "var recompMap = map[uint32]rune{")
fmt.Fprintln(w, "var recompMap map[uint32]rune")
fmt.Fprintln(w, "var recompMapOnce sync.Once\n")
fmt.Fprintln(w, `const recompMapPacked = "" +`)
var buf [8]byte
for i, c := range chars {
f := c.forms[FCanonical]
d := f.decomp
if !f.isOneWay && len(d) > 0 {
key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1]))
fmt.Fprintf(w, "0x%.8X: 0x%.4X,\n", key, i)
binary.BigEndian.PutUint32(buf[:4], key)
binary.BigEndian.PutUint32(buf[4:], uint32(i))
fmt.Fprintf(w, "\t\t%q + // 0x%.8X: 0x%.8X\n", string(buf[:]), key, uint32(i))
}
}
fmt.Fprintf(w, "}\n\n")
// hack so we don't have to special case the trailing plus sign
fmt.Fprintf(w, ` ""`)
fmt.Fprintln(w)
}
fmt.Fprintf(w, "// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size)
gen.WriteGoFile("tables.go", "norm", w.Bytes())
gen.WriteVersionedGoFile("tables.go", "norm", w.Bytes())
}
func printChars() {
......@@ -857,7 +867,7 @@ func verifyComputed() {
// DerivedNormalizationProps.txt has form:
// 00C0..00C5 ; NFD_QC; N # ...
// 0374 ; NFD_QC; N # ...
// See http://unicode.org/reports/tr44/ for full explanation
// See https://unicode.org/reports/tr44/ for full explanation
func testDerived() {
f := gen.OpenUCDFile("DerivedNormalizationProps.txt")
defer f.Close()
......@@ -972,5 +982,5 @@ func printTestdata() {
}
}
fmt.Fprintln(w, "}")
gen.WriteGoFile("data_test.go", "norm", w.Bytes())
gen.WriteVersionedGoFile("data_test.go", "norm", w.Bytes())
}
......@@ -29,8 +29,8 @@ import (
// proceed independently on both sides:
// f(x) == append(f(x[0:n]), f(x[n:])...)
//
// References: http://unicode.org/reports/tr15/ and
// http://unicode.org/notes/tn5/.
// References: https://unicode.org/reports/tr15/ and
// https://unicode.org/notes/tn5/.
type Form int
const (
......
......@@ -60,8 +60,8 @@ func (w *normWriter) Close() error {
}
// Writer returns a new writer that implements Write(b)
// by writing f(b) to w. The returned writer may use an
// an internal buffer to maintain state across Write calls.
// by writing f(b) to w. The returned writer may use an
// internal buffer to maintain state across Write calls.
// Calling its Close method writes any buffered data to w.
func (f Form) Writer(w io.Writer) io.WriteCloser {
wr := &normWriter{rb: reorderBuffer{}, w: w}
......
......@@ -18,7 +18,6 @@ func (Form) Reset() {}
// Users should either catch ErrShortDst and allow dst to grow or have dst be at
// least of size MaxTransformChunkSize to be guaranteed of progress.
func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
n := 0
// Cap the maximum number of src bytes to check.
b := src
eof := atEOF
......@@ -27,20 +26,21 @@ func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
eof = false
b = b[:ns]
}
i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof)
n += copy(dst[n:], b[n:i])
i, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), eof)
n := copy(dst, b[:i])
if !ok {
nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
return nDst + n, nSrc + n, err
}
if n < len(src) && !atEOF {
if err == nil && n < len(src) && !atEOF {
err = transform.ErrShortSrc
}
return n, n, err
}
func flushTransform(rb *reorderBuffer) bool {
// Write out (must fully fit in dst, or else it is a ErrShortDst).
// Write out (must fully fit in dst, or else it is an ErrShortDst).
if len(rb.out) < rb.nrune*utf8.UTFMax {
return false
}
......@@ -79,7 +79,7 @@ func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
nSrc += n
nDst += n
if ok {
if n < rb.nsrc && !atEOF {
if err == nil && n < rb.nsrc && !atEOF {
err = transform.ErrShortSrc
}
return nDst, nSrc, err
......
......@@ -13,12 +13,13 @@ import (
"io"
"log"
"reflect"
"sort"
"strings"
"unicode"
"golang.org/x/text/collate"
"golang.org/x/text/internal/gen"
"golang.org/x/text/internal/ucd"
"golang.org/x/text/language"
"golang.org/x/text/unicode/rangetable"
)
......@@ -30,15 +31,16 @@ To bootstrap the code generation, run:
go run gen.go --versions=4.1.0,5.0.0,6.0.0,6.1.0,6.2.0,6.3.0,7.0.0
and ensure that the latest versions are included by checking:
http://www.unicode.org/Public/`
https://www.unicode.org/Public/`
func getVersions() []string {
if *versionList == "" {
log.Fatal(bootstrapMessage)
}
c := collate.New(language.Und, collate.Numeric)
versions := strings.Split(*versionList, ",")
sort.Strings(versions)
c.SortStrings(versions)
// Ensure that at least the current version is included.
for _, v := range versions {
......@@ -48,7 +50,7 @@ func getVersions() []string {
}
versions = append(versions, gen.UnicodeVersion())
sort.Strings(versions)
c.SortStrings(versions)
return versions
}
......@@ -74,7 +76,7 @@ func main() {
for _, v := range versions {
assigned := []rune{}
r := gen.Open("http://www.unicode.org/Public/", "", v+"/ucd/UnicodeData.txt")
r := gen.Open("https://www.unicode.org/Public/", "", v+"/ucd/UnicodeData.txt")
ucd.Parse(r, func(p *ucd.Parser) {
assigned = append(assigned, p.Rune(0))
})
......@@ -93,7 +95,7 @@ func main() {
fmt.Fprintf(w, "// Total size %d bytes (%d KiB)\n", size, size/1024)
gen.WriteGoFile("tables.go", "rangetable", w.Bytes())
gen.WriteVersionedGoFile("tables.go", "rangetable", w.Bytes())
}
func print(w io.Writer, rt *unicode.RangeTable) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册