<commit_before>// Copyright 2015 <NAME>. All rights reserved.
// Use of this source code is governed by the Apache License,
// Version 2.0 that can be found in the LICENSE file.

package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"gopkg.in/yaml.v2"
)

var (
	inputFile       = flag.String("i", "routes.yaml", "Routes input file")
	outputFile      = flag.String("o", "routes.go", "Routes output file")
	packageName     = flag.String("p", "", "Package name")
	varName         = flag.String("v", "Routes", "Variable name")
	errInvalidInput = errors.New("missing routes input file")
	errInvalidPath  = errors.New("invalid route path")
)

type routemap map[string]*route

type routes struct {
	params map[string]string
	routes routemap
}

type route struct {
	child                *route
	children             routemap
	param, check, handle string
}

func main() {
	flag.Parse()
	log.SetFlags(log.Lmicroseconds)

	if *inputFile == "" {
		log.Fatal("input filename is required (use -i flag)")
	} else if *packageName == "" {
		log.Fatal("package name is required (use -p flag)")
	}

	f, err := os.OpenFile(*outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)

	if err != nil {
		log.Fatal(err)
	}

	defer f.Close()

	r, err := loadRoutes()

	//spew.Dump(r)

	if err != nil {
		log.Fatal(err)
	}

	buf := &bytes.Buffer{}

	fmt.Fprintf(buf, `package %s 

import "github.com/martingallagher/routify/router"

var %s =  router.Routes{
`, *packageName, *varName)

	for k, v := range r.routes {
		if len(v.children) == 0 {
			continue
		}

		r.writeRule(buf, k, v)
	}

	buf.WriteString("\n}")

	if _, err = buf.WriteTo(f); err != nil {
		log.Fatal(err)
	}
}

func (r *routes) add(method, path, handle string) error {
	if _, exists := r.routes[method]; !exists {
		r.routes[method] = &route{children: routemap{}}
	}

	var (
		p []string
		c = r.routes[method]
	)

	if path != "/" {
		p = strings.Split(path, "/")
	} else {
		p = []string{"/"}
	}

	for _, v := range p {
		if v == "" {
			return errInvalidPath
		}

		// Parameter
		if v[0] == '$' {
			c.child = &route{
				param:    v[1:],
				check:    r.params[v],
				children: routemap{},
			}

			c = c.child

			continue
		}

		// Allocate map for static routes
		if _, exists := c.children[v]; !exists {
			c.children[v] = &route{children: routemap{}}
		}

		c = c.children[v]
	}

	c.handle = handle

	return nil
}

func (r *routes) writeChild(buf *bytes.Buffer, c *route) {
	fmt.Fprintf(buf, "Child: &router.Route{\nParam: \"%s\",\n", c.param)

	if c.check != "" {
		fmt.Fprintf(buf, "Check: %s,\n", c.check)
	}

	if c.handle != "" {
		fmt.Fprintf(buf, "HandlerFunc: %s,\n", c.handle)
	}

	if len(c.children) > 0 {
		r.writeChildren(buf, c)
	} else if c.child != nil {
		r.writeChild(buf, c.child)
	}

	buf.WriteString("},\n")
}

func (r *routes) writeChildren(buf *bytes.Buffer, c *route) {
	buf.WriteString("Children: router.Routes{\n")

	for k, v := range c.children {
		r.writeRule(buf, k, v)
	}

	buf.WriteString("},\n")
}

func (r *routes) writeRule(buf *bytes.Buffer, p string, c *route) {
	fmt.Fprintf(buf, "\"%s\": &router.Route{\n", p)

	if c.handle != "" {
		fmt.Fprintf(buf, "HandlerFunc: %s,\n", c.handle)
	}

	if len(c.children) > 0 {
		r.writeChildren(buf, c)
	} else if c.child != nil {
		r.writeChild(buf, c.child)
	}

	buf.WriteString("},\n")
}

func loadRoutes() (*routes, error) {
	f, err := os.Open(*inputFile)
<commit_msg>Simplify routes construction; use the output file directly.<commit_after>// Copyright 2015 <NAME>. All rights reserved.
// Use of this source code is governed by the Apache License,
// Version 2.0 that can be found in the LICENSE file.

package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"gopkg.in/yaml.v2"
)

var (
	inputFile       = flag.String("i", "routes.yaml", "Routes input file")
	outputFile      = flag.String("o", "routes.go", "Routes output file")
	packageName     = flag.String("p", "", "Package name")
	varName         = flag.String("v", "Routes", "Variable name")
	errInvalidInput = errors.New("missing routes input file")
	errInvalidPath  = errors.New("invalid route path")
)

type routemap map[string]*route

type routes struct {
	params map[string]string
	routes routemap
}

type route struct {
	child                *route
	children             routemap
	param, check, handle string
}

func main() {
	flag.Parse()
	log.SetFlags(log.Lmicroseconds)

	if *inputFile == "" {
		log.Fatal("input filename is required (use -i flag)")
	} else if *packageName == "" {
		log.Fatal("package name is required (use -p flag)")
	}

	f, err := os.OpenFile(*outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)

	if err != nil {
		log.Fatal(err)
	}

	defer f.Close()

	r, err := loadRoutes()

	if err != nil {
		log.Fatal(err)
	}

	fmt.Fprintf(f, `package %s 

import "github.com/martingallagher/routify/router"

var %s =  router.Routes{
`, *packageName, *varName)

	for k, v := range r.routes {
		if len(v.children) == 0 {
			continue
		}

		r.writeRule(f, k, v)
	}

	f.WriteString("\n}")

	if err = f.Sync(); err != nil {
		log.Fatal(err)
	}
}

func (r *routes) add(method, path, handle string) error {
	if _, exists := r.routes[method]; !exists {
		r.routes[method] = &route{children: routemap{}}
	}

	var (
		p []string
		c = r.routes[method]
	)

	if path != "/" {
		p = strings.Split(path, "/")
	} else {
		p = []string{"/"}
	}

	for _, v := range p {
		if v == "" {
			return errInvalidPath
		}

		// Parameter
		if v[0] == '$' {
			c.child = &route{
				param:    v[1:],
				check:    r.params[v],
				children: routemap{},
			}

			c = c.child

			continue
		}

		// Allocate map for static routes
		if _, exists := c.children[v]; !exists {
			c.children[v] = &route{children: routemap{}}
		}

		c = c.children[v]
	}

	c.handle = handle

	return nil
}

func (r *routes) writeChild(f *os.File, c *route) {
	fmt.Fprintf(f, "Child: &router.Route{\nParam: \"%s\",\n", c.param)

	if c.check != "" {
		fmt.Fprintf(f, "Check: %s,\n", c.check)
	}

	if c.handle != "" {
		fmt.Fprintf(f, "HandlerFunc: %s,\n", c.handle)
	}

	if len(c.children) > 0 {
		r.writeChildren(f, c)
	} else if c.child != nil {
		r.writeChild(f, c.child)
	}

	f.WriteString("},\n")
}

func (r *routes) writeChildren(f *os.File, c *route) {
	f.WriteString("Children: router.Routes{\n")

	for k, v := range c.children {
		r.writeRule(f, k, v)
	}

	f.WriteString("},\n")
}

func (r *routes) writeRule(f *os.File, p string, c *route) {
	fmt.Fprintf(f, "\"%s\": &router.Route{\n", p)

	if c.handle != "" {
		fmt.Fprintf(f, "HandlerFunc: %s,\n", c.handle)
	}

	if len(c.children) > 0 {
		r.writeChildren(f, c)
	} else if c.child != nil {
		r.writeChild(f, c.child)
	}

	f.WriteString("},\n")
}

func loadRoutes() (*routes, error) {
	f, err := os.Open(*inputFile)

{'fraction_non_alphanumeric': 0.18149727901161936, 'fraction_numerical': 0.0047065744962494485, 'mean_word_length': 3.0524433849821215, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 9, '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': '3452953', 'n_tokens_mistral': 2872, 'n_tokens_neox': 2687, 'n_words': 651}