<commit_before>package stack

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"github.com/appcelerator/amp/data/accounts"
	"github.com/appcelerator/amp/data/stacks"
	"github.com/appcelerator/amp/pkg/docker/docker/stack"
	"github.com/docker/docker/cli/command"
	cliflags "github.com/docker/docker/cli/flags"
	"golang.org/x/net/context"
)

// Server is used to implement stack.StackServer
type Server struct {
	Accounts accounts.Interface
	Stacks   stacks.Interface
}

// Deploy implements stack.Server
func (s *Server) Deploy(ctx context.Context, in *DeployRequest) (*DeployReply, error) {
	log.Println("[stack] Deploy", in.String())

	r, w, _ := os.Pipe()
	dockerCli := command.NewDockerCli(os.Stdin, w, w)
	opts := cliflags.NewClientOptions()
	if err := dockerCli.Initialize(opts); err != nil {
		return nil, grpc.Errorf(codes.Internal, "%v", fmt.Errorf("error in cli initialize: %v", err))
	}
	fileName := fmt.Sprintf("/tmp/%d-%s.yml", time.Now().UnixNano(), in.Name)
	if err := ioutil.WriteFile(fileName, []byte(in.Compose), 0666); err != nil {
		return nil, grpc.Errorf(codes.Internal, "%v", err)
	}

	fullName, err := s.getStackInst(ctx, in.Name)
	if err != nil {
		return nil, grpc.Errorf(codes.Internal, "%v", err)
	}
	deployOpt := stack.NewDeployOptions(fullName, fileName, true)
	if err := stack.RunDeploy(dockerCli, deployOpt); err != nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "%v", err)
	}
	w.Close()
	out, _ := ioutil.ReadAll(r)
	outs := strings.Replace(string(out), "docker", "amp", -1)
	ans := &DeployReply{
		FullName: fullName,
		Answer:   string(outs),
	}
	return ans, nil
}

// verify if stack id alreaday exist, if yes, it's an update, if not create a new stack data entry
func (s *Server) getStackInst(ctx context.Context, name string) (string, error) {
	if stackInst, err := s.Stacks.GetStack(ctx, name); err == nil && stackInst != nil {
		return fmt.Sprintf("%s-%s", stackInst.Name, stackInst.Id), nil
	}
	ids := strings.Split(name, "-")
	id := ids[len(ids)-1]
	if stackInst, err := s.Stacks.GetStack(ctx, id); err == nil && stackInst != nil {
		return name, nil
	}
	stackInst, err := s.Stacks.CreateStack(ctx, name)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s-%s", stackInst.Name, stackInst.Id), nil
}
<commit_msg>fix stack deploy issue 1041<commit_after>package stack

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"github.com/appcelerator/amp/data/accounts"
	"github.com/appcelerator/amp/data/stacks"
	"github.com/appcelerator/amp/pkg/docker/docker/stack"
	"github.com/docker/docker/cli/command"
	cliflags "github.com/docker/docker/cli/flags"
	"golang.org/x/net/context"
)

// Server is used to implement stack.StackServer
type Server struct {
	Accounts accounts.Interface
	Stacks   stacks.Interface
}

// Deploy implements stack.Server
func (s *Server) Deploy(ctx context.Context, in *DeployRequest) (*DeployReply, error) {
	log.Println("[stack] Deploy", in.String())

	r, w, _ := os.Pipe()
	dockerCli := command.NewDockerCli(os.Stdin, w, w)
	opts := cliflags.NewClientOptions()
	if err := dockerCli.Initialize(opts); err != nil {
		return nil, grpc.Errorf(codes.Internal, "%v", fmt.Errorf("error in cli initialize: %v", err))
	}
	fileName := fmt.Sprintf("/tmp/%d-%s.yml", time.Now().UnixNano(), in.Name)
	if err := ioutil.WriteFile(fileName, []byte(in.Compose), 0666); err != nil {
		return nil, grpc.Errorf(codes.Internal, "%v", err)
	}

	fullName, id, isCreated, err := s.getStackInst(ctx, in.Name)
	if err != nil {
		return nil, grpc.Errorf(codes.Internal, "%v", err)
	}
	deployOpt := stack.NewDeployOptions(fullName, fileName, true)
	if err := stack.RunDeploy(dockerCli, deployOpt); err != nil {
		if isCreated {
			s.Stacks.DeleteStack(ctx, id)
		}
		return nil, grpc.Errorf(codes.InvalidArgument, "%v", err)
	}
	w.Close()
	out, _ := ioutil.ReadAll(r)
	outs := strings.Replace(string(out), "docker", "amp", -1)
	ans := &DeployReply{
		FullName: fullName,
		Answer:   string(outs),
	}
	return ans, nil
}

// verify if stack id alreaday exist, if yes, it's an update, if not create a new stack data entry
func (s *Server) getStackInst(ctx context.Context, name string) (string, string, bool, error) {
	if stackInst, err := s.Stacks.GetStack(ctx, name); err == nil && stackInst != nil {
		return fmt.Sprintf("%s-%s", stackInst.Name, stackInst.Id), stackInst.Id, false, nil
	}
	ids := strings.Split(name, "-")
	id := ids[len(ids)-1]
	if stackInst, err := s.Stacks.GetStack(ctx, id); err == nil && stackInst != nil {
		return name, id, false, nil
	}
	stackInst, err := s.Stacks.CreateStack(ctx, name)
	if err != nil {
		return "", "", false, err
	}
	return fmt.Sprintf("%s-%s", stackInst.Name, stackInst.Id), stackInst.Id, true, nil
}

{'fraction_non_alphanumeric': 0.16997108632796365, 'fraction_numerical': 0.003304419661296985, 'mean_word_length': 4.31030701754386, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3911195', 'n_tokens_mistral': 1878, 'n_tokens_neox': 1804, 'n_words': 423}