fix: ensure all copied files always have line endings converted to unix-style
Closes #6490
This commit is contained in:
@@ -5,7 +5,6 @@ go 1.21
|
||||
require (
|
||||
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/otiai10/copy v1.14.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
golang.org/x/sync v0.6.0
|
||||
)
|
||||
@@ -21,6 +20,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/melbahja/goph v1.4.0 // indirect
|
||||
github.com/otiai10/copy v1.14.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.5 // indirect
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/otiai10/copy"
|
||||
)
|
||||
|
||||
// TriggerAppJSONProcessDeployParallelism returns the max number of processes to deploy in parallel
|
||||
@@ -120,12 +119,12 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error {
|
||||
return common.TouchFile(fmt.Sprintf("%s.missing", processSpecificAppJSON))
|
||||
}
|
||||
|
||||
if err := copy.Copy(repoAppJSONPath, processSpecificAppJSON); err != nil {
|
||||
if err := common.Copy(repoAppJSONPath, processSpecificAppJSON); err != nil {
|
||||
return fmt.Errorf("Unable to extract app.json: %v", err.Error())
|
||||
}
|
||||
|
||||
if appJSONPath != "app.json" {
|
||||
if err := copy.Copy(repoAppJSONPath, repoDefaultAppJSONPath); err != nil {
|
||||
if err := common.Copy(repoAppJSONPath, repoDefaultAppJSONPath); err != nil {
|
||||
return fmt.Errorf("Unable to move app.json into place: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ go 1.21
|
||||
|
||||
require (
|
||||
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
|
||||
github.com/otiai10/copy v1.14.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
)
|
||||
|
||||
@@ -19,6 +18,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/melbahja/goph v1.4.0 // indirect
|
||||
github.com/otiai10/copy v1.14.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.5 // indirect
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/otiai10/copy"
|
||||
)
|
||||
|
||||
// TriggerBuilderDetect outputs a manually selected builder for the app
|
||||
@@ -79,7 +78,7 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error {
|
||||
return fmt.Errorf("Unable to clear out temporary working directory for rewrite: %v", err.Error())
|
||||
}
|
||||
|
||||
if err := copy.Copy(newSourceWorkDir, tmpWorkDir); err != nil {
|
||||
if err := common.Copy(newSourceWorkDir, tmpWorkDir); err != nil {
|
||||
return fmt.Errorf("Unable to move build-dir to temporary working directory: %v", err.Error())
|
||||
}
|
||||
|
||||
@@ -87,7 +86,7 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error {
|
||||
return fmt.Errorf("Unable to clear out sourcecode working directory for rewrite: %v", err.Error())
|
||||
}
|
||||
|
||||
if err := copy.Copy(tmpWorkDir, sourceWorkDir); err != nil {
|
||||
if err := common.Copy(tmpWorkDir, sourceWorkDir); err != nil {
|
||||
return fmt.Errorf("Unable to move build-dir to sourcecode working directory: %v", err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/otiai10/copy"
|
||||
)
|
||||
|
||||
// CreateAppDataDirectory creates a data directory for the given plugin/app combination with the correct permissions
|
||||
@@ -68,7 +66,7 @@ func CloneAppData(pluginName string, oldAppName string, newAppName string) error
|
||||
}
|
||||
|
||||
newDataDir := GetAppDataDirectory(pluginName, newAppName)
|
||||
if err := copy.Copy(oldDataDir, newDataDir); err != nil {
|
||||
if err := Copy(oldDataDir, newDataDir); err != nil {
|
||||
return fmt.Errorf("Unable to clone app data to new location: %v", err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ func CopyFromImage(appName string, image string, source string, destination stri
|
||||
return fmt.Errorf("Unable to copy file %s from image", source)
|
||||
}
|
||||
|
||||
// workaround for CHECKS file when owner is root. seems to only happen when running inside docker
|
||||
// workaround when owner is root. seems to only happen when running inside docker
|
||||
dos2unixCmd := NewShellCmd(strings.Join([]string{
|
||||
"dos2unix",
|
||||
"-l",
|
||||
|
||||
@@ -3,11 +3,12 @@ package common
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/otiai10/copy"
|
||||
)
|
||||
|
||||
// CatFile cats the contents of a file (if it exists)
|
||||
@@ -24,66 +25,41 @@ func CatFile(filename string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// Copy copies a file/directory from src to dst. If the source is a file, it will also
|
||||
// convert line endings to unix style
|
||||
func Copy(src, dst string) error {
|
||||
fi, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
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 !fi.Mode().IsRegular() {
|
||||
return copy.Copy(src, dst)
|
||||
}
|
||||
|
||||
// ensure file has the correct line endings
|
||||
dos2unixCmd := NewShellCmd(strings.Join([]string{
|
||||
"dos2unix",
|
||||
"-l",
|
||||
"-n",
|
||||
src,
|
||||
dst,
|
||||
}, " "))
|
||||
dos2unixCmd.ShowOutput = false
|
||||
dos2unixCmd.Execute()
|
||||
|
||||
// ensure file permissions are correct
|
||||
b, err := os.ReadFile(dst)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
out, err := os.Create(dst)
|
||||
|
||||
err = os.WriteFile(dst, b, fi.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
cerr := out.Close()
|
||||
if err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
if _, err = io.Copy(out, in); err != nil {
|
||||
return
|
||||
}
|
||||
err = out.Sync()
|
||||
return
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DirectoryExists returns if a path exists and is a directory
|
||||
|
||||
@@ -8,7 +8,6 @@ require (
|
||||
github.com/dokku/dokku/plugins/config v0.0.0-00010101000000-000000000000
|
||||
github.com/dokku/dokku/plugins/docker-options v0.0.0-00010101000000-000000000000
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/otiai10/copy v1.14.0
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible
|
||||
github.com/spf13/pflag v1.0.5
|
||||
)
|
||||
@@ -24,6 +23,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/melbahja/goph v1.4.0 // indirect
|
||||
github.com/otiai10/copy v1.14.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.5 // indirect
|
||||
golang.org/x/crypto v0.18.0 // indirect
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
|
||||
"github.com/otiai10/copy"
|
||||
)
|
||||
|
||||
// TriggerAppRestart restarts an app
|
||||
@@ -90,12 +89,12 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error {
|
||||
return common.TouchFile(fmt.Sprintf("%s.missing", processSpecificProcfile))
|
||||
}
|
||||
|
||||
if err := copy.Copy(repoProcfilePath, processSpecificProcfile); err != nil {
|
||||
if err := common.Copy(repoProcfilePath, processSpecificProcfile); err != nil {
|
||||
return fmt.Errorf("Unable to extract Procfile: %v", err.Error())
|
||||
}
|
||||
|
||||
if procfilePath != "Procfile" {
|
||||
if err := copy.Copy(repoProcfilePath, repoDefaultProcfilePath); err != nil {
|
||||
if err := common.Copy(repoProcfilePath, repoDefaultProcfilePath); err != nil {
|
||||
return fmt.Errorf("Unable to move Procfile into place: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,13 @@ EOF
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
|
||||
@test "(ps) handle windows newlines in procfile" {
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP procfile_line_endings_to_windows
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "(ps:restart-policy) default policy" {
|
||||
run /bin/bash -c "dokku --quiet ps:report $TEST_APP --ps-restart-policy"
|
||||
echo "output: $output"
|
||||
@@ -131,3 +138,11 @@ EOF
|
||||
echo "status: $status"
|
||||
assert_output "$test_restart_policy"
|
||||
}
|
||||
|
||||
procfile_line_endings_to_windows() {
|
||||
local APP="$1"
|
||||
local APP_REPO_DIR="$2"
|
||||
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||
echo "setting line endings on Procfile to \n via unix2dos"
|
||||
sed -i -e 's/\r*$/\r/' "$APP_REPO_DIR/Procfile"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user