<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strconv"
	"strings"

	"github.com/mholt/caddy/app"
	"github.com/mholt/caddy/config"
	"github.com/mholt/caddy/server"
)

var (
	conf    string
	cpu     string
	version bool
)

func init() {
	flag.StringVar(&conf, "conf", "", "Configuration file to use (default="+config.DefaultConfigFile+")")
	flag.BoolVar(&app.Http2, "http2", true, "Enable HTTP/2 support") // TODO: temporary flag until http2 merged into std lib
	flag.BoolVar(&app.Quiet, "quiet", false, "Quiet mode (no initialization output)")
	flag.StringVar(&cpu, "cpu", "100%", "CPU cap")
	flag.StringVar(&config.Root, "root", config.DefaultRoot, "Root path to default site")
	flag.StringVar(&config.Host, "host", config.DefaultHost, "Default host")
	flag.StringVar(&config.Port, "port", config.DefaultPort, "Default port")
	flag.BoolVar(&version, "version", false, "Show version")
}

func main() {
	flag.Parse()

	if version {
		fmt.Printf("%s %s\n", app.Name, app.Version)
		os.Exit(0)
	}

	// Set CPU cap
	err := app.SetCPU(cpu)
	if err != nil {
		log.Fatal(err)
	}

	// Load config from file
	allConfigs, err := loadConfigs()
	if err != nil {
		log.Fatal(err)
	}

	// Group by address (virtual hosts)
	addresses, err := config.ArrangeBindings(allConfigs)
	if err != nil {
		log.Fatal(err)
	}

	// Start each server with its one or more configurations
	for addr, configs := range addresses {
		s, err := server.New(addr.String(), configs, configs[0].TLS.Enabled)
		if err != nil {
			log.Fatal(err)
		}
		s.HTTP2 = app.Http2 // TODO: This setting is temporary
		app.Wg.Add(1)
		go func(s *server.Server) {
			defer app.Wg.Done()
			err := s.Serve()
			if err != nil {
				log.Fatal(err) // kill whole process to avoid a half-alive zombie server
			}
		}(s)

		app.Servers = append(app.Servers, s)
	}

	// Show initialization output
	if !app.Quiet {
		var checkedFdLimit bool
		for addr, configs := range addresses {
			for _, conf := range configs {
				// Print address of site
				fmt.Println(conf.Address())

				// Note if non-localhost site resolves to loopback interface
				if addr.IP.IsLoopback() && !isLocalhost(conf.Host) {
					fmt.Printf("Notice: %s is only accessible on this machine (%s)\n",
						conf.Host, addr.IP.String())
				}
			}

			// Warn if ulimit is too low for production sites
			if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") &&
				!addr.IP.IsLoopback() && !checkedFdLimit {
				out, err := exec.Command("ulimit", "-n").Output()
				if err == nil {
					// Note that an error here need not be reported
					lim, err := strconv.Atoi(string(bytes.TrimSpace(out)))
					if err == nil && lim < 4096 {
						fmt.Printf("Warning: File descriptor limit is too low (%d) for production sites\n", lim)
					}
					checkedFdLimit = true
				}
			}
		}
	}

	// Wait for all listeners to stop
	app.Wg.Wait()
}

func isLocalhost(s string) bool {
	return s == "localhost" || s == "::1" || strings.HasPrefix(s, "127.")
}

// loadConfigs loads configuration from a file or stdin (piped).
// Configuration is obtained from one of three sources, tried
// in this order: 1. -conf flag, 2. stdin, 3. Caddyfile.
// If none of those are available, a default configuration is
// loaded.
func loadConfigs() ([]server.Config, error) {
	// -conf flag
	if conf != "" {
		file, err := os.Open(conf)
		if err != nil {
			return []server.Config{}, err
		}
		defer file.Close()<commit_msg>Lil' bit of godoc<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strconv"
	"strings"

	"github.com/mholt/caddy/app"
	"github.com/mholt/caddy/config"
	"github.com/mholt/caddy/server"
)

var (
	conf    string
	cpu     string
	version bool
)

func init() {
	flag.StringVar(&conf, "conf", "", "Configuration file to use (default="+config.DefaultConfigFile+")")
	flag.BoolVar(&app.Http2, "http2", true, "Enable HTTP/2 support") // TODO: temporary flag until http2 merged into std lib
	flag.BoolVar(&app.Quiet, "quiet", false, "Quiet mode (no initialization output)")
	flag.StringVar(&cpu, "cpu", "100%", "CPU cap")
	flag.StringVar(&config.Root, "root", config.DefaultRoot, "Root path to default site")
	flag.StringVar(&config.Host, "host", config.DefaultHost, "Default host")
	flag.StringVar(&config.Port, "port", config.DefaultPort, "Default port")
	flag.BoolVar(&version, "version", false, "Show version")
}

func main() {
	flag.Parse()

	if version {
		fmt.Printf("%s %s\n", app.Name, app.Version)
		os.Exit(0)
	}

	// Set CPU cap
	err := app.SetCPU(cpu)
	if err != nil {
		log.Fatal(err)
	}

	// Load config from file
	allConfigs, err := loadConfigs()
	if err != nil {
		log.Fatal(err)
	}

	// Group by address (virtual hosts)
	addresses, err := config.ArrangeBindings(allConfigs)
	if err != nil {
		log.Fatal(err)
	}

	// Start each server with its one or more configurations
	for addr, configs := range addresses {
		s, err := server.New(addr.String(), configs, configs[0].TLS.Enabled)
		if err != nil {
			log.Fatal(err)
		}
		s.HTTP2 = app.Http2 // TODO: This setting is temporary
		app.Wg.Add(1)
		go func(s *server.Server) {
			defer app.Wg.Done()
			err := s.Serve()
			if err != nil {
				log.Fatal(err) // kill whole process to avoid a half-alive zombie server
			}
		}(s)

		app.Servers = append(app.Servers, s)
	}

	// Show initialization output
	if !app.Quiet {
		var checkedFdLimit bool
		for addr, configs := range addresses {
			for _, conf := range configs {
				// Print address of site
				fmt.Println(conf.Address())

				// Note if non-localhost site resolves to loopback interface
				if addr.IP.IsLoopback() && !isLocalhost(conf.Host) {
					fmt.Printf("Notice: %s is only accessible on this machine (%s)\n",
						conf.Host, addr.IP.String())
				}
			}

			// Warn if ulimit is too low for production sites
			if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") &&
				!addr.IP.IsLoopback() && !checkedFdLimit {
				out, err := exec.Command("ulimit", "-n").Output()
				if err == nil {
					// Note that an error here need not be reported
					lim, err := strconv.Atoi(string(bytes.TrimSpace(out)))
					if err == nil && lim < 4096 {
						fmt.Printf("Warning: File descriptor limit is too low (%d) for production sites\n", lim)
					}
					checkedFdLimit = true
				}
			}
		}
	}

	// Wait for all listeners to stop
	app.Wg.Wait()
}

// isLocalhost returns true if the string looks explicitly like a localhost address.
func isLocalhost(s string) bool {
	return s == "localhost" || s == "::1" || strings.HasPrefix(s, "127.")
}

// loadConfigs loads configuration from a file or stdin (piped).
// Configuration is obtained from one of three sources, tried
// in this order: 1. -conf flag, 2. stdin, 3. Caddyfile.
// If none of those are available, a default configuration is
// loaded.
func loadConfigs() ([]server.Config, error) {
	// -conf flag
	if conf != "" {
		file, err := os.Open(conf)
		if err != nil {
			return []server.Config{}, err
		}
		defer file.Close()
{'fraction_non_alphanumeric': 0.15277580576458896, 'fraction_numerical': 0.006531307681385773, 'mean_word_length': 3.2382671480144403, 'pattern_counts': {'":': 2, '<': 5, '<?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': '6823302', 'n_tokens_mistral': 2725, 'n_tokens_neox': 2451, 'n_words': 724}