Skip to content

Commit

Permalink
Rename CopyIfChanged to WriteIfNeeded and clarify comments
Browse files Browse the repository at this point in the history
  • Loading branch information
pjcdawkins committed Jan 15, 2025
1 parent caa330b commit 4db1dae
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 18 deletions.
14 changes: 7 additions & 7 deletions internal/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
"os"
)

// CopyIfChanged copies source data to a destination filename if it has changed.
func CopyIfChanged(destFilename string, source []byte, perm os.FileMode) error {
matches, err := probablyMatches(destFilename, source)
// WriteIfNeeded writes data to a destination file, only if the file does not exist or if it was partially written.
// To save time, it only checks that the file size is correct, and then matches the end of its contents (up to 32KB).
func WriteIfNeeded(destFilename string, source []byte, perm os.FileMode) error {
matches, err := probablyMatches(destFilename, source, 32*1024)
if err != nil || matches {
return err
}
Expand All @@ -27,9 +28,8 @@ func Write(path string, content []byte, fileMode fs.FileMode) error {
return os.Rename(tmpFile, path)
}

// probablyMatches checks, heuristically, if a file matches source data.
// To save time, it only compares the file size and the end of its contents (up to 32KB).
func probablyMatches(filename string, data []byte) (bool, error) {
// probablyMatches checks if a file exists and matches the end of source data (up to checkSize bytes).
func probablyMatches(filename string, data []byte, checkSize int) (bool, error) {
f, err := os.Open(filename)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
Expand All @@ -47,7 +47,7 @@ func probablyMatches(filename string, data []byte) (bool, error) {
return false, nil
}

return matchEndOfFile(f, data, 32*1024)
return matchEndOfFile(f, data, checkSize)
}

func matchEndOfFile(f *os.File, b []byte, size int) (bool, error) {
Expand Down
16 changes: 9 additions & 7 deletions internal/file/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestCopyIfChanged(t *testing.T) {
func TestWriteIfNeeded(t *testing.T) {
largeContentLength := 128 * 1024
largeContent := make([]byte, largeContentLength)
largeContent[0] = 'f'
Expand Down Expand Up @@ -50,24 +50,26 @@ func TestCopyIfChanged(t *testing.T) {
time.Sleep(time.Millisecond * 5)
}

var modTimeBeforeCopy time.Time
var modTimeBefore time.Time
stat, err := os.Stat(destFile)
if c.initialData == nil {
require.True(t, os.IsNotExist(err))
} else {
require.NoError(t, err)
modTimeBeforeCopy = stat.ModTime()
modTimeBefore = stat.ModTime()
}

err = CopyIfChanged(destFile, c.sourceData, 0o600)
err = WriteIfNeeded(destFile, c.sourceData, 0o600)
require.NoError(t, err)

statAfterCopy, err := os.Stat(destFile)
statAfter, err := os.Stat(destFile)
require.NoError(t, err)
modTimeAfter := statAfter.ModTime()

if c.expectWrite {
assert.Greater(t, statAfterCopy.ModTime().Truncate(time.Millisecond), modTimeBeforeCopy.Truncate(time.Millisecond))
assert.Greater(t, modTimeAfter.Truncate(time.Millisecond), modTimeBefore.Truncate(time.Millisecond))
} else {
assert.Equal(t, modTimeBeforeCopy.Truncate(time.Millisecond), statAfterCopy.ModTime().Truncate(time.Millisecond))
assert.Equal(t, modTimeBefore.Truncate(time.Millisecond), modTimeAfter.Truncate(time.Millisecond))
}

data, err := os.ReadFile(destFile)
Expand Down
4 changes: 2 additions & 2 deletions internal/legacy/legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (c *CLIWrapper) init() error {

g := errgroup.Group{}
g.Go(func() error {
if err := file.CopyIfChanged(c.pharPath(cacheDir), phar, 0o644); err != nil {
if err := file.WriteIfNeeded(c.pharPath(cacheDir), phar, 0o644); err != nil {
return fmt.Errorf("could not copy phar file: %w", err)
}
return nil
Expand All @@ -90,7 +90,7 @@ func (c *CLIWrapper) init() error {
if err != nil {
return fmt.Errorf("could not load config for checking: %w", err)
}
if err := file.CopyIfChanged(filepath.Join(cacheDir, configBasename), configContent, 0o644); err != nil {
if err := file.WriteIfNeeded(filepath.Join(cacheDir, configBasename), configContent, 0o644); err != nil {
return fmt.Errorf("could not write config: %w", err)
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion internal/legacy/php_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

// copyPHP to destination, if it does not exist
func (c *CLIWrapper) copyPHP(cacheDir string) error {
return file.CopyIfChanged(c.phpPath(cacheDir), phpCLI, 0o755)
return file.WriteIfNeeded(c.phpPath(cacheDir), phpCLI, 0o755)
}

// phpPath returns the path to the temporary PHP-CLI binary
Expand Down
2 changes: 1 addition & 1 deletion internal/legacy/php_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (c *CLIWrapper) copyPHP(cacheDir string) error {
return err
}

if err := file.CopyIfChanged(filepath.Join(destDir, "extras", "cacert.pem"), caCert, 0o644); err != nil {
if err := file.WriteIfNeeded(filepath.Join(destDir, "extras", "cacert.pem"), caCert, 0o644); err != nil {
return err
}

Expand Down

0 comments on commit 4db1dae

Please sign in to comment.