summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/instructions.go13
-rw-r--r--build/phases.go14
-rw-r--r--config/apt.go25
-rw-r--r--config/common.go19
-rw-r--r--config/config.go4
-rw-r--r--config/npm.go39
-rw-r--r--config/runs.go40
-rw-r--r--docker/compiler.go29
8 files changed, 131 insertions, 52 deletions
diff --git a/build/instructions.go b/build/instructions.go
new file mode 100644
index 0000000..2676a75
--- /dev/null
+++ b/build/instructions.go
@@ -0,0 +1,13 @@
+package build
+
+type InstructionType int
+
+const (
+ Run InstructionType = iota
+ Copy
+)
+
+type Instruction struct {
+ Type InstructionType
+ Arguments []string
+}
diff --git a/build/phases.go b/build/phases.go
new file mode 100644
index 0000000..095263c
--- /dev/null
+++ b/build/phases.go
@@ -0,0 +1,14 @@
+package build
+
+type Phase int
+
+const (
+ PhasePrivileged Phase = iota
+ PhasePrivilegeDropped
+ PhasePreInstall
+ PhasePostInstall
+)
+
+type PhaseCompileable interface {
+ InstructionsForPhase(phase Phase) []Instruction
+}
diff --git a/config/apt.go b/config/apt.go
index f9e631f..65dad9c 100644
--- a/config/apt.go
+++ b/config/apt.go
@@ -1,8 +1,8 @@
package config
import (
- "bytes"
"strings"
+ "github.com/marxarelli/blubber/build"
)
type AptConfig struct {
@@ -13,16 +13,19 @@ func (apt *AptConfig) Merge(apt2 AptConfig) {
apt.Packages = append(apt.Packages, apt2.Packages...)
}
-func (apt AptConfig) Commands() []string {
- if len(apt.Packages) < 1 {
- return []string{}
+func (apt AptConfig) InstructionsForPhase(phase build.Phase) []build.Instruction {
+ if len(apt.Packages) > 0 {
+ switch phase {
+ case build.PhasePrivileged:
+ return []build.Instruction{
+ {build.Run, []string{
+ "apt-get update && apt-get install -y ",
+ strings.Join(apt.Packages, " "),
+ " && rm -rf /var/lib/apt/lists/*",
+ }},
+ }
+ }
}
- buffer := new(bytes.Buffer)
-
- buffer.WriteString("apt-get update && apt-get install -y ")
- buffer.WriteString(strings.Join(apt.Packages, " "))
- buffer.WriteString(" && rm -rf /var/lib/apt/lists/*")
-
- return []string{buffer.String()}
+ return []build.Instruction{}
}
diff --git a/config/common.go b/config/common.go
index c4dc2db..1073b18 100644
--- a/config/common.go
+++ b/config/common.go
@@ -1,5 +1,9 @@
package config
+import (
+ "github.com/marxarelli/blubber/build"
+)
+
type CommonConfig struct {
Base string `yaml:"base"`
Apt AptConfig `yaml:"apt"`
@@ -24,3 +28,18 @@ func (cc1 *CommonConfig) Merge(cc2 CommonConfig) {
cc1.EntryPoint = cc2.EntryPoint
}
}
+
+
+func (cc *CommonConfig) PhaseCompileableConfig() []build.PhaseCompileable {
+ return []build.PhaseCompileable{cc.Apt, cc.Npm, cc.Runs}
+}
+
+func (cc *CommonConfig) InstructionsForPhase(phase build.Phase) []build.Instruction {
+ instructions := []build.Instruction{}
+
+ for _, phaseCompileable := range cc.PhaseCompileableConfig() {
+ instructions = append(instructions, phaseCompileable.InstructionsForPhase(phase)...)
+ }
+
+ return instructions
+}
diff --git a/config/config.go b/config/config.go
index dcf1adb..ee38ea8 100644
--- a/config/config.go
+++ b/config/config.go
@@ -4,7 +4,3 @@ type Config struct {
CommonConfig `yaml:",inline"`
Variants map[string]VariantConfig `yaml:"variants"`
}
-
-type CommandCompileable interface {
- Commands() []string
-}
diff --git a/config/npm.go b/config/npm.go
index c4a52c1..78307b6 100644
--- a/config/npm.go
+++ b/config/npm.go
@@ -2,8 +2,12 @@ package config
import (
"bytes"
+ "path"
+ "github.com/marxarelli/blubber/build"
)
+const TempNpmInstallDir = "/tmp/node-deps/"
+
type NpmConfig struct {
Install bool `yaml:"install"`
Env string `yaml:"env"`
@@ -17,18 +21,29 @@ func (npm *NpmConfig) Merge(npm2 NpmConfig) {
}
}
-func (npm NpmConfig) Commands() []string {
- if !npm.Install {
- return []string{}
- }
-
- buffer := new(bytes.Buffer)
-
- buffer.WriteString("npm install")
-
- if npm.Env == "production" {
- buffer.WriteString(" --production && npm dedupe")
+func (npm NpmConfig) InstructionsForPhase(phase build.Phase) []build.Instruction{
+ if npm.Install {
+ switch phase {
+ case build.PhasePreInstall:
+ npmCmd := new(bytes.Buffer)
+
+ npmCmd.WriteString("npm install")
+
+ if npm.Env == "production" {
+ npmCmd.WriteString(" --production && npm dedupe")
+ }
+
+ return []build.Instruction{
+ {build.Run, []string{"mkdir -p ", TempNpmInstallDir}},
+ {build.Copy, []string{"package.json", TempNpmInstallDir}},
+ {build.Run, []string{"cd ", TempNpmInstallDir, " && ", npmCmd.String()}},
+ }
+ case build.PhasePostInstall:
+ return []build.Instruction{
+ {build.Run, []string{"mv ", path.Join(TempNpmInstallDir, "node_modules"), " ./"}},
+ }
+ }
}
- return []string{buffer.String()}
+ return []build.Instruction{}
}
diff --git a/config/runs.go b/config/runs.go
index 70f03a9..1d1f63a 100644
--- a/config/runs.go
+++ b/config/runs.go
@@ -2,7 +2,7 @@ package config
import (
"strconv"
- "strings"
+ "github.com/marxarelli/blubber/build"
)
type RunsConfig struct {
@@ -19,26 +19,32 @@ func (run *RunsConfig) Merge(run2 RunsConfig) {
if run2.Gid != 0 { run.Gid = run2.Gid }
}
-func (run RunsConfig) Commands() []string {
- cmds := []string{}
+func (run RunsConfig) InstructionsForPhase(phase build.Phase) []build.Instruction {
+ ins := []build.Instruction{}
- if run.In != "" {
- cmds = append(cmds, strings.Join([]string{"mkdir -p", run.In}, " "))
- }
-
- if run.As != "" {
- cmd := []string{
- "groupadd -o -g", strconv.Itoa(run.Gid), "-r", run.As, "&&",
- "useradd -o -m -r -g", run.As, "-u", strconv.Itoa(run.Uid), run.As,
+ switch phase {
+ case build.PhasePrivileged:
+ if run.In != "" {
+ ins = append(ins, []build.Instruction{{build.Run, []string{"mkdir -p ", run.In}}}...)
}
- cmds = append(cmds, strings.Join(cmd, " "))
-
- if run.In != "" {
- owner := strings.Join([]string{run.As, ":", run.As}, "")
- cmds = append(cmds, strings.Join([]string{"chown", owner, run.In}, " "))
+ if run.As != "" {
+ ins = append(ins, []build.Instruction{
+ {build.Run, []string{
+ "groupadd -o -g ", strconv.Itoa(run.Gid), " -r ", run.As, " && ",
+ "useradd -o -m -r -g ", run.As, " -u ", strconv.Itoa(run.Uid), " ", run.As,
+ }},
+ }...)
+
+ if run.In != "" {
+ ins = append(ins, []build.Instruction{
+ {build.Run, []string{
+ "chown ", run.As, ":", run.As, " ", run.In,
+ }},
+ }...)
+ }
}
}
- return cmds
+ return ins
}
diff --git a/docker/compiler.go b/docker/compiler.go
index f5114c4..6b08355 100644
--- a/docker/compiler.go
+++ b/docker/compiler.go
@@ -3,6 +3,7 @@ package docker
import (
"bytes"
"strings"
+ "github.com/marxarelli/blubber/build"
"github.com/marxarelli/blubber/config"
)
@@ -33,26 +34,27 @@ func CompileStage(buffer *bytes.Buffer, stage string, vcfg *config.VariantConfig
Writeln(buffer, "FROM ", vcfg.Base, " AS ", stage)
Writeln(buffer, "USER root")
- Writeln(buffer, "WORKDIR /srv")
- CompileToCommands(buffer, vcfg.Apt)
- CompileToCommands(buffer, vcfg.Runs)
+
+ CompilePhase(buffer, vcfg, build.PhasePrivileged)
if vcfg.Runs.As != "" {
Writeln(buffer, "USER ", vcfg.Runs.As)
}
+ CompilePhase(buffer, vcfg, build.PhasePrivilegeDropped)
+
if vcfg.Runs.In != "" {
Writeln(buffer, "WORKDIR ", vcfg.Runs.In)
}
+ CompilePhase(buffer, vcfg, build.PhasePreInstall)
+
if vcfg.SharedVolume {
Writeln(buffer, "VOLUME [\"", vcfg.Runs.In, "\"]")
} else {
Writeln(buffer, "COPY . \"", vcfg.Runs.In, "\"")
}
- CompileToCommands(buffer, vcfg.Npm)
-
// Artifact copying
for _, artifact := range vcfg.Artifacts {
Write(buffer, "COPY ")
@@ -64,14 +66,25 @@ func CompileStage(buffer *bytes.Buffer, stage string, vcfg *config.VariantConfig
Writeln(buffer, artifact.Source, " ", artifact.Destination)
}
+ CompilePhase(buffer, vcfg, build.PhasePostInstall)
+
if len(vcfg.EntryPoint) > 0 {
Writeln(buffer, "ENTRYPOINT [\"", strings.Join(vcfg.EntryPoint, "\", \""), "\"]")
}
}
-func CompileToCommands(buffer *bytes.Buffer, compileable config.CommandCompileable) {
- for _, command := range compileable.Commands() {
- Writeln(buffer, "RUN ", command)
+func CompilePhase(buffer *bytes.Buffer, vcfg *config.VariantConfig, phase build.Phase) {
+ for _, instruction := range vcfg.InstructionsForPhase(phase) {
+ CompileInstruction(buffer, instruction)
+ }
+}
+
+func CompileInstruction(buffer *bytes.Buffer, instruction build.Instruction) {
+ switch instruction.Type {
+ case build.Run:
+ Writeln(buffer, append([]string{"RUN "}, instruction.Arguments...)...)
+ case build.Copy:
+ Writeln(buffer, "COPY \"", instruction.Arguments[0], "\" \"", instruction.Arguments[1], "\"")
}
}