<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"

	_ "github.com/apex/apex/runtime/golang"
	_ "github.com/apex/apex/runtime/nodejs"
	_ "github.com/apex/apex/runtime/python"

	"github.com/apex/apex/dryrun"
	"github.com/apex/apex/function"
	"github.com/apex/apex/logs"
	"github.com/apex/apex/project"
	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/segmentio/go-prompt"
	"github.com/tj/docopt"
)

var version = "0.3.0"

const usage = `
  Usage:
    apex deploy [options] [<name>...] [--env name=val]...
    apex delete [options] [<name>...]
    apex invoke [options] <name> [--async] [-v]
    apex rollback [options] <name> [<version>]
    apex logs [options] <name> [--filter pattern]
    apex build [options] <name>
    apex list [options]
    apex -h | --help
    apex --version

  Options:
    -e, --env name=val      Environment variable
    -D, --dry-run           Perform a dry-run
    -F, --filter pattern    Filter logs with pattern [default: ]
    -l, --log-level level   Log severity level [default: info]
    -a, --async             Async invocation
    -C, --chdir path        Working directory
    -y, --yes               Automatic yes to prompts
    -h, --help              Output help information
    -v, --verbose           Output verbose logs
    -V, --version           Output version

  Examples:
    Deploy all functions
    $ apex deploy

    Deploy specific functions
    $ apex deploy foo bar

    Delete all functions
    $ apex delete

    Delete specified functions
    $ apex delete foo bar

    Invoke a function with input json
    $ apex invoke foo < request.json

    Rollback a function to the previous version
    $ apex rollback foo

    Rollback a function to the specified version
    $ apex rollback bar 3

    Deploy functions in a different project
    $ apex deploy -C ~/dev/myapp

    Build zip output for a function
    $ apex build foo > /tmp/out.zip
`

func main() {
	args, err := docopt.Parse(usage, nil, true, version, false)
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	log.SetHandler(cli.Default)

	if l, err := log.ParseLevel(args["--log-level"].(string)); err == nil {
		log.SetLevel(l)
	}

	session := session.New(aws.NewConfig())

	project := &project.Project{
		Log:  log.Log,
		Path: ".",
	}

	if args["--dry-run"].(bool) {
		log.SetLevel(log.WarnLevel)
		project.Service = dryrun.New(session)
		project.Concurrency = 1
	} else {
		project.Service = lambda.New(session)
	}

	if dir, ok := args["--chdir"].(string); ok {
		if err := os.Chdir(dir); err != nil {
			log.Fatalf("error: %s", err)
		}
	}

	if err := project.Open(); err != nil {
		log.Fatalf("error opening project: %s", err)
	}

	switch {
	case args["list"].(bool):
		list(project)
	case args["deploy"].(bool):
		deploy(project, args["<name>"].([]string), args["--env"].([]string))
	case args["delete"].(bool):
		delete(project, args["<name>"].([]string), args["--yes"].(bool))
	case args["invoke"].(bool):
		invoke(project, args["<name>"].([]string), args["--verbose"].(bool), args["--async"].(bool))
	case args["rollback"].(bool):
		rollback(project, args["<name>"].([]string), args["<version>"])
	case args["build"].(bool):
		build(project, args["<name>"].([]string))
	case args["logs"].(bool):
		tail(project, args["<name>"].([]string), args["--filter"].(string))
	}
}

// list functions.
func list(project *project.Project) {
	// TODO(tj): more informative output
	fmt.Println()
	for _, fn := range project.Functions {
		fmt.Printf("  - %s (%s)\n", fn.Name, fn.Runtime)
	}
	fmt.Println()
}

// invoke reads request json from stdin and outputs the responses.
func invoke(project *project.Project, name []string, verbose, async bool) {
	dec := json.NewDecoder(os.Stdin)
	kind := function.RequestResponse

	if async {
		kind = function.Event
	}

	fn, err := project.FunctionByName(name[0])
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	for {
		var v struct {
			Event   interface{}
			Context interface{}
		}

		err := dec.Decode(&v)

		if err == io.EOF {
			break
		}

		if err != nil {
			log.Fatalf("error: %s", err)
		}

		reply, logs, err := fn.Invoke(v.Event, v.Context, kind)
		if err != nil {
			log.Fatalf("error: %s", err)
		}

		// TODO(tj) rename flag to --with-logs or --logs
		if verbose {
			io.Copy(os.Stderr, logs)
		}

		io.Copy(os.Stdout, reply)
		fmt.Fprintf(os.Stdout, "\n")
	}
}

// deploy code and config changes.
func deploy(project *project.Project, names []string, env []string) {
	for _, s := range env {
		parts := strings.Split(s, "=")
		project.SetEnv(parts[0], parts[1])<commit_msg>add erro clarification when invoking<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"

	_ "github.com/apex/apex/runtime/golang"
	_ "github.com/apex/apex/runtime/nodejs"
	_ "github.com/apex/apex/runtime/python"

	"github.com/apex/apex/dryrun"
	"github.com/apex/apex/function"
	"github.com/apex/apex/logs"
	"github.com/apex/apex/project"
	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/segmentio/go-prompt"
	"github.com/tj/docopt"
)

var version = "0.3.0"

const usage = `
  Usage:
    apex deploy [options] [<name>...] [--env name=val]...
    apex delete [options] [<name>...]
    apex invoke [options] <name> [--async] [-v]
    apex rollback [options] <name> [<version>]
    apex logs [options] <name> [--filter pattern]
    apex build [options] <name>
    apex list [options]
    apex -h | --help
    apex --version

  Options:
    -e, --env name=val      Environment variable
    -D, --dry-run           Perform a dry-run
    -F, --filter pattern    Filter logs with pattern [default: ]
    -l, --log-level level   Log severity level [default: info]
    -a, --async             Async invocation
    -C, --chdir path        Working directory
    -y, --yes               Automatic yes to prompts
    -h, --help              Output help information
    -v, --verbose           Output verbose logs
    -V, --version           Output version

  Examples:
    Deploy all functions
    $ apex deploy

    Deploy specific functions
    $ apex deploy foo bar

    Delete all functions
    $ apex delete

    Delete specified functions
    $ apex delete foo bar

    Invoke a function with input json
    $ apex invoke foo < request.json

    Rollback a function to the previous version
    $ apex rollback foo

    Rollback a function to the specified version
    $ apex rollback bar 3

    Deploy functions in a different project
    $ apex deploy -C ~/dev/myapp

    Build zip output for a function
    $ apex build foo > /tmp/out.zip
`

func main() {
	args, err := docopt.Parse(usage, nil, true, version, false)
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	log.SetHandler(cli.Default)

	if l, err := log.ParseLevel(args["--log-level"].(string)); err == nil {
		log.SetLevel(l)
	}

	session := session.New(aws.NewConfig())

	project := &project.Project{
		Log:  log.Log,
		Path: ".",
	}

	if args["--dry-run"].(bool) {
		log.SetLevel(log.WarnLevel)
		project.Service = dryrun.New(session)
		project.Concurrency = 1
	} else {
		project.Service = lambda.New(session)
	}

	if dir, ok := args["--chdir"].(string); ok {
		if err := os.Chdir(dir); err != nil {
			log.Fatalf("error: %s", err)
		}
	}

	if err := project.Open(); err != nil {
		log.Fatalf("error opening project: %s", err)
	}

	switch {
	case args["list"].(bool):
		list(project)
	case args["deploy"].(bool):
		deploy(project, args["<name>"].([]string), args["--env"].([]string))
	case args["delete"].(bool):
		delete(project, args["<name>"].([]string), args["--yes"].(bool))
	case args["invoke"].(bool):
		invoke(project, args["<name>"].([]string), args["--verbose"].(bool), args["--async"].(bool))
	case args["rollback"].(bool):
		rollback(project, args["<name>"].([]string), args["<version>"])
	case args["build"].(bool):
		build(project, args["<name>"].([]string))
	case args["logs"].(bool):
		tail(project, args["<name>"].([]string), args["--filter"].(string))
	}
}

// list functions.
func list(project *project.Project) {
	// TODO(tj): more informative output
	fmt.Println()
	for _, fn := range project.Functions {
		fmt.Printf("  - %s (%s)\n", fn.Name, fn.Runtime)
	}
	fmt.Println()
}

// invoke reads request json from stdin and outputs the responses.
func invoke(project *project.Project, name []string, verbose, async bool) {
	dec := json.NewDecoder(os.Stdin)
	kind := function.RequestResponse

	if async {
		kind = function.Event
	}

	fn, err := project.FunctionByName(name[0])
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	for {
		var v struct {
			Event   interface{}
			Context interface{}
		}

		err := dec.Decode(&v)

		if err == io.EOF {
			break
		}

		if err != nil {
			log.Fatalf("error parsing response: %s", err)
		}

		reply, logs, err := fn.Invoke(v.Event, v.Context, kind)
		if err != nil {
			log.Fatalf("error response: %s", err)
		}

		// TODO(tj) rename flag to --with-logs or --logs
		if verbose {
			io.Copy(os.Stderr, logs)
		}

		io.Copy(os.Stdout, reply)
		fmt.Fprintf(os.Stdout, "\n")
	}
}

// deploy code and config changes.
func deploy(project *project.Project, names []string, env []string) {
	for _, s := range env {
		parts := strings.Split(s, "=")
		project.SetEnv(parts[0], parts[1])
{'fraction_non_alphanumeric': 0.1729346806959058, 'fraction_numerical': 0.0016668402958641526, 'mean_word_length': 2.9669421487603307, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, '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': '3574704', 'n_tokens_mistral': 3620, 'n_tokens_neox': 3366, 'n_words': 844}