Skip to content

Commit

Permalink
Always copy PHP and legacy CLI files if they have changed
Browse files Browse the repository at this point in the history
  • Loading branch information
pjcdawkins committed Dec 29, 2024
1 parent 8fc58ce commit 3bd3c31
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 170 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
touch internal/legacy/archives/php_darwin_amd64
touch internal/legacy/archives/php_darwin_arm64
touch internal/config/embedded-config.yaml
touch internal/legacy/archives/php_windows.zip.sha256
- name: Run linter
uses: golangci/golangci-lint-action@v3
Expand Down
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,21 @@ internal/legacy/archives/php_linux_$(GOARCH):
--progress=plain \
ext/static-php-cli/docker

PHP_WINDOWS_REMOTE_FILENAME := "php-$(PHP_VERSION)-nts-Win32-vs16-x64.zip"
internal/legacy/archives/php_windows.zip:
mkdir -p internal/legacy/archives
wget https://windows.php.net/downloads/releases/php-$(PHP_VERSION)-nts-Win32-vs16-x64.zip -O internal/legacy/archives/php_windows.zip
( \
mkdir -p internal/legacy/archives ;\
cd internal/legacy/archives ;\
# Using curl (instead of wget) because it's built in to things like Git Bash.
curl "https://windows.php.net/downloads/releases/$(PHP_WINDOWS_REMOTE_FILENAME)" > php_windows.zip ;\
curl https://windows.php.net/downloads/releases/sha256sum.txt | grep "$(PHP_WINDOWS_REMOTE_FILENAME)" | sed s/"$(PHP_WINDOWS_REMOTE_FILENAME)"/"php_windows.zip"/g > php_windows.zip.sha256 ;\
sha256sum -c php_windows.zip.sha256 ;\
)

.PHONY: internal/legacy/archives/cacert.pem
internal/legacy/archives/cacert.pem:
mkdir -p internal/legacy/archives
wget https://curl.se/ca/cacert.pem -O internal/legacy/archives/cacert.pem
curl https://curl.se/ca/cacert.pem > internal/legacy/archives/cacert.pem

php: $(PHP_BINARY_PATH)

Expand Down
19 changes: 1 addition & 18 deletions commands/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ package commands

import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"path"
"strings"

"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/spf13/viper"

Expand Down Expand Up @@ -39,21 +35,8 @@ func newCompletionCommand(cnf *config.Config) *cobra.Command {
Stdin: cmd.InOrStdin(),
}

if err := c.Init(); err != nil {
debugLog("%s\n", color.RedString(err.Error()))
os.Exit(1)
return
}

if err := c.Exec(cmd.Context(), completionArgs...); err != nil {
debugLog("%s\n", color.RedString(err.Error()))
exitCode := 1
var execErr *exec.ExitError
if errors.As(err, &execErr) {
exitCode = execErr.ExitCode()
}
os.Exit(exitCode)
return
handleLegacyError(err)
}

completions := strings.ReplaceAll(
Expand Down
25 changes: 3 additions & 22 deletions commands/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package commands
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"

"github.com/fatih/color"
"github.com/spf13/cobra"
Expand All @@ -33,11 +31,6 @@ func newListCommand(cnf *config.Config) *cobra.Command {
Stderr: cmd.ErrOrStderr(),
Stdin: cmd.InOrStdin(),
}
if err := c.Init(); err != nil {
debugLog("%s\n", color.RedString(err.Error()))
os.Exit(1)
return
}

arguments := []string{"list", "--format=json"}
if viper.GetBool("all") {
Expand All @@ -46,15 +39,9 @@ func newListCommand(cnf *config.Config) *cobra.Command {
if len(args) > 0 {
arguments = append(arguments, args[0])
}

if err := c.Exec(cmd.Context(), arguments...); err != nil {
debugLog("%s\n", color.RedString(err.Error()))
exitCode := 1
var execErr *exec.ExitError
if errors.As(err, &execErr) {
exitCode = execErr.ExitCode()
}
os.Exit(exitCode)
return
handleLegacyError(err)
}

var list List
Expand Down Expand Up @@ -99,13 +86,7 @@ func newListCommand(cnf *config.Config) *cobra.Command {
c.Stdout = cmd.OutOrStdout()
arguments := []string{"list", "--format=" + format}
if err := c.Exec(cmd.Context(), arguments...); err != nil {
debugLog("%s\n", color.RedString(err.Error()))
exitCode := 1
var execErr *exec.ExitError
if errors.As(err, &execErr) {
exitCode = execErr.ExitCode()
}
os.Exit(exitCode)
handleLegacyError(err)
}
return
}
Expand Down
24 changes: 12 additions & 12 deletions commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,9 @@ func newRootCommand(cnf *config.Config, assets *vendorization.VendorAssets) *cob
Stderr: cmd.ErrOrStderr(),
Stdin: cmd.InOrStdin(),
}
if err := c.Init(); err != nil {
log.Println(color.RedString(err.Error()))
os.Exit(1)
return
}

if err := c.Exec(cmd.Context(), os.Args[1:]...); err != nil {
debugLog("%s\n", color.RedString(err.Error()))
exitCode := 1
var execErr *exec.ExitError
if errors.As(err, &execErr) {
exitCode = execErr.ExitCode()
}
os.Exit(exitCode)
handleLegacyError(err)
}
},
PersistentPostRun: func(_ *cobra.Command, _ []string) {
Expand Down Expand Up @@ -248,3 +237,14 @@ func debugLog(format string, v ...any) {

log.Printf(format, v...)
}

func handleLegacyError(err error) {
var execErr *exec.ExitError
if errors.As(err, &execErr) {
exitCode := execErr.ExitCode()
debugLog("%s\n", err)
os.Exit(exitCode)
}
log.Println(color.RedString(err.Error()))
os.Exit(1)
}
79 changes: 79 additions & 0 deletions internal/file/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package file

import (
"bytes"
"crypto/sha256"
"encoding/hex"
"io"
"os"
)

// CopyIfChanged copies source data to a destination filename if it has changed.
// It is considered changed if its length or contents are different.
func CopyIfChanged(destFilename string, source []byte, perm os.FileMode) error {
matches, err := compare(destFilename, source)
if (err != nil && !os.IsNotExist(err)) || matches {
return err
}
return os.WriteFile(destFilename, source, perm)
}

// compare checks if a file matches the given source.
func compare(filename string, data []byte) (bool, error) {
f, err := os.Open(filename)
if err != nil {
return false, err
}
defer f.Close()

fi, err := f.Stat()
if err != nil {
return false, err
}
if fi.Size() != int64(len(data)) {
return false, nil
}

var (
buf = make([]byte, 32*1024)
offset = 0
)
for {
n, err := f.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return false, err
}
if offset+n > len(data) || !bytes.Equal(data[offset:offset+n], buf[:n]) {
return false, nil
}
offset += n
}

return offset == len(data), nil
}

// CheckHash checks if a file has the given SHA256 hash.
func CheckHash(filename, hash string) (bool, error) {
fh, err := sha256File(filename)
if err != nil {
return false, err
}
return fh == hash, nil
}

// sha256File calculates the SHA256 hash of a file.
func sha256File(filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
63 changes: 63 additions & 0 deletions internal/file/file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package file

import (
"os"
"path/filepath"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCopyIfChanged(t *testing.T) {
cases := []struct {
name string
initialData []byte
sourceData []byte
expectWrite bool
}{
{"File does not exist", nil, []byte("new data"), true},
{"File matches source", []byte("same data"), []byte("same data"), false},
{"File content differs", []byte("old data"), []byte("new data"), true},
{"File size differs", []byte("short"), []byte("much longer data"), true},
{"Empty source", []byte("existing data"), []byte{}, true},
}

tmpDir := t.TempDir()
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
destFile := filepath.Join(tmpDir, "testfile")

if c.initialData != nil {
require.NoError(t, os.WriteFile(destFile, c.initialData, 0o600))
time.Sleep(time.Millisecond * 5)
}

var modTimeBeforeCopy 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()
}

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

statAfterCopy, err := os.Stat(destFile)
require.NoError(t, err)
if c.expectWrite {
assert.Greater(t, statAfterCopy.ModTime().Truncate(time.Millisecond), modTimeBeforeCopy.Truncate(time.Millisecond))
} else {
assert.Equal(t, modTimeBeforeCopy.Truncate(time.Millisecond), statAfterCopy.ModTime().Truncate(time.Millisecond))
}

data, err := os.ReadFile(destFile)
require.NoError(t, err)

assert.Equal(t, data, c.sourceData)
})
}
}
Loading

0 comments on commit 3bd3c31

Please sign in to comment.