Example #1
0
// PrepareBuild prepares a custombuild.Builder for generating a custom binary using
// middlewares. A call to Build on the returned builder will generate the binary.
// If error is not nil, the returned Builder should be ignored.
func PrepareBuild(middlewares features.Middlewares) (custombuild.Builder, error) {
	// create builder
	builder, err := custombuild.NewUnready(CaddyPackage, gen(middlewares), middlewares.Packages())
	if err != nil {
		return builder, err
	}

	// TODO make this configurable and enable only for dev
	builder.UseNetworkForAll(false)

	err = builder.Setup()
	if err != nil {
		// not useful, clear assets
		go builder.Teardown()
		return builder, err
	}

	// necessary to ensure import "github.com/mholt/caddy..." is referencing
	// this code.
	err = builder.SetImportPath(CaddyPackage)
	if err != nil {
		// not useful, clear assets
		go builder.Teardown()
		return builder, err
	}

	return builder, nil
}
Example #2
0
// PrepareBuild prepares a custombuild.Builder for generating a custom binary using
// middlewares. A call to Build on the returned builder will generate the binary.
// If error is not nil, the returned Builder should be ignored.
func PrepareBuild(middlewares features.Middlewares, pullLatest bool) (custombuild.Builder, error) {
	// create builder
	builder, err := custombuild.NewUnready(CaddyPackage, gen(middlewares), middlewares.Packages())
	if err != nil {
		return builder, err
	}

	builder.UseNetworkForAll(pullLatest) // if true, run go get -u for all dependencies before each build

	err = builder.Setup()
	if err != nil {
		// not useful, clear assets
		go builder.Teardown()
		return builder, err
	}

	// necessary to ensure import "github.com/mholt/caddy..." is referencing
	// this code.
	err = builder.SetImportPath(CaddyPackage)
	if err != nil {
		// not useful, clear assets
		go builder.Teardown()
		return builder, err
	}

	return builder, nil
}
Example #3
0
// gen is code generation function that insert custom directives at runtime.
func gen(middlewares features.Middlewares) custombuild.CodeGenFunc {
	return func(src string, packages []string) (err error) {
		// prevent possible panic from assertions.
		defer func() {
			if recover() != nil {
				err = errParse
			}
		}()

		// if no middleware is added, no code generation needed.
		if len(middlewares) == 0 {
			return nil
		}

		fset := token.NewFileSet()
		file := filepath.Join(src, directivesFile)
		f, err := parser.ParseFile(fset, file, nil, 0)
		if err != nil {
			return err
		}
		packageNames, err := getPackageNames(middlewares.Packages())
		if err != nil {
			return err
		}
		for _, m := range middlewares {
			astutil.AddImport(fset, f, m.Package)
		}
		var buf bytes.Buffer
		err = printer.Fprint(&buf, fset, f)
		if err != nil {
			return err
		}

		out := buf.String()

		for _, mid := range middlewares {
			f, err = parser.ParseFile(token.NewFileSet(), "", out, 0)
			node, ok := f.Scope.Lookup("directiveOrder").Decl.(ast.Node)
			if !ok {
				return errParse
			}

			snippet := fmt.Sprintf(`{"%s", %s.Setup},`+"\n", mid.Directive, packageNames[mid.Package])

			// add to end of directives.
			end := int(node.End()) - 2

			// if after is set, locate directive and add after it.
			after := getPrevDirective(mid.Directive)
			if after != "" {
				found := false
				c := node.(*ast.ValueSpec).Values[0].(*ast.CompositeLit)
				for _, m := range c.Elts {
					directive := m.(*ast.CompositeLit).Elts[0].(*ast.BasicLit)
					if strconv.Quote(after) == directive.Value && !found {
						end = int(m.End()) + 1
						found = true
					}
					// check if directive exists
					if strconv.Quote(mid.Directive) == directive.Value {
						return fmt.Errorf("Directive '%s' exists in Caddy core, use a distinct name.", mid.Directive)
					}
				}
				if !found {
					return fmt.Errorf("Cannot place afer %s, directive '%s' not found.", config.After, config.After)
				}
			}

			out = out[:end] + snippet + out[end:]
		}

		return ioutil.WriteFile(file, []byte(out), os.FileMode(0660))
	}
}