fix: ensure all copied files always have line endings converted to unix-style

Closes #6490
This commit is contained in:
Jose Diaz-Gonzalez
2024-01-24 22:43:43 -05:00
parent ea95d71e56
commit b6425ab431
10 changed files with 56 additions and 70 deletions

View File

@@ -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

View File

@@ -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())
}
}

View File

@@ -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

View File

@@ -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())
}

View File

@@ -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())
}

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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())
}
}

View File

@@ -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"
}