From 198bc9290425d229454f0d32d14cdb4fb8b750ce Mon Sep 17 00:00:00 2001 From: Mohammed Al Sahaf Date: Wed, 13 Dec 2023 21:39:32 +0300 Subject: [PATCH] code review --- builder.go | 5 +++- cmd/main.go | 25 +++++++++++++++----- environment.go | 48 ++++++++++++++++++++----------------- io.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 io.go diff --git a/builder.go b/builder.go index 8969f1a..b4badf4 100644 --- a/builder.go +++ b/builder.go @@ -47,7 +47,10 @@ type Builder struct { ModFlags string `json:"mod_flags,omitempty"` // Experimental: subject to change - EmbedDir string `json:"embed_dir,omitempty"` + EmbedDirs []struct { + Dir string `json:"dir,omitempty"` + Name string `json:"name,omitempty"` + } `json:"embed_dir,omitempty"` } // Build builds Caddy at the configured version with the diff --git a/cmd/main.go b/cmd/main.go index e63e35f..de70999 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -71,7 +71,7 @@ func runBuild(ctx context.Context, args []string) error { var argCaddyVersion, output string var plugins []xcaddy.Dependency var replacements []xcaddy.Replace - var embedDir string + var embedDir []string for i := 0; i < len(args); i++ { switch args[i] { case "--with": @@ -110,11 +110,8 @@ func runBuild(ctx context.Context, args []string) error { if i == len(args)-1 { return fmt.Errorf("expected value after --embed flag") } - if embedDir != "" { - return fmt.Errorf("multiple --embed flags specified") - } i++ - embedDir = args[i] + embedDir = append(embedDir, args[i]) default: if argCaddyVersion != "" { return fmt.Errorf("missing flag; caddy version already set at %s", argCaddyVersion) @@ -147,7 +144,23 @@ func runBuild(ctx context.Context, args []string) error { Debug: buildDebugOutput, BuildFlags: buildFlags, ModFlags: modFlags, - EmbedDir: embedDir, + } + for _, md := range embedDir { + if before, after, found := strings.Cut(md, ":"); found { + builder.EmbedDirs = append(builder.EmbedDirs, struct { + Dir string `json:"dir,omitempty"` + Name string `json:"name,omitempty"` + }{ + after, before, + }) + } else { + builder.EmbedDirs = append(builder.EmbedDirs, struct { + Dir string `json:"dir,omitempty"` + Name string `json:"name,omitempty"` + }{ + before, "", + }) + } } err := builder.Build(ctx, output) if err != nil { diff --git a/environment.go b/environment.go index c74bcfb..cc3c37b 100644 --- a/environment.go +++ b/environment.go @@ -91,29 +91,33 @@ func (b Builder) newEnvironment(ctx context.Context) (*environment, error) { return nil, err } - if b.EmbedDir != "" { - if err := utils.Copy(b.EmbedDir, filepath.Join(tempFolder, "files")); err != nil { - return nil, err - } - if _, err := os.Stat(b.EmbedDir); err != nil { - return nil, fmt.Errorf("embed directory does not exist: %s", b.EmbedDir) - } - log.Printf("[INFO] Embedding directory: %s", b.EmbedDir) + if len(b.EmbedDirs) > 0 { + for _, d := range b.EmbedDirs { + err = copy(d.Dir, filepath.Join(tempFolder, "files", d.Name)) + if err != nil { + return nil, err + } + _, err = os.Stat(d.Dir) + if err != nil { + return nil, fmt.Errorf("embed directory does not exist: %s", d.Dir) + } + log.Printf("[INFO] Embedding directory: %s", d.Dir) - var buf bytes.Buffer - tpl, err := template.New("embed").Parse(embeddedModuleTemplate) - if err != nil { - return nil, err - } - err = tpl.Execute(&buf, tplCtx) - if err != nil { - return nil, err - } - log.Printf("[INFO] Writing 'embedded' module: %s\n%s", mainPath, buf.Bytes()) - emedPath := filepath.Join(tempFolder, "embed.go") - err = os.WriteFile(emedPath, buf.Bytes(), 0o644) - if err != nil { - return nil, err + var buf bytes.Buffer + tpl, err := template.New("embed").Parse(embeddedModuleTemplate) + if err != nil { + return nil, err + } + err = tpl.Execute(&buf, tplCtx) + if err != nil { + return nil, err + } + log.Printf("[INFO] Writing 'embedded' module: %s\n%s", mainPath, buf.Bytes()) + emedPath := filepath.Join(tempFolder, "embed.go") + err = os.WriteFile(emedPath, buf.Bytes(), 0o644) + if err != nil { + return nil, err + } } } diff --git a/io.go b/io.go new file mode 100644 index 0000000..49ba488 --- /dev/null +++ b/io.go @@ -0,0 +1,64 @@ +package xcaddy + +// credit: https://github.com/goreleaser/goreleaser/blob/3f54b5eb2f13e86f07420124818fb6594f966278/internal/gio/copy.go +import ( + "fmt" + "io" + "log" + "os" + "path/filepath" + "strings" +) + +// copy recursively copies src into dst with src's file modes. +func copy(src, dst string) error { + src = filepath.ToSlash(src) + dst = filepath.ToSlash(dst) + log.Printf("[INFO] copying files: src=%s dest=%s", src, dst) + return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("failed to copy %s to %s: %w", src, dst, err) + } + path = filepath.ToSlash(path) + // We have the following: + // - src = "a/b" + // - dst = "dist/linuxamd64/b" + // - path = "a/b/c.txt" + // So we join "a/b" with "c.txt" and use it as the destination. + dst := filepath.ToSlash(filepath.Join(dst, strings.Replace(path, src, "", 1))) + if info.IsDir() { + return os.MkdirAll(dst, info.Mode()) + } + if info.Mode()&os.ModeSymlink != 0 { + return copySymlink(path, dst) + } + return copyFile(path, dst, info.Mode()) + }) +} + +func copySymlink(src, dst string) error { + src, err := os.Readlink(src) + if err != nil { + return err + } + return os.Symlink(src, dst) +} + +func copyFile(src, dst string, mode os.FileMode) error { + original, err := os.Open(src) + if err != nil { + return fmt.Errorf("failed to open '%s': %w", src, err) + } + defer original.Close() + + f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode) + if err != nil { + return fmt.Errorf("failed to open '%s': %w", dst, err) + } + defer f.Close() + + if _, err := io.Copy(f, original); err != nil { + return fmt.Errorf("failed to copy: %w", err) + } + return nil +}