239 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
package utils
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"io"
 | 
						|
	"log"
 | 
						|
	"net/http"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"reflect"
 | 
						|
	"strings"
 | 
						|
	"text/template"
 | 
						|
	"unicode"
 | 
						|
 | 
						|
	"github.com/hacdias/caddy-hugo/assets"
 | 
						|
	"github.com/hacdias/caddy-hugo/config"
 | 
						|
)
 | 
						|
 | 
						|
// CanBeEdited checks if the extension of a file is supported by the editor
 | 
						|
func CanBeEdited(filename string) bool {
 | 
						|
	extensions := [...]string{
 | 
						|
		"md", "markdown", "mdown", "mmark",
 | 
						|
		"asciidoc", "adoc", "ad",
 | 
						|
		"rst",
 | 
						|
		".json", ".toml", ".yaml",
 | 
						|
		".css", ".sass", ".scss",
 | 
						|
		".js",
 | 
						|
		".html",
 | 
						|
		".txt",
 | 
						|
	}
 | 
						|
 | 
						|
	for _, extension := range extensions {
 | 
						|
		if strings.HasSuffix(filename, extension) {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// CopyFile is used to copy a file
 | 
						|
func CopyFile(old, new string) error {
 | 
						|
	// Open the file and create a new one
 | 
						|
	r, err := os.Open(old)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer r.Close()
 | 
						|
 | 
						|
	w, err := os.Create(new)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer w.Close()
 | 
						|
 | 
						|
	// Copy the content
 | 
						|
	_, err = io.Copy(w, r)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Defined checks if variable is defined in a struct
 | 
						|
func Defined(data interface{}, field string) bool {
 | 
						|
	t := reflect.Indirect(reflect.ValueOf(data)).Type()
 | 
						|
 | 
						|
	if t.Kind() != reflect.Struct {
 | 
						|
		log.Print("Non-struct type not allowed.")
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	_, b := t.FieldByName(field)
 | 
						|
	return b
 | 
						|
}
 | 
						|
 | 
						|
// Dict allows to send more than one variable into a template
 | 
						|
func Dict(values ...interface{}) (map[string]interface{}, error) {
 | 
						|
	if len(values)%2 != 0 {
 | 
						|
		return nil, errors.New("invalid dict call")
 | 
						|
	}
 | 
						|
	dict := make(map[string]interface{}, len(values)/2)
 | 
						|
	for i := 0; i < len(values); i += 2 {
 | 
						|
		key, ok := values[i].(string)
 | 
						|
		if !ok {
 | 
						|
			return nil, errors.New("dict keys must be strings")
 | 
						|
		}
 | 
						|
		dict[key] = values[i+1]
 | 
						|
	}
 | 
						|
 | 
						|
	return dict, nil
 | 
						|
}
 | 
						|
 | 
						|
// GetTemplate is used to get a ready to use template based on the url and on
 | 
						|
// other sent templates
 | 
						|
func GetTemplate(r *http.Request, functions template.FuncMap, templates ...string) (*template.Template, error) {
 | 
						|
	// If this is a pjax request, use the minimal template to send only
 | 
						|
	// the main content
 | 
						|
	if r.Header.Get("X-PJAX") == "true" {
 | 
						|
		templates = append(templates, "base_minimal")
 | 
						|
	} else {
 | 
						|
		templates = append(templates, "base_full")
 | 
						|
	}
 | 
						|
 | 
						|
	var tpl *template.Template
 | 
						|
 | 
						|
	// For each template, add it to the the tpl variable
 | 
						|
	for i, t := range templates {
 | 
						|
		// Get the template from the assets
 | 
						|
		page, err := assets.Asset("templates/" + t + ".tmpl")
 | 
						|
 | 
						|
		// Check if there is some error. If so, the template doesn't exist
 | 
						|
		if err != nil {
 | 
						|
			log.Print(err)
 | 
						|
			return new(template.Template), err
 | 
						|
		}
 | 
						|
 | 
						|
		// If it's the first iteration, creates a new template and add the
 | 
						|
		// functions map
 | 
						|
		if i == 0 {
 | 
						|
			tpl, err = template.New(t).Funcs(functions).Parse(string(page))
 | 
						|
		} else {
 | 
						|
			tpl, err = tpl.Parse(string(page))
 | 
						|
		}
 | 
						|
 | 
						|
		if err != nil {
 | 
						|
			log.Print(err)
 | 
						|
			return new(template.Template), err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return tpl, nil
 | 
						|
}
 | 
						|
 | 
						|
// IsMap checks if some variable is a map
 | 
						|
func IsMap(sth interface{}) bool {
 | 
						|
	return reflect.ValueOf(sth).Kind() == reflect.Map
 | 
						|
}
 | 
						|
 | 
						|
// IsSlice checks if some variable is a slice
 | 
						|
func IsSlice(sth interface{}) bool {
 | 
						|
	return reflect.ValueOf(sth).Kind() == reflect.Slice
 | 
						|
}
 | 
						|
 | 
						|
// ParseComponents parses the components of an URL creating an array
 | 
						|
func ParseComponents(r *http.Request) []string {
 | 
						|
	//The URL that the user queried.
 | 
						|
	path := r.URL.Path
 | 
						|
	path = strings.TrimSpace(path)
 | 
						|
	//Cut off the leading and trailing forward slashes, if they exist.
 | 
						|
	//This cuts off the leading forward slash.
 | 
						|
	if strings.HasPrefix(path, "/") {
 | 
						|
		path = path[1:]
 | 
						|
	}
 | 
						|
	//This cuts off the trailing forward slash.
 | 
						|
	if strings.HasSuffix(path, "/") {
 | 
						|
		cutOffLastCharLen := len(path) - 1
 | 
						|
		path = path[:cutOffLastCharLen]
 | 
						|
	}
 | 
						|
	//We need to isolate the individual components of the path.
 | 
						|
	components := strings.Split(path, "/")
 | 
						|
	return components
 | 
						|
}
 | 
						|
 | 
						|
// Run is used to run the static website generator
 | 
						|
func Run(c *config.Config, force bool) {
 | 
						|
	os.RemoveAll(c.Path + "public")
 | 
						|
 | 
						|
	// Prevent running if watching is enabled
 | 
						|
	if b, pos := stringInSlice("--watch", c.Args); b && !force {
 | 
						|
		if len(c.Args) > pos && c.Args[pos+1] != "false" {
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		if len(c.Args) == pos+1 {
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if err := RunCommand(c.Hugo, c.Args, c.Path); err != nil {
 | 
						|
		log.Panic(err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// RunCommand executes an external command
 | 
						|
func RunCommand(command string, args []string, path string) error {
 | 
						|
	cmd := exec.Command(command, args...)
 | 
						|
	cmd.Dir = path
 | 
						|
	cmd.Stdout = os.Stderr
 | 
						|
	cmd.Stderr = os.Stderr
 | 
						|
	return cmd.Run()
 | 
						|
}
 | 
						|
 | 
						|
func stringInSlice(a string, list []string) (bool, int) {
 | 
						|
	for i, b := range list {
 | 
						|
		if b == a {
 | 
						|
			return true, i
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false, 0
 | 
						|
}
 | 
						|
 | 
						|
var splitCapitalizeExceptions = map[string]string{
 | 
						|
	"youtube":    "YouTube",
 | 
						|
	"github":     "GitHub",
 | 
						|
	"googleplus": "Google Plus",
 | 
						|
	"linkedin":   "LinkedIn",
 | 
						|
}
 | 
						|
 | 
						|
// SplitCapitalize splits a string by its uppercase letters and capitalize the
 | 
						|
// first letter of the string
 | 
						|
func SplitCapitalize(name string) string {
 | 
						|
	if val, ok := splitCapitalizeExceptions[strings.ToLower(name)]; ok {
 | 
						|
		return val
 | 
						|
	}
 | 
						|
 | 
						|
	var words []string
 | 
						|
	l := 0
 | 
						|
	for s := name; s != ""; s = s[l:] {
 | 
						|
		l = strings.IndexFunc(s[1:], unicode.IsUpper) + 1
 | 
						|
		if l <= 0 {
 | 
						|
			l = len(s)
 | 
						|
		}
 | 
						|
		words = append(words, s[:l])
 | 
						|
	}
 | 
						|
 | 
						|
	name = ""
 | 
						|
 | 
						|
	for _, element := range words {
 | 
						|
		name += element + " "
 | 
						|
	}
 | 
						|
 | 
						|
	name = strings.ToLower(name[:len(name)-1])
 | 
						|
	name = strings.ToUpper(string(name[0])) + name[1:]
 | 
						|
 | 
						|
	return name
 | 
						|
}
 |