<commit_before>// Package new generates micro service templates
package new

import (
	"errors"
	"fmt"
	"go/build"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
	"time"

	"github.com/micro/cli/v2"
	tmpl "github.com/micro/micro/v2/internal/template"
	"github.com/micro/micro/v2/internal/usage"
	"github.com/xlab/treeprint"
)

func protoComments(goDir, alias string) []string {
	return []string{
		"\ndownload protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:\n",
		"visit https://github.com/protocolbuffers/protobuf/releases",
		"\ndownload protobuf for micro:\n",
		"go get -u github.com/golang/protobuf/proto",
		"go get -u github.com/golang/protobuf/protoc-gen-go",
		"go get github.com/micro/micro/v2/cmd/protoc-gen-micro",
		"\ncompile the proto file " + alias + ".proto:\n",
		"cd " + goDir,
		"make proto\n",
	}
}

type config struct {
	// foo
	Alias string
	// micro new example -type
	Command string
	// go.micro
	Namespace string
	// api, service, web, function
	Type string
	// go.micro.service.foo
	FQDN string
	// github.com/micro/foo
	Dir string
	// $GOPATH/src/github.com/micro/foo
	GoDir string
	// $GOPATH
	GoPath string
	// UseGoPath
	UseGoPath bool
	// Files
	Files []file
	// Comments
	Comments []string
	// Plugins registry=etcd:broker=nats
	Plugins []string
}

type file struct {
	Path string
	Tmpl string
}

func write(c config, file, tmpl string) error {
	fn := template.FuncMap{
		"title": strings.Title,
	}

	f, err := os.Create(file)
	if err != nil {
		return err
	}
	defer f.Close()

	t, err := template.New("f").Funcs(fn).Parse(tmpl)
	if err != nil {
		return err
	}

	return t.Execute(f, c)
}

func create(c config) error {
	// check if dir exists
	if _, err := os.Stat(c.GoDir); !os.IsNotExist(err) {
		return fmt.Errorf("%s already exists", c.GoDir)
	}

	// create usage report
	u := usage.New("new")
	// a single request/service
	u.Metrics.Count["requests"] = uint64(1)
	u.Metrics.Count["services"] = uint64(1)
	// send report
	go usage.Report(u)

	// just wait
	<-time.After(time.Millisecond * 250)

	fmt.Printf("Creating service %s in %s\n\n", c.FQDN, c.GoDir)

	t := treeprint.New()

	// write the files
	for _, file := range c.Files {
		f := filepath.Join(c.GoDir, file.Path)
		dir := filepath.Dir(f)

		if _, err := os.Stat(dir); os.IsNotExist(err) {
			if err := os.MkdirAll(dir, 0755); err != nil {
				return err
			}
		}

		addFileToTree(t, file.Path)
		if err := write(c, f, file.Tmpl); err != nil {
			return err
		}
	}

	dst, err := copyAPIProto(c)
	if err != nil {
		return err
	}
	addFileToTree(t, dst)
	// print tree
	fmt.Println(t.String())

	for _, comment := range c.Comments {
		fmt.Println(comment)
	}

	// just wait
	<-time.After(time.Millisecond * 250)

	return nil
}

func copyAPIProto(c config) (string, error) {
	// Find and copy the api proto from go-micro located *somewhere* on local machine.
	// Required because proto can't do imports from random places on the internet like github.com,
	// needs to be somewhere local. Let's try and find it from go mod. This doesn't work if micro
	// wasn't built on the user's machine
	basedir := build.Default.GOPATH

	contents, err := ioutil.ReadDir(filepath.Join(basedir, "pkg", "mod", "github.com", "micro", "go-micro"))
	if err != nil {
		return "", errors.New("Unable to find go-micro version. Please try `go get github.com/micro/go-micro/v2`")
	}
	newestDir := ""<commit_msg>dont copy proto for non api projects (#966)<commit_after>// Package new generates micro service templates
package new

import (
	"errors"
	"fmt"
	"go/build"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
	"time"

	"github.com/micro/cli/v2"
	tmpl "github.com/micro/micro/v2/internal/template"
	"github.com/micro/micro/v2/internal/usage"
	"github.com/xlab/treeprint"
)

func protoComments(goDir, alias string) []string {
	return []string{
		"\ndownload protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:\n",
		"visit https://github.com/protocolbuffers/protobuf/releases",
		"\ndownload protobuf for micro:\n",
		"go get -u github.com/golang/protobuf/proto",
		"go get -u github.com/golang/protobuf/protoc-gen-go",
		"go get github.com/micro/micro/v2/cmd/protoc-gen-micro",
		"\ncompile the proto file " + alias + ".proto:\n",
		"cd " + goDir,
		"make proto\n",
	}
}

type config struct {
	// foo
	Alias string
	// micro new example -type
	Command string
	// go.micro
	Namespace string
	// api, service, web, function
	Type string
	// go.micro.service.foo
	FQDN string
	// github.com/micro/foo
	Dir string
	// $GOPATH/src/github.com/micro/foo
	GoDir string
	// $GOPATH
	GoPath string
	// UseGoPath
	UseGoPath bool
	// Files
	Files []file
	// Comments
	Comments []string
	// Plugins registry=etcd:broker=nats
	Plugins []string
}

type file struct {
	Path string
	Tmpl string
}

func write(c config, file, tmpl string) error {
	fn := template.FuncMap{
		"title": strings.Title,
	}

	f, err := os.Create(file)
	if err != nil {
		return err
	}
	defer f.Close()

	t, err := template.New("f").Funcs(fn).Parse(tmpl)
	if err != nil {
		return err
	}

	return t.Execute(f, c)
}

func create(c config) error {
	// check if dir exists
	if _, err := os.Stat(c.GoDir); !os.IsNotExist(err) {
		return fmt.Errorf("%s already exists", c.GoDir)
	}

	// create usage report
	u := usage.New("new")
	// a single request/service
	u.Metrics.Count["requests"] = uint64(1)
	u.Metrics.Count["services"] = uint64(1)
	// send report
	go usage.Report(u)

	// just wait
	<-time.After(time.Millisecond * 250)

	fmt.Printf("Creating service %s in %s\n\n", c.FQDN, c.GoDir)

	t := treeprint.New()

	// write the files
	for _, file := range c.Files {
		f := filepath.Join(c.GoDir, file.Path)
		dir := filepath.Dir(f)

		if _, err := os.Stat(dir); os.IsNotExist(err) {
			if err := os.MkdirAll(dir, 0755); err != nil {
				return err
			}
		}

		addFileToTree(t, file.Path)
		if err := write(c, f, file.Tmpl); err != nil {
			return err
		}
	}

	if c.Type == "api" {
		dst, err := copyAPIProto(c)
		if err != nil {
			return err
		}
		addFileToTree(t, dst)

	}
	// print tree
	fmt.Println(t.String())

	for _, comment := range c.Comments {
		fmt.Println(comment)
	}

	// just wait
	<-time.After(time.Millisecond * 250)

	return nil
}

func copyAPIProto(c config) (string, error) {
	// Find and copy the api proto from go-micro located *somewhere* on local machine.
	// Required because proto can't do imports from random places on the internet like github.com,
	// needs to be somewhere local. Let's try and find it from go mod. This doesn't work if micro
	// wasn't built on the user's machine
	basedir := build.Default.GOPATH

	contents, err := ioutil.ReadDir(filepath.Join(basedir, "pkg", "mod", "github.com", "micro", "go-micro"))
	if err != nil {
		return "", errors.New("Unable to find go-micro version. Please try `go get github.com/micro/go-micro/v2`")
	}
	newestDir := ""
{'fraction_non_alphanumeric': 0.15277978339350182, 'fraction_numerical': 0.006498194945848376, 'mean_word_length': 3.2991930477963995, 'pattern_counts': {'":': 2, '<': 7, '<?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': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7110338', 'n_tokens_mistral': 2788, 'n_tokens_neox': 2576, 'n_words': 686}