2019-09-23 21:30:20 +03:00

164 lines
3.9 KiB
Go

package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/apex/log"
"github.com/client9/codegen/shell"
yaml "gopkg.in/yaml.v2"
)
// TreeConfig is the project configuration
type TreeConfig struct {
// these can be set by config
Source string `yaml:"source,omitempty"` // type of downloader to make
Exe string `yaml:"exe,omitempty"` // stuff for "raw"
Nametpl string `yaml:"nametpl,omitempty"` // stuff for "raw"
Config string `yaml:"config,omitempty"` // sets a custom location for goreleaser.yml config file
// these can not be set by config file
// and are set by the url/path
org string // github.com for now
owner string // ^ github username
name string // repo name
}
// LoadTreeConfig Loads config file
func LoadTreeConfig(file string) (config TreeConfig, err error) {
// nolint: gosec
f, err := os.Open(file)
if err != nil {
return
}
log.WithField("file", file).Debug("loading config file")
return LoadTreeConfigReader(f)
}
// LoadTreeConfigReader config via io.Reader
func LoadTreeConfigReader(fd io.Reader) (config TreeConfig, err error) {
data, err := ioutil.ReadAll(fd)
if err != nil {
return config, err
}
err = yaml.UnmarshalStrict(data, &config)
log.WithField("config", config).Debug("loaded config file")
return config, err
}
// treewalk walks the directory looking for .yaml files and generates
// downloader scripts from them. These are published to
// https://install.goreleaser.com
//
// see the following for performance improvement ideas:
// https://github.com/goreleaser/godownloader/issues/64
//
func treewalk(root string, treeout string, forceWrite bool) error { // nolint: gocyclo
rooterr := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
// weird case where filewalk failed
if err != nil {
return err
}
// ignore directories
if info.IsDir() {
return nil
}
suffix := filepath.Ext(path)
// ignore non-yaml stuff
if suffix != ".yaml" && suffix != ".yml" {
return nil
}
// Now: root/github.com/owner/repo.yaml
rel, err := filepath.Rel(root, path)
if err != nil {
panic("should never happen.. path is always in root")
}
// Now: github.com/owner/repo.yaml
rel = rel[0 : len(rel)-len(suffix)]
// Now: github.com/owner/repo
// better way of doing this?
parts := strings.Split(rel, string(os.PathSeparator))
if len(parts) != 3 {
return fmt.Errorf("invalid path: %s", path)
}
org, owner, repo := parts[0], parts[1], parts[2]
// Now: [ github.com client misspell ]
// only github.com for now
if org != "github.com" {
return fmt.Errorf("only github.com supported, got %s", org)
}
type repoConf struct {
Ignore bool `yaml:"ignore"`
}
var conf repoConf
bts, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if err := yaml.Unmarshal(bts, &conf); err != nil {
return err
}
if conf.Ignore {
log.WithField("repo", rel).Warn("ignoring repo as instructed")
return nil
}
// nice and clean
// org == github.com
// owner == you
// repo == your project
c, err := LoadTreeConfig(path)
if err != nil {
return err
}
// hacking for now and just hardwiring
if c.Source == "" {
c.Source = "godownloader"
}
// overwrite what exists for security
c.org = org
c.owner = owner
c.name = repo
shellcode, err := processSource(c.Source, owner+"/"+repo, c.Config, "", c.Exe, c.Nametpl)
if err != nil {
return err
}
// now write back
outdir := filepath.Join(treeout, org, owner)
err = os.MkdirAll(outdir, 0700)
if err != nil {
return err
}
shellpath := filepath.Join(outdir, repo+".sh")
// only write out if forced to, OR if output is effectively different
// than what the file has.
if forceWrite || shell.ShouldWriteFile(shellpath, shellcode) {
if err = ioutil.WriteFile(shellpath, shellcode, 0644); err != nil {
return err
}
}
// we did it!
return nil
})
return rooterr
}