<commit_before>package gce

import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/cockroachdb/roachprod/config"
	"github.com/cockroachdb/roachprod/vm"
	"github.com/pkg/errors"
	"github.com/spf13/pflag"
	"golang.org/x/sync/errgroup"
)

const (
	project      = "cockroach-ephemeral"
	ProviderName = "gce"
)

// init will inject the GCE provider into vm.Providers, but only if the gcloud tool is available on the local path.
func init() {
	if _, err := exec.LookPath("gcloud"); err == nil {
		vm.Providers[ProviderName] = &Provider{}
	} else {
		log.Printf("please install the gcloud CLI utilities (https://cloud.google.com/sdk/downloads)")
	}
}

func runJSONCommand(args []string, parsed interface{}) error {
	cmd := exec.Command("gcloud", args...)

	rawJSON, err := cmd.Output()
	if err != nil {
		return errors.Wrapf(err, "failed to run: gcloud %s", strings.Join(args, " "))
	}

	if err := json.Unmarshal(rawJSON, &parsed); err != nil {
		return errors.Wrapf(err, "failed to parse json %s", rawJSON)
	}

	return nil
}

// Used to parse the gcloud responses
type jsonVM struct {
	Name              string
	Labels            map[string]string
	CreationTimestamp time.Time
	NetworkInterfaces []struct {
		Network       string
		NetworkIP     string
		AccessConfigs []struct {
			Name  string
			NatIP string
		}
	}
	Zone string<commit_msg>gce: show stdout/stderr when gcloud fails<commit_after>package gce

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/cockroachdb/roachprod/config"
	"github.com/cockroachdb/roachprod/vm"
	"github.com/pkg/errors"
	"github.com/spf13/pflag"
	"golang.org/x/sync/errgroup"
)

const (
	project      = "cockroach-ephemeral"
	ProviderName = "gce"
)

// init will inject the GCE provider into vm.Providers, but only if the gcloud tool is available on the local path.
func init() {
	if _, err := exec.LookPath("gcloud"); err == nil {
		vm.Providers[ProviderName] = &Provider{}
	} else {
		log.Printf("please install the gcloud CLI utilities (https://cloud.google.com/sdk/downloads)")
	}
}

func runJSONCommand(args []string, parsed interface{}) error {
	cmd := exec.Command("gcloud", args...)

	rawJSON, err := cmd.Output()
	if err != nil {
		var stderr []byte
		if exitErr, ok := err.(*exec.ExitError); ok {
			stderr = exitErr.Stderr
		}
		return errors.Errorf("failed to run: gcloud %s: %s\nstdout: %s\nstderr: %s",
			strings.Join(args, " "), err, bytes.TrimSpace(rawJSON), bytes.TrimSpace(stderr))
	}

	if err := json.Unmarshal(rawJSON, &parsed); err != nil {
		return errors.Wrapf(err, "failed to parse json %s", rawJSON)
	}

	return nil
}

// Used to parse the gcloud responses
type jsonVM struct {
	Name              string
	Labels            map[string]string
	CreationTimestamp time.Time
	NetworkInterfaces []struct {
		Network       string
		NetworkIP     string
		AccessConfigs []struct {
			Name  string
			NatIP string
		}
	}
	Zone string
{'fraction_non_alphanumeric': 0.1352802954011413, 'fraction_numerical': 0.001342732460557234, 'mean_word_length': 3.481203007518797, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4846119', 'n_tokens_mistral': 1107, 'n_tokens_neox': 1051, 'n_words': 272}