mirror of
https://github.com/dokku/dokku.git
synced 2025-12-16 12:07:45 +01:00
We will no longer support CentOS, Fedora, and Opensuse as installation targets. These are not actively maintained by anyone with commit rights and occasionally cause issues for users as they are not tested during the release process. Rather than have subpar support for an untested operating system, we're removing support for them completely. Users of these operating systems should take a look migration to the docker-based installation method, which will always be tested and supported by the project. Additionally, drop support for Debian 9 as it is now EOL.
237 lines
5.1 KiB
Go
237 lines
5.1 KiB
Go
package common
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/user"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// CatFile cats the contents of a file (if it exists)
|
|
func CatFile(filename string) {
|
|
slice, err := FileToSlice(filename)
|
|
if err != nil {
|
|
LogDebug(fmt.Sprintf("Error cat'ing file %s: %s", filename, err.Error()))
|
|
return
|
|
}
|
|
|
|
for _, line := range slice {
|
|
LogDebug(fmt.Sprintf("line: '%s'", line))
|
|
}
|
|
}
|
|
|
|
// CopyFile copies a file from src to dst. If src and dst files exist, and are
|
|
// the same, then return success. Otherise, attempt to create a hard link
|
|
// between the two files. If that fail, copy the file contents from src to dst.
|
|
// FROM: https://stackoverflow.com/a/21067803/1515875
|
|
func CopyFile(src, dst string) (err error) {
|
|
sfi, err := os.Stat(src)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if !sfi.Mode().IsRegular() {
|
|
// cannot copy non-regular files (e.g., directories,
|
|
// symlinks, devices, etc.)
|
|
return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
|
|
}
|
|
dfi, err := os.Stat(dst)
|
|
if err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return
|
|
}
|
|
} else {
|
|
if !(dfi.Mode().IsRegular()) {
|
|
return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
|
|
}
|
|
if os.SameFile(sfi, dfi) {
|
|
return
|
|
}
|
|
}
|
|
if err = os.Link(src, dst); err == nil {
|
|
return
|
|
}
|
|
err = copyFileContents(src, dst)
|
|
return
|
|
}
|
|
|
|
// copyFileContents copies the contents of the file named src to the file named
|
|
// by dst. The file will be created if it does not already exist. If the
|
|
// destination file exists, all it's contents will be replaced by the contents
|
|
// of the source file.
|
|
// FROM: https://stackoverflow.com/a/21067803/1515875
|
|
func copyFileContents(src, dst string) (err error) {
|
|
in, err := os.Open(src)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer in.Close()
|
|
out, err := os.Create(dst)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer func() {
|
|
cerr := out.Close()
|
|
if err == nil {
|
|
err = cerr
|
|
}
|
|
}()
|
|
if _, err = io.Copy(out, in); err != nil {
|
|
return
|
|
}
|
|
err = out.Sync()
|
|
return
|
|
}
|
|
|
|
// DirectoryExists returns if a path exists and is a directory
|
|
func DirectoryExists(filename string) bool {
|
|
fi, err := os.Stat(filename)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return fi.IsDir()
|
|
}
|
|
|
|
// FileToSlice reads in all the lines from a file into a string slice
|
|
func FileToSlice(filename string) (lines []string, err error) {
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer f.Close()
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
text := strings.TrimSpace(scanner.Text())
|
|
if text == "" {
|
|
continue
|
|
}
|
|
lines = append(lines, text)
|
|
}
|
|
err = scanner.Err()
|
|
return
|
|
}
|
|
|
|
// FileExists returns if a path exists and is a file
|
|
func FileExists(filename string) bool {
|
|
fi, err := os.Stat(filename)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return fi.Mode().IsRegular()
|
|
}
|
|
|
|
// IsAbsPath returns 0 if input path is absolute
|
|
func IsAbsPath(path string) bool {
|
|
return strings.HasPrefix(path, "/")
|
|
}
|
|
|
|
// ListFilesWithPrefix lists files within a given path that have a given prefix
|
|
func ListFilesWithPrefix(path string, prefix string) []string {
|
|
names, err := ioutil.ReadDir(path)
|
|
if err != nil {
|
|
return []string{}
|
|
}
|
|
|
|
files := []string{}
|
|
for _, f := range names {
|
|
if prefix != "" && !strings.HasPrefix(f.Name(), prefix) {
|
|
continue
|
|
}
|
|
|
|
if f.Mode().IsRegular() {
|
|
files = append(files, fmt.Sprintf("%s/%s", path, f.Name()))
|
|
}
|
|
}
|
|
|
|
return files
|
|
}
|
|
|
|
// ReadFirstLine gets the first line of a file that has contents and returns it
|
|
// if there are no contents, an empty string is returned
|
|
// will also return an empty string if the file does not exist
|
|
func ReadFirstLine(filename string) (text string) {
|
|
if !FileExists(filename) {
|
|
return
|
|
}
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer f.Close()
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
if text = strings.TrimSpace(scanner.Text()); text == "" {
|
|
continue
|
|
}
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// SetPermissions sets the proper owner and filemode for a given file
|
|
func SetPermissions(path string, fileMode os.FileMode) error {
|
|
if err := os.Chmod(path, fileMode); err != nil {
|
|
return err
|
|
}
|
|
|
|
systemGroup := GetenvWithDefault("DOKKU_SYSTEM_GROUP", "dokku")
|
|
systemUser := GetenvWithDefault("DOKKU_SYSTEM_USER", "dokku")
|
|
if strings.HasPrefix(path, "/etc/sudoers.d/") {
|
|
systemGroup = "root"
|
|
systemUser = "root"
|
|
}
|
|
|
|
group, err := user.LookupGroup(systemGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user, err := user.Lookup(systemUser)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
uid, err := strconv.Atoi(user.Uid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
gid, err := strconv.Atoi(group.Gid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.Chown(path, uid, gid)
|
|
}
|
|
|
|
// WriteSliceToFile writes a slice of strings to a file
|
|
func WriteSliceToFile(filename string, lines []string) error {
|
|
mode := os.FileMode(0600)
|
|
if strings.HasPrefix(filename, "/etc/sudoers.d/") {
|
|
mode = os.FileMode(0440)
|
|
}
|
|
|
|
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
w := bufio.NewWriter(file)
|
|
for _, line := range lines {
|
|
fmt.Fprintln(w, line)
|
|
}
|
|
if err = w.Flush(); err != nil {
|
|
return err
|
|
}
|
|
|
|
file.Chmod(mode)
|
|
SetPermissions(filename, mode)
|
|
|
|
return nil
|
|
}
|