gogogo

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package gogogo creates projects from tar-based templates.

Templates may use {{key}} and __key__ placeholders in text files. Binary files are copied byte-for-byte without placeholder substitution.

Create consumes a caller-provided tar stream, optionally gzip-compressed, and strips one leading path component from each archive entry. It builds the project in a sibling staging directory before publishing it by rename. The caller owns the input reader and is responsible for closing it and arranging cancellation of blocking reads, such as reads from a network connection.

Extraction rejects escaping paths, duplicate entries, unsupported entry types, and traversal through archive-created symlink parents. These checks are not a sandbox for generated content: templates and replacement values should be reviewed before building or executing the resulting project. Callers handling untrusted archives should also enforce their own input and resource limits.

Repository helpers normalize template references and construct GitHub archive URLs; they do not download archives or verify repository access.

Index

Examples

Constants

View Source
const DefaultRepository = "bcomnes/go-template#master"

DefaultRepository is the GitHub template used when no repository is configured.

Variables

This section is empty.

Functions

This section is empty.

Types

type Options

type Options struct {
	// Parameters contains placeholder values.
	// The name parameter defaults to the destination directory name.
	// An explicit name value overrides substitution but not Project.Name.
	// Empty keys are ignored during substitution, and unknown placeholders remain
	// unchanged. Values are inserted literally, without escaping for the target
	// file's language or syntax. Create copies the map; callers must not mutate it
	// concurrently with that copy.
	Parameters map[string]string
}

Options controls project creation. Its zero value uses only the destination-derived name placeholder.

type Project

type Project struct {
	// Name is the cleaned destination's base name, independent of Parameters.
	Name string
	// Destination is the absolute path at which the project was published.
	Destination string
}

Project describes a created project. It is returned only after extraction and publication succeed; Create returns the zero value on error.

func Create

func Create(ctx context.Context, destination string, archive io.Reader, options Options) (Project, error)

Create extracts a tar or gzip-compressed tar template into destination.

The archive must contain a common top-level directory, which Create strips. Placeholder substitution is applied only to text files.

destination must not already exist, including as a dangling symlink. Missing parent directories are created and may remain after an error. Extraction uses a sibling staging directory, with best-effort cleanup on failure, and publishes by rename only after extraction succeeds. Callers must prevent concurrent changes to the destination and its parents; the existence check and publication are not an atomic no-replace operation.

archive must be non-nil and remains owned by the caller; Create never closes it. ctx must be non-nil. Cancellation is checked between archive entries and before content reads, but cannot interrupt an underlying Read already in progress. Some filesystem work, text classification, and gzip draining do not check ctx.

File contents are processed incrementally using disk-backed staging rather than loading the complete archive into memory. No size, entry-count, or expansion limits are imposed. Paths and link targets are not subject to substitution. Regular-file and directory permission bits and nonzero modification times are restored; ownership and special mode bits are not.

Example
var archive bytes.Buffer
writer := tar.NewWriter(&archive)
content := []byte("# __name__\n")
_ = writer.WriteHeader(&tar.Header{
	Name:     "template/README.md",
	Mode:     0o644,
	Size:     int64(len(content)),
	Typeflag: tar.TypeReg,
})
_, _ = writer.Write(content)
_ = writer.Close()

parent, _ := os.MkdirTemp("", "gogogo-example-")
defer os.RemoveAll(parent)
destination := filepath.Join(parent, "example")
project, _ := gogogo.Create(context.Background(), destination, bytes.NewReader(archive.Bytes()), gogogo.Options{})
readme, _ := os.Open(filepath.Join(project.Destination, "README.md"))
defer readme.Close()

fmt.Println(project.Name)
_, _ = io.Copy(os.Stdout, readme)
Output:
example
# example

type Repository

type Repository struct {
	// User is the repository owner's account or organization name.
	User string `json:"user"`
	// Repo is the repository name; ParseRepository removes a Git URL's .git suffix.
	Repo string `json:"repo"`
	// Branch is the archive reference, which may include slashes.
	Branch string `json:"branch"`
}

Repository identifies a GitHub repository and branch. ParseRepository validates input; callers constructing structs directly should use Validate. The value carries no credentials or assurance that the repository exists.

func ParseRepository

func ParseRepository(value string) (Repository, error)

ParseRepository parses user/repo, Git URL, and optional #branch forms.

An absent or empty fragment defaults to master, not the remote's default branch. Surrounding whitespace is trimmed, a trailing .git suffix is removed, and the last two path components supply the owner and repository. Repeated trailing .git suffixes are rejected because reparsing the canonical reference would otherwise change the repository identity. URL hosts, schemes, credentials, and preceding path components are not retained or authenticated; accepting a URL does not mean subsequent requests will use that URL's host. ArchiveURL always targets GitHub.

Owner and repository components must use ASCII letters, digits, underscores, dots, or hyphens and cannot equal "." or "..". Branches must be nonempty and contain no control characters, but are not checked against Git's full ref-name rules. Parsing performs no network requests.

func (Repository) ArchiveURL

func (r Repository) ArchiveURL() string

ArchiveURL returns the GitHub tarball URL for the repository branch. Each field is path-escaped independently, so slashes in Branch remain part of the reference rather than introducing URL path segments. The method performs no validation, authentication, or network access.

func (Repository) String

func (r Repository) String() string

String returns the canonical user/repo#branch representation. It neither escapes nor validates fields, including fields supplied directly by callers rather than through ParseRepository.

func (Repository) Validate added in v0.2.0

func (r Repository) Validate() error

Validate checks the actual structured fields without parsing or normalizing them. Owner and repository must be nonempty ASCII components containing only letters, digits, underscores, dots, or hyphens, and cannot be "." or "..". Branch must be nonempty and contain no control characters; Git's full ref-name rules and repository existence are not checked. Unlike ParseRepository, Validate does not supply a default branch or strip a .git suffix from a literal repository name.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL