mirror of
https://github.com/dokku/dokku.git
synced 2025-12-16 12:07:45 +01:00
When git --aggressive is run on a bare repo, it deletes all head refs. This change copies the contents into memory and then writes them out at the end of the repo:gc call. Closes #6973
97 lines
2.5 KiB
Go
97 lines
2.5 KiB
Go
package repo
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/dokku/dokku/plugins/common"
|
|
)
|
|
|
|
// PurgeCacheFailed wraps error to allow returning the correct exit code
|
|
type PurgeCacheFailed struct {
|
|
exitCode int
|
|
}
|
|
|
|
// ExitCode returns an exit code to use in case this error bubbles
|
|
// up into an os.Exit() call
|
|
func (err *PurgeCacheFailed) ExitCode() int {
|
|
return err.exitCode
|
|
}
|
|
|
|
// Error returns a standard non-existent app error
|
|
func (err *PurgeCacheFailed) Error() string {
|
|
return fmt.Sprintf("failed to purge cache, exit code %d", err.exitCode)
|
|
}
|
|
|
|
// PurgeCache deletes the contents of the build cache stored in the repository
|
|
func PurgeCache(appName string) error {
|
|
containerIDs, _ := common.DockerFilterContainers([]string{
|
|
fmt.Sprintf("label=com.dokku.app-name=%v", appName),
|
|
"label=com.dokku.image-stage=build",
|
|
})
|
|
if len(containerIDs) > 0 {
|
|
common.DockerRemoveContainers(containerIDs)
|
|
}
|
|
result, err := common.CallExecCommand(common.ExecCommandInput{
|
|
Command: common.DockerBin(),
|
|
Args: []string{"volume", "rm", "-f", fmt.Sprintf("cache-%s", appName)},
|
|
StreamStderr: true,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to remove cache volume: %w", err)
|
|
}
|
|
if result.ExitCode != 0 {
|
|
return &PurgeCacheFailed{result.ExitCode}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func RepoGc(appName string) error {
|
|
heads := map[string][]byte{}
|
|
headsDir := filepath.Join(common.AppRoot(appName), "refs", "heads")
|
|
if common.DirectoryExists(headsDir) {
|
|
headFiles, err := os.ReadDir(headsDir)
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to read heads directory: %w", err)
|
|
}
|
|
|
|
for _, head := range headFiles {
|
|
if head.IsDir() {
|
|
continue
|
|
}
|
|
headContents, err := os.ReadFile(filepath.Join(headsDir, head.Name()))
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to read head file: %w", err)
|
|
}
|
|
heads[head.Name()] = headContents
|
|
}
|
|
}
|
|
|
|
defer func() {
|
|
for head, contents := range heads {
|
|
if err := os.WriteFile(filepath.Join(headsDir, head), contents, 0644); err != nil {
|
|
common.LogWarn(fmt.Sprintf("Unable to write head file: %s\n", err))
|
|
}
|
|
}
|
|
}()
|
|
appRoot := common.AppRoot(appName)
|
|
result, err := common.CallExecCommand(common.ExecCommandInput{
|
|
Command: "git",
|
|
Args: []string{"gc", "--aggressive"},
|
|
Env: map[string]string{
|
|
"GIT_DIR": appRoot,
|
|
},
|
|
StreamStderr: true,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to run git gc: %w", err)
|
|
}
|
|
if result.ExitCode != 0 {
|
|
return fmt.Errorf("Unable to run git gc: %s", result.StderrContents())
|
|
}
|
|
|
|
return nil
|
|
}
|