-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement the extract of hack scripts
Signed-off-by: Chris Suszyński <ksuszyns@redhat.com>
- Loading branch information
Showing
23 changed files
with
982 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package cli_test | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"knative.dev/hack/pkg/inflator/cli" | ||
"knative.dev/hack/pkg/inflator/extract" | ||
) | ||
|
||
func TestApp(t *testing.T) { | ||
tmpdir := t.TempDir() | ||
t.Setenv(extract.ArtifactsEnvVar, tmpdir) | ||
c := cli.App{}.Command() | ||
var ( | ||
outb bytes.Buffer | ||
errb bytes.Buffer | ||
) | ||
c.SetOut(&outb) | ||
c.SetErr(&errb) | ||
c.SetArgs([]string{"e2e-tests.sh"}) | ||
err := c.Execute() | ||
|
||
require.NoError(t, err) | ||
assert.Equal(t, outb.String(), tmpdir+"/hack-scripts/e2e-tests.sh\n") | ||
assert.Equal(t, errb.String(), "") | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package extract | ||
|
||
import ( | ||
"io/fs" | ||
"math" | ||
"os" | ||
"path" | ||
"strings" | ||
|
||
"knative.dev/hack" | ||
) | ||
|
||
const ( | ||
// ArtifactsEnvVar is the name of the environment variable that points | ||
// to ARTIFACTS directory. | ||
ArtifactsEnvVar = "ARTIFACTS" | ||
// PermOwnerWrite is the permission bits for owner write. | ||
PermOwnerWrite = 0o200 | ||
// PermAllExecutable is the permission bits for executable. | ||
PermAllExecutable = 0o111 | ||
) | ||
|
||
// Printer is an interface for printing messages. | ||
type Printer interface { | ||
Print(i ...interface{}) | ||
Println(i ...interface{}) | ||
Printf(format string, i ...interface{}) | ||
PrintErr(i ...interface{}) | ||
PrintErrln(i ...interface{}) | ||
PrintErrf(format string, i ...interface{}) | ||
} | ||
|
||
// Operation is the main extract object that can extract scripts. | ||
type Operation struct { | ||
// ScriptName is the name of the script to extract. | ||
ScriptName string | ||
// Verbose will print more information. | ||
Verbose bool | ||
} | ||
|
||
// Extract will extract a script from the library to a temporary directory and | ||
// provide the file path to it. | ||
func (o Operation) Extract(prtr Printer) error { | ||
l := logger{o.Verbose, prtr} | ||
artifactsDir := os.Getenv(ArtifactsEnvVar) | ||
if artifactsDir == "" { | ||
var err error | ||
if artifactsDir, err = os.MkdirTemp("", "knative.*"); err != nil { | ||
return wrapErr(err, ErrBug) | ||
} | ||
} | ||
hackRootDir := path.Join(artifactsDir, "hack-scripts") | ||
l.debugf("Extracting hack scripts to directory: %s", hackRootDir) | ||
if err := copyDir(l, hack.Scripts, hackRootDir, "."); err != nil { | ||
return err | ||
} | ||
scriptPath := path.Join(hackRootDir, o.ScriptName) | ||
l.Println(scriptPath) | ||
return nil | ||
} | ||
|
||
func copyDir(l logger, inputFS fs.ReadDirFS, destRootDir, dir string) error { | ||
return wrapErr(fs.WalkDir(inputFS, dir, func(filePath string, dirEntry fs.DirEntry, err error) error { | ||
if err != nil { | ||
return wrapErr(err, ErrBug) | ||
} | ||
return copyFile(l, inputFS, destRootDir, filePath, dirEntry) | ||
}), ErrUnexpected) | ||
} | ||
|
||
func copyFile( | ||
l logger, | ||
inputFS fs.ReadDirFS, | ||
destRootDir, filePath string, | ||
dirEntry fs.DirEntry, | ||
) error { | ||
inputFI, err := dirEntry.Info() | ||
if err != nil { | ||
return wrapErr(err, ErrBug) | ||
} | ||
|
||
destPath := path.Join(destRootDir, filePath) | ||
perm := inputFI.Mode().Perm() | ||
|
||
perm |= PermOwnerWrite | ||
if dirEntry.IsDir() { | ||
perm |= PermAllExecutable | ||
if err = os.MkdirAll(destPath, perm); err != nil { | ||
return wrapErr(err, ErrUnexpected) | ||
} | ||
return nil | ||
} | ||
|
||
var ( | ||
inputCS checksum | ||
destCS checksum | ||
destFI fs.FileInfo | ||
bytes []byte | ||
) | ||
inputCS = asChecksum(inputFI) | ||
if destFI, err = os.Stat(destPath); err != nil { | ||
if !os.IsNotExist(err) { | ||
return wrapErr(err, ErrUnexpected) | ||
} | ||
} else { | ||
destCS = asChecksum(destFI) | ||
} | ||
if inputCS == destCS { | ||
l.debugf("%-30s up-to-date", filePath) | ||
return nil | ||
} | ||
if bytes, err = fs.ReadFile(inputFS, filePath); err != nil { | ||
return wrapErr(err, ErrBug) | ||
} | ||
if err = os.WriteFile(destPath, bytes, perm); err != nil { | ||
return wrapErr(err, ErrUnexpected) | ||
} | ||
|
||
sizeKB := int(inputFI.Size() / 1024) | ||
size5k := int(math.Ceil(float64(sizeKB) / 5)) | ||
l.debugf("%-30s %3d KiB %s", filePath, sizeKB, strings.Repeat("+", size5k)) | ||
return nil | ||
} | ||
|
||
func asChecksum(f fs.FileInfo) checksum { | ||
return checksum{ | ||
exists: true, | ||
size: f.Size(), | ||
} | ||
} | ||
|
||
type checksum struct { | ||
exists bool | ||
size int64 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package extract_test | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"knative.dev/hack/pkg/inflator/extract" | ||
) | ||
|
||
func TestExtract(t *testing.T) { | ||
tmpdir := t.TempDir() | ||
t.Setenv(extract.ArtifactsEnvVar, tmpdir) | ||
op := extract.Operation{ | ||
ScriptName: "library.sh", | ||
Verbose: true, | ||
} | ||
prtr := &testPrinter{} | ||
err := op.Extract(prtr) | ||
require.NoError(t, err) | ||
assert.Equal(t, prtr.out.String(), tmpdir+"/hack-scripts/library.sh\n") | ||
assert.Equal(t, | ||
`[hack] Extracting hack scripts to directory: /tmp/x/hack-scripts | ||
[hack] codegen-library.sh 1 KiB + | ||
[hack] e2e-tests.sh 6 KiB ++ | ||
[hack] infra-library.sh 5 KiB + | ||
[hack] library.sh 33 KiB +++++++ | ||
[hack] microbenchmarks.sh 2 KiB + | ||
[hack] performance-tests.sh 6 KiB ++ | ||
[hack] presubmit-tests.sh 12 KiB +++ | ||
[hack] release.sh 26 KiB ++++++ | ||
[hack] shellcheck-presubmit.sh 1 KiB + | ||
`, strings.ReplaceAll(prtr.err.String(), tmpdir, "/tmp/x")) | ||
|
||
// second time should be a no-op | ||
prtr = &testPrinter{} | ||
err = op.Extract(prtr) | ||
require.NoError(t, err) | ||
assert.Equal(t, prtr.out.String(), tmpdir+"/hack-scripts/library.sh\n") | ||
assert.Equal(t, | ||
`[hack] Extracting hack scripts to directory: /tmp/x/hack-scripts | ||
[hack] codegen-library.sh up-to-date | ||
[hack] e2e-tests.sh up-to-date | ||
[hack] infra-library.sh up-to-date | ||
[hack] library.sh up-to-date | ||
[hack] microbenchmarks.sh up-to-date | ||
[hack] performance-tests.sh up-to-date | ||
[hack] presubmit-tests.sh up-to-date | ||
[hack] release.sh up-to-date | ||
[hack] shellcheck-presubmit.sh up-to-date | ||
`, strings.ReplaceAll(prtr.err.String(), tmpdir, "/tmp/x")) | ||
} | ||
|
||
type testPrinter struct { | ||
out bytes.Buffer | ||
err bytes.Buffer | ||
} | ||
|
||
func (t *testPrinter) Print(i ...interface{}) { | ||
_, _ = fmt.Fprint(&t.out, i...) | ||
} | ||
|
||
func (t *testPrinter) Println(i ...interface{}) { | ||
t.Print(fmt.Sprintln(i...)) | ||
} | ||
|
||
func (t *testPrinter) Printf(format string, i ...interface{}) { | ||
t.Print(fmt.Sprintf(format, i...)) | ||
} | ||
|
||
func (t *testPrinter) PrintErr(i ...interface{}) { | ||
_, _ = fmt.Fprint(&t.err, i...) | ||
} | ||
|
||
func (t *testPrinter) PrintErrln(i ...interface{}) { | ||
t.PrintErr(fmt.Sprintln(i...)) | ||
} | ||
|
||
func (t *testPrinter) PrintErrf(format string, i ...interface{}) { | ||
t.PrintErr(fmt.Sprintf(format, i...)) | ||
} |
File renamed without changes.
Oops, something went wrong.