package build import ( "fmt" "path" "sort" ) // ApplyUser wraps any build.Copy instructions as build.CopyAs using the given // UID/GID. // func ApplyUser(uid uint, gid uint, instructions []Instruction) []Instruction { applied := make([]Instruction, len(instructions)) for i, instruction := range instructions { switch instruction.(type) { case Copy, CopyFrom: applied[i] = CopyAs{uid, gid, instruction} default: applied[i] = instruction } } return applied } // Chown returns a build.Run instruction for setting ownership on the given // path. // func Chown(uid uint, gid uint, path string) Run { return Run{"chown %s:%s", []string{fmt.Sprint(uid), fmt.Sprint(gid), path}} } // CreateDirectories returns a build.Run instruction for creating all the // given directories. // func CreateDirectories(paths []string) Run { return Run{"mkdir -p", paths} } // CreateDirectory returns a build.Run instruction for creating the given // directory. // func CreateDirectory(path string) Run { return CreateDirectories([]string{path}) } // CreateUser returns build.Run instructions for creating the given user // account and group. // func CreateUser(name string, uid uint, gid uint) []Run { return []Run{ {"groupadd -o -g %s -r", []string{fmt.Sprint(gid), name}}, {"useradd -o -m -d %s -r -g %s -u %s", []string{homeDir(name), name, fmt.Sprint(uid), name}}, } } // Home returns a build.Env instruction for setting the user's home directory. // func Home(name string) Env { return Env{map[string]string{"HOME": homeDir(name)}} } func homeDir(name string) string { if name == "root" { return "/root" } return "/home/" + name } // SortFilesByDir returns both the given files indexed by parent directory and // a sorted slice of those parent directories. The latter is useful in // ensuring deterministic iteration since the ordering of map keys is not // guaranteed. // func SortFilesByDir(files []string) ([]string, map[string][]string) { bydir := make(map[string][]string) for _, file := range files { dir := path.Dir(file) + "/" file = path.Clean(file) if dirfiles, found := bydir[dir]; found { bydir[dir] = append(dirfiles, file) } else { bydir[dir] = []string{file} } } dirs := make([]string, len(bydir)) i := 0 for dir := range bydir { dirs[i] = dir i++ } sort.Strings(dirs) return dirs, bydir } // SyncFiles returns build instructions to copy over the given files after // creating their parent directories. Parent directories are created in a // sorted order. // func SyncFiles(files []string, dest string) []Instruction { if len(files) < 1 { return []Instruction{} } dirs, bydir := SortFilesByDir(files) mkdirs := []string{} copies := make([]Instruction, len(dirs)) // make project subdirectories for requirements files if necessary, and // copy in requirements files for i, dir := range dirs { fulldir := dest + "/" + dir fulldir = path.Clean(fulldir) + "/" if dir != "./" { mkdirs = append(mkdirs, fulldir) } copies[i] = Copy{bydir[dir], fulldir} } ins := []Instruction{} if len(mkdirs) > 0 { ins = append(ins, CreateDirectories(mkdirs)) } return append(ins, copies...) }