mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 10:37:24 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			172 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package setup
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"log"
 | |
| 	"net/url"
 | |
| 	"path/filepath"
 | |
| 	"runtime"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/mholt/caddy/middleware"
 | |
| 	"github.com/mholt/caddy/middleware/git"
 | |
| )
 | |
| 
 | |
| // Git configures a new Git service routine.
 | |
| func Git(c *Controller) (middleware.Middleware, error) {
 | |
| 	repo, err := gitParse(c)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	c.Startup = append(c.Startup, func() error {
 | |
| 		// Startup functions are blocking; start
 | |
| 		// service routine in background
 | |
| 		go func() {
 | |
| 			for {
 | |
| 				time.Sleep(repo.Interval)
 | |
| 
 | |
| 				err := repo.Pull()
 | |
| 				if err != nil {
 | |
| 					if git.Logger == nil {
 | |
| 						log.Println(err)
 | |
| 					} else {
 | |
| 						git.Logger.Println(err)
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}()
 | |
| 
 | |
| 		// Do a pull right away to return error
 | |
| 		return repo.Pull()
 | |
| 	})
 | |
| 
 | |
| 	return nil, err
 | |
| }
 | |
| 
 | |
| func gitParse(c *Controller) (*git.Repo, error) {
 | |
| 	repo := &git.Repo{Branch: "master", Interval: git.DefaultInterval, Path: c.Root}
 | |
| 
 | |
| 	for c.Next() {
 | |
| 		args := c.RemainingArgs()
 | |
| 
 | |
| 		switch len(args) {
 | |
| 		case 2:
 | |
| 			repo.Path = filepath.Clean(c.Root + string(filepath.Separator) + args[1])
 | |
| 			fallthrough
 | |
| 		case 1:
 | |
| 			repo.Url = args[0]
 | |
| 		}
 | |
| 
 | |
| 		for c.NextBlock() {
 | |
| 			switch c.Val() {
 | |
| 			case "repo":
 | |
| 				if !c.NextArg() {
 | |
| 					return nil, c.ArgErr()
 | |
| 				}
 | |
| 				repo.Url = c.Val()
 | |
| 			case "path":
 | |
| 				if !c.NextArg() {
 | |
| 					return nil, c.ArgErr()
 | |
| 				}
 | |
| 				repo.Path = filepath.Clean(c.Root + string(filepath.Separator) + c.Val())
 | |
| 			case "branch":
 | |
| 				if !c.NextArg() {
 | |
| 					return nil, c.ArgErr()
 | |
| 				}
 | |
| 				repo.Branch = c.Val()
 | |
| 			case "key":
 | |
| 				if !c.NextArg() {
 | |
| 					return nil, c.ArgErr()
 | |
| 				}
 | |
| 				repo.KeyPath = c.Val()
 | |
| 			case "interval":
 | |
| 				if !c.NextArg() {
 | |
| 					return nil, c.ArgErr()
 | |
| 				}
 | |
| 				t, _ := strconv.Atoi(c.Val())
 | |
| 				if t > 0 {
 | |
| 					repo.Interval = time.Duration(t) * time.Second
 | |
| 				}
 | |
| 			case "then":
 | |
| 				thenArgs := c.RemainingArgs()
 | |
| 				if len(thenArgs) == 0 {
 | |
| 					return nil, c.ArgErr()
 | |
| 				}
 | |
| 				repo.Then = strings.Join(thenArgs, " ")
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// if repo is not specified, return error
 | |
| 	if repo.Url == "" {
 | |
| 		return nil, c.ArgErr()
 | |
| 	}
 | |
| 
 | |
| 	// if private key is not specified, convert repository url to https
 | |
| 	// to avoid ssh authentication
 | |
| 	// else validate git url
 | |
| 	// Note: private key support not yet available on Windows
 | |
| 	var err error
 | |
| 	if repo.KeyPath == "" {
 | |
| 		repo.Url, repo.Host, err = sanitizeHttp(repo.Url)
 | |
| 	} else {
 | |
| 		repo.Url, repo.Host, err = sanitizeGit(repo.Url)
 | |
| 		// TODO add Windows support for private repos
 | |
| 		if runtime.GOOS == "windows" {
 | |
| 			return nil, fmt.Errorf("Private repository not yet supported on Windows")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// validate git availability in PATH
 | |
| 	if err = git.InitGit(); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return repo, repo.Prepare()
 | |
| }
 | |
| 
 | |
| // sanitizeHttp cleans up repository url and converts to https format
 | |
| // if currently in ssh format.
 | |
| // Returns sanitized url, hostName (e.g. github.com, bitbucket.com)
 | |
| // and possible error
 | |
| func sanitizeHttp(repoUrl string) (string, string, error) {
 | |
| 	url, err := url.Parse(repoUrl)
 | |
| 	if err != nil {
 | |
| 		return "", "", err
 | |
| 	}
 | |
| 
 | |
| 	if url.Host == "" && strings.HasPrefix(url.Path, "git@") {
 | |
| 		url.Path = url.Path[len("git@"):]
 | |
| 		i := strings.Index(url.Path, ":")
 | |
| 		if i < 0 {
 | |
| 			return "", "", fmt.Errorf("Invalid git url %s", repoUrl)
 | |
| 		}
 | |
| 		url.Host = url.Path[:i]
 | |
| 		url.Path = "/" + url.Path[i+1:]
 | |
| 	}
 | |
| 
 | |
| 	repoUrl = "https://" + url.Host + url.Path
 | |
| 	return repoUrl, url.Host, nil
 | |
| }
 | |
| 
 | |
| // sanitizeGit cleans up repository url and validate ssh format.
 | |
| // Returns sanitized url, hostName (e.g. github.com, bitbucket.com)
 | |
| // and possible error
 | |
| func sanitizeGit(repoUrl string) (string, string, error) {
 | |
| 	repoUrl = strings.TrimSpace(repoUrl)
 | |
| 	if !strings.HasPrefix(repoUrl, "git@") || strings.Index(repoUrl, ":") < len("git@a:") {
 | |
| 		return "", "", fmt.Errorf("Invalid git url %s", repoUrl)
 | |
| 	}
 | |
| 	hostUrl := repoUrl[len("git@"):]
 | |
| 	i := strings.Index(hostUrl, ":")
 | |
| 	host := hostUrl[:i]
 | |
| 	return repoUrl, host, nil
 | |
| }
 |