copy
API
copy
packageAPI reference for the copy
package.
Imports
(11)
S
struct
rule
cmd/rfw/plugins/copy/copy.go:20-23
type rule struct
Fields
| Name | Type | Description |
|---|---|---|
| From | string | json:"from" |
| To | string | json:"to" |
S
struct
plugin
cmd/rfw/plugins/copy/copy.go:25-27
type plugin struct
Methods
Build
Method
Parameters
raw
json.RawMessage
Returns
err
error
func (*plugin) Build(raw json.RawMessage) (err error)
{
cfg := struct {
Files []rule `json:"files"`
}{}
if len(raw) > 0 {
if err := json.Unmarshal(raw, &cfg); err != nil {
return err
}
}
p.rules = cfg.Files
projectRoot, err := os.OpenRoot(".")
if err != nil {
return err
}
defer func() {
if closeErr := projectRoot.Close(); err == nil {
err = closeErr
}
}()
for _, r := range p.rules {
if err := validateRule(r); err != nil {
return err
}
matches, err := doublestar.Glob(os.DirFS("."), r.From)
if err != nil {
return err
}
base, _ := doublestar.SplitPattern(r.From)
base = filepath.FromSlash(base)
for _, m := range matches {
path := filepath.FromSlash(m)
info, err := os.Stat(path)
if err != nil {
return err
}
if info.IsDir() {
continue
}
rel, err := filepath.Rel(base, path)
if err != nil {
return err
}
dst := filepath.Join(r.To, rel)
destinationDirectory := filepath.Dir(dst)
if err := projectRoot.MkdirAll(destinationDirectory, 0o755); err != nil {
return err
}
if err := copyFile(projectRoot, path, dst); err != nil {
return err
}
logging.Log.Info("copied file", logging.F("plugin", "copy"), logging.F("path", dst))
}
}
return nil
}
ShouldRebuild
Method
Parameters
path
string
Returns
bool
func (*plugin) ShouldRebuild(path string) bool
{
for _, r := range p.rules {
if ok, _ := doublestar.PathMatch(r.From, path); ok {
return true
}
}
return false
}
Fields
| Name | Type | Description |
|---|---|---|
| rules | []rule |
F
function
init
cmd/rfw/plugins/copy/copy.go:29-29
func init()
{ plugins.Register(&plugin{}) }
F
function
validateRule
Parameters
copyRule
Returns
error
cmd/rfw/plugins/copy/copy.go:100-114
func validateRule(copyRule rule) error
{
for field, value := range map[string]string{"from": copyRule.From, "to": copyRule.To} {
if value == "" || filepath.IsAbs(value) {
return fmt.Errorf("copy %s path %q must be project-relative", field, value)
}
for _, segment := range strings.FieldsFunc(filepath.Clean(value), func(char rune) bool {
return char == '/' || char == '\\'
}) {
if segment == ".." {
return fmt.Errorf("copy %s path %q escapes the project", field, value)
}
}
}
return nil
}
Uses
F
function
copyFile
Parameters
Returns
error
cmd/rfw/plugins/copy/copy.go:116-131
func copyFile(projectRoot *os.Root, src, dst string) error
{
in, err := projectRoot.Open(src)
if err != nil {
return err
}
if err := projectRoot.Remove(dst); err != nil && !errors.Is(err, os.ErrNotExist) {
return errors.Join(err, in.Close())
}
out, err := projectRoot.OpenFile(dst, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
if err != nil {
return errors.Join(err, in.Close())
}
_, copyErr := io.Copy(out, in)
closeErr := errors.Join(out.Close(), in.Close())
return errors.Join(copyErr, closeErr)
}
F
function
TestBuildAndShouldRebuild
TestBuildAndShouldRebuild ensures files matching patterns are copied
and rebuilds are triggered for matched paths.
Parameters
t
cmd/rfw/plugins/copy/copy_test.go:14-69
func TestBuildAndShouldRebuild(t *testing.T)
{
p := &plugin{}
tmp := t.TempDir()
t.Chdir(tmp)
srcRoot := filepath.Join("examples", "components")
if err := os.MkdirAll(filepath.Join(srcRoot, "templates"), 0o750); err != nil {
t.Fatalf("mkdir: %v", err)
}
fileA := filepath.Join(srcRoot, "comp.txt")
if err := os.WriteFile(fileA, []byte("a"), 0o600); err != nil {
t.Fatalf("write: %v", err)
}
fileB := filepath.Join(srcRoot, "templates", "tpl.txt")
if err := os.WriteFile(fileB, []byte("b"), 0o600); err != nil {
t.Fatalf("write: %v", err)
}
destRoot := filepath.Join("build", "static", "examples", "components")
cfg := struct {
Files []struct {
From string `json:"from"`
To string `json:"to"`
} `json:"files"`
}{
Files: []struct {
From string `json:"from"`
To string `json:"to"`
}{{
From: filepath.Join(srcRoot, "**", "*"),
To: destRoot,
}},
}
raw, err := json.Marshal(cfg)
if err != nil {
t.Fatal(err)
}
if err := p.Build(raw); err != nil {
t.Fatalf("Build: %v", err)
}
if data, err := os.ReadFile("build/static/examples/components/comp.txt"); err != nil || string(data) != "a" {
t.Fatalf("comp.txt not copied: %v %s", err, data)
}
if data, err := os.ReadFile("build/static/examples/components/templates/tpl.txt"); err != nil || string(data) != "b" {
t.Fatalf("tpl.txt not copied: %v %s", err, data)
}
if !p.ShouldRebuild(fileA) {
t.Fatalf("expected ShouldRebuild true for %s", fileA)
}
if p.ShouldRebuild(filepath.Join("other.txt")) {
t.Fatalf("unexpected rebuild for unrelated file")
}
}
F
function
TestBuildRejectsPathsOutsideProject
Parameters
t
cmd/rfw/plugins/copy/copy_test.go:71-88
func TestBuildRejectsPathsOutsideProject(t *testing.T)
{
p := &plugin{}
for _, copyRule := range []rule{
{From: "../*", To: "build"},
{From: "*", To: "../build"},
{From: "*", To: filepath.Join(t.TempDir(), "build")},
} {
raw, err := json.Marshal(struct {
Files []rule `json:"files"`
}{Files: []rule{copyRule}})
if err != nil {
t.Fatal(err)
}
if err := p.Build(raw); err == nil {
t.Errorf("expected rule %+v to be rejected", copyRule)
}
}
}