Files
fx-serverless/packer/packer.go
Minghe 2298f39cca k3s on docker (#401)
* since we do the image build in initialize container of pod, so we have to make sure the image built can be access from kubelet on same node, containerd could not support that
* update docs
* bump version
* clean up
2019-12-07 01:42:13 +08:00

244 lines
5.1 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package packer
import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/gobuffalo/packr"
"github.com/metrue/fx/utils"
"github.com/otiai10/copy"
)
var presets packr.Box
func init() {
presets = packr.NewBox("./images")
}
// Pack pack a file or directory into a Docker project
func Pack(output string, input ...string) error {
if len(input) == 0 {
return fmt.Errorf("source file or directory required")
}
var lang string
for _, f := range input {
if utils.IsRegularFile(f) {
lang = langFromFileName(f)
} else if utils.IsDir(f) {
if err := filepath.Walk(f, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if utils.IsRegularFile(path) {
lang = langFromFileName(path)
}
return nil
}); err != nil {
return err
}
}
}
if lang == "" {
return fmt.Errorf("could not tell programe language of your input source codes")
}
if err := restore(output, lang); err != nil {
return err
}
if len(input) == 1 {
stat, err := os.Stat(input[0])
if err != nil {
return err
}
if stat.Mode().IsRegular() {
if err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if isHandler(path) {
if err := copy.Copy(input[0], path); err != nil {
return err
}
}
return nil
}); err != nil {
return err
}
}
return nil
}
if !hasFxHandleFile(input...) {
msg := `it requires a fx handle file when input is not a single file function, e.g.  
fx.go for Golang
Fx.java for Java
fx.php for PHP
fx.py for Python
fx.js for JavaScript or Node
fx.rb for Ruby
fx.jl for Julia
fx.d for D`
return fmt.Errorf(msg)
}
if err := merge(output, input...); err != nil {
return err
}
return nil
}
func restore(output string, lang string) error {
for _, name := range presets.List() {
prefix := fmt.Sprintf("%s/", lang)
if strings.HasPrefix(name, prefix) {
content, err := presets.FindString(name)
if err != nil {
return err
}
filePath := filepath.Join(output, strings.Replace(name, prefix, "", 1))
if err := utils.EnsureFile(filePath); err != nil {
return err
}
if err := ioutil.WriteFile(filePath, []byte(content), 0666); err != nil {
return err
}
}
}
return nil
}
func merge(dest string, input ...string) error {
for _, file := range input {
stat, err := os.Stat(file)
if err != nil {
return err
}
if stat.Mode().IsRegular() {
targetFilePath := filepath.Join(dest, stat.Name())
if err := utils.EnsureFile(targetFilePath); err != nil {
return err
}
body, err := ioutil.ReadFile(file)
if err != nil {
return err
}
if err := ioutil.WriteFile(targetFilePath, body, 0644); err != nil {
return err
}
} else if stat.Mode().IsDir() {
if err := filepath.Walk(file, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if err := copy.Copy(file, dest); err != nil {
return err
}
return nil
}); err != nil {
return err
}
}
}
return nil
}
func isHandler(name string) bool {
basename := filepath.Base(name)
nameWithoutExt := strings.TrimSuffix(basename, filepath.Ext(basename))
return nameWithoutExt == "fx" ||
nameWithoutExt == "Fx" || // Fx is for Java
nameWithoutExt == "mod" // mod.rs is for Rust
}
func langFromFileName(fileName string) string {
extLangMap := map[string]string{
".js": "node",
".go": "go",
".rb": "ruby",
".py": "python",
".php": "php",
".jl": "julia",
".java": "java",
".d": "d",
".rs": "rust",
}
return extLangMap[filepath.Ext(fileName)]
}
func hasFxHandleFile(input ...string) bool {
var handleFile string
for _, file := range input {
if utils.IsRegularFile(file) && isHandler(file) {
handleFile = file
break
} else if utils.IsDir(file) {
if err := filepath.Walk(file, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if utils.IsRegularFile(path) && isHandler(info.Name()) {
handleFile = path
}
return nil
}); err != nil {
return false
}
}
}
return handleFile != ""
}
// PackIntoK8SConfigMapFile pack function a K8S config map file
func PackIntoK8SConfigMapFile(dir string) (string, error) {
tree := map[string]string{}
if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
relpath := strings.Replace(path, dir, "", 1)
body, err := ioutil.ReadFile(path)
if err != nil {
return err
}
tree[relpath] = string(body)
}
return nil
}); err != nil {
return "", nil
}
data, err := json.Marshal(tree)
if err != nil {
return "", err
}
return base64.StdEncoding.WithPadding(base64.StdPadding).EncodeToString(data), nil
}
// TreeToDir restore to docker project
func TreeToDir(tree map[string]string, outputDir string) error {
for k, v := range tree {
fn := filepath.Join(outputDir, k)
if err := utils.EnsureFile(fn); err != nil {
return err
}
if err := ioutil.WriteFile(fn, []byte(v), 0666); err != nil {
return err
}
}
return nil
}