<commit_before>package core

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/joyent/containerpilot/config"
	"github.com/joyent/containerpilot/control"
	"github.com/joyent/containerpilot/discovery"
	"github.com/joyent/containerpilot/events"
	"github.com/joyent/containerpilot/jobs"
	"github.com/joyent/containerpilot/subcommands"
	"github.com/joyent/containerpilot/telemetry"
	"github.com/joyent/containerpilot/watches"

	log "github.com/Sirupsen/logrus"
)

var (
	// Version is the version for this build, set at build time via LDFLAGS
	Version string
	// GitHash is the short-form commit hash of this build, set at build time
	GitHash string
)

// App encapsulates the state of ContainerPilot after the initial setup.
type App struct {
	ControlServer *control.HTTPServer
	Discovery     discovery.Backend
	Jobs          []*jobs.Job
	Watches       []*watches.Watch
	Telemetry     *telemetry.Telemetry
	StopTimeout   int
	signalLock    *sync.RWMutex
	ConfigFlag    string
	Bus           *events.EventBus
}

// EmptyApp creates an empty application
func EmptyApp() *App {
	app := &App{}
	app.signalLock = &sync.RWMutex{}
	return app
}

// LoadApp parses the commandline arguments and loads the config
func LoadApp() (*App, error) {

	var versionFlag bool
	var templateFlag bool
	var reloadFlag bool

	var configFlag string
	var renderFlag string
	var maintFlag string

	var putMetricFlags MultiFlag
	var putEnvFlags MultiFlag

	if !flag.Parsed() {
		flag.BoolVar(&versionFlag, "version", false,
			"Show version identifier and quit.")

		flag.BoolVar(&templateFlag, "template", false,
			"Render template and quit.")

		flag.BoolVar(&reloadFlag, "reload", false,
			"Reload a ContainerPilot process through its control socket.")

		flag.StringVar(&configFlag, "config", "",
			"File path to JSON5 configuration file. Defaults to CONTAINERPILOT env var.")

		flag.StringVar(&renderFlag, "out", "",
			`File path where to save rendered config file when '-template' is used.
	Defaults to stdout ('-').`)

		flag.StringVar(&maintFlag, "maintenance", "",
			`Toggle maintenance mode for a ContainerPilot process through its control socket.
	Options: '-maintenance enable' or '-maintenance disable'`)

		flag.Var(&putMetricFlags, "putmetric",
			`Update metrics of a ContainerPilot process through its control socket.
	Pass metrics in the format: 'key=value'`)

		flag.Var(&putEnvFlags, "putenv",
			`Update environ of a ContainerPilot process through its control socket.
	Pass environment in the format: 'key=value'`)

		flag.Parse()
	}

	if versionFlag {
		fmt.Printf("Version: %s\nGitHash: %s\n", Version, GitHash)
		os.Exit(0)
	}

	if configFlag == "" {
		configFlag = os.Getenv("CONTAINERPILOT")
	}

	if templateFlag {
		err := config.RenderConfig(configFlag, renderFlag)
		if err != nil {
			return nil, err
		}
		os.Exit(0)
	}

	cmd, _ := subcommands.Init(configFlag)

	if reloadFlag {
		if err := cmd.SendReload(); err != nil {
			fmt.Println("Reload: failed to run subcommand:", err)
			os.Exit(2)
		}
		os.Exit(0)
	}

	if maintFlag != "" {
		if err := cmd.SendMaintenance(maintFlag); err != nil {
			fmt.Println("SendMaintenance: failed to run subcommand:", err)
			os.Exit(2)
		}

		os.Exit(0)
	}

	if putEnvFlags.Len() != 0 {
		if err := cmd.SendEnviron(putEnvFlags.Values); err != nil {
			fmt.Println("SendEnviron: failed to run subcommand:", err)
			os.Exit(2)
		}

		os.Exit(0)
	}

	if putMetricFlags.Len() != 0 {
		if err := cmd.SendMetric(putMetricFlags.Values); err != nil {
			fmt.Println("SendMetric: failed to run subcommand:", err)
			os.Exit(2)
		}

		os.Exit(0)
	}

	os.Setenv("CONTAINERPILOT_PID", fmt.Sprintf("%v", os.Getpid()))

	app, err := NewApp(configFlag)
	if err != nil {
		return nil, err
	}
	return app, nil
}

// NewApp creates a new App from the config
func NewApp(configFlag string) (*App, error) {
	a := EmptyApp()
	cfg, err := config.LoadConfig(configFlag)
	if err != nil {
		return nil, err
	}

	if err := cfg.InitLogging(); err != nil {
		return nil, err
	}
	if log.GetLevel() >= log.DebugLevel {
		configJSON, err := json.Marshal(cfg)<commit_msg>move subcommand.Init into flag blocks to avoid extra config parse (#384)<commit_after>package core

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/joyent/containerpilot/config"
	"github.com/joyent/containerpilot/control"
	"github.com/joyent/containerpilot/discovery"
	"github.com/joyent/containerpilot/events"
	"github.com/joyent/containerpilot/jobs"
	"github.com/joyent/containerpilot/subcommands"
	"github.com/joyent/containerpilot/telemetry"
	"github.com/joyent/containerpilot/watches"

	log "github.com/Sirupsen/logrus"
)

var (
	// Version is the version for this build, set at build time via LDFLAGS
	Version string
	// GitHash is the short-form commit hash of this build, set at build time
	GitHash string
)

// App encapsulates the state of ContainerPilot after the initial setup.
type App struct {
	ControlServer *control.HTTPServer
	Discovery     discovery.Backend
	Jobs          []*jobs.Job
	Watches       []*watches.Watch
	Telemetry     *telemetry.Telemetry
	StopTimeout   int
	signalLock    *sync.RWMutex
	ConfigFlag    string
	Bus           *events.EventBus
}

// EmptyApp creates an empty application
func EmptyApp() *App {
	app := &App{}
	app.signalLock = &sync.RWMutex{}
	return app
}

// LoadApp parses the commandline arguments and loads the config
func LoadApp() (*App, error) {

	var versionFlag bool
	var templateFlag bool
	var reloadFlag bool

	var configFlag string
	var renderFlag string
	var maintFlag string

	var putMetricFlags MultiFlag
	var putEnvFlags MultiFlag

	if !flag.Parsed() {
		flag.BoolVar(&versionFlag, "version", false,
			"Show version identifier and quit.")

		flag.BoolVar(&templateFlag, "template", false,
			"Render template and quit.")

		flag.BoolVar(&reloadFlag, "reload", false,
			"Reload a ContainerPilot process through its control socket.")

		flag.StringVar(&configFlag, "config", "",
			"File path to JSON5 configuration file. Defaults to CONTAINERPILOT env var.")

		flag.StringVar(&renderFlag, "out", "",
			`File path where to save rendered config file when '-template' is used.
	Defaults to stdout ('-').`)

		flag.StringVar(&maintFlag, "maintenance", "",
			`Toggle maintenance mode for a ContainerPilot process through its control socket.
	Options: '-maintenance enable' or '-maintenance disable'`)

		flag.Var(&putMetricFlags, "putmetric",
			`Update metrics of a ContainerPilot process through its control socket.
	Pass metrics in the format: 'key=value'`)

		flag.Var(&putEnvFlags, "putenv",
			`Update environ of a ContainerPilot process through its control socket.
	Pass environment in the format: 'key=value'`)

		flag.Parse()
	}

	if versionFlag {
		fmt.Printf("Version: %s\nGitHash: %s\n", Version, GitHash)
		os.Exit(0)
	}

	if configFlag == "" {
		configFlag = os.Getenv("CONTAINERPILOT")
	}

	if templateFlag {
		err := config.RenderConfig(configFlag, renderFlag)
		if err != nil {
			return nil, err
		}
		os.Exit(0)
	}

	if reloadFlag {
		cmd, err := subcommands.Init(configFlag)
		if err != nil {
			return nil, err
		}
		if err := cmd.SendReload(); err != nil {
			return nil,
				fmt.Errorf("-reload: failed to run subcommand: %v", err)
		}
		os.Exit(0)
	}

	if maintFlag != "" {
		cmd, err := subcommands.Init(configFlag)
		if err != nil {
			return nil, err
		}
		if err := cmd.SendMaintenance(maintFlag); err != nil {
			return nil,
				fmt.Errorf("-maintenance: failed to run subcommand: %v", err)
		}
		os.Exit(0)
	}

	if putEnvFlags.Len() != 0 {
		cmd, err := subcommands.Init(configFlag)
		if err != nil {
			return nil, err
		}
		if err := cmd.SendEnviron(putEnvFlags.Values); err != nil {
			return nil, fmt.Errorf("-putenv: failed to run subcommand: %v", err)
		}
		os.Exit(0)
	}

	if putMetricFlags.Len() != 0 {
		cmd, err := subcommands.Init(configFlag)
		if err != nil {
			return nil, err
		}
		if err := cmd.SendMetric(putMetricFlags.Values); err != nil {
			return nil,
				fmt.Errorf("-putmetric: failed to run subcommand: %v", err)
		}
		os.Exit(0)
	}

	os.Setenv("CONTAINERPILOT_PID", fmt.Sprintf("%v", os.Getpid()))

	app, err := NewApp(configFlag)
	if err != nil {
		return nil, err
	}
	return app, nil
}

// NewApp creates a new App from the config
func NewApp(configFlag string) (*App, error) {
	a := EmptyApp()
	cfg, err := config.LoadConfig(configFlag)
	if err != nil {
		return nil, err
	}

	if err := cfg.InitLogging(); err != nil {
		return nil, err
	}
	if log.GetLevel() >= log.DebugLevel {
		configJSON, err := json.Marshal(cfg)
{'fraction_non_alphanumeric': 0.12420048842888708, 'fraction_numerical': 0.002907314804046982, 'mean_word_length': 3.756637168141593, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '7094110', 'n_tokens_mistral': 3133, 'n_tokens_neox': 2874, 'n_words': 827}