Documentation
¶
Overview ¶
Package mailpatch parses git "format-patch" emails into structured data.
`git format-patch` turns commits into RFC 5322 email messages: the commit subject becomes the mail Subject (prefixed with "[PATCH n/m]"), the author and date become headers, the commit message becomes the body, and the diff follows after a "---" separator and a diffstat. `git send-email` mails those out; reviewers reply, and maintainers feed them back to `git am`.
mailpatch reads one of those messages — or a whole mbox of them — and gives you the pieces without shelling out to git:
- Parse / ParseBytes decode a single message into a Patch: author, date, cleaned subject, [PATCH n/m] series position, commit message body, and the parsed diff (per-file hunks plus a diffstat).
- ParseMbox splits an mbox into one Patch per message.
- ParseSeries groups an mbox into a Series: the cover letter (the "0/n" message) plus the numbered patches in order.
- ParseDiff parses a bare unified diff on its own, no email envelope.
It depends only on the standard library and never executes git.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrEmpty is returned when the input has no message at all. ErrEmpty = errors.New("mailpatch: empty input") // ErrMalformed is returned when the input is not a parseable RFC 5322 // message (bad headers, truncated mid-header, and similar). ErrMalformed = errors.New("mailpatch: malformed message") )
Sentinel errors. Compare with errors.Is.
Functions ¶
This section is empty.
Types ¶
type ChangeType ¶
type ChangeType int
ChangeType classifies what happened to a file in a diff.
const ( // Modified is an in-place edit (the default). Modified ChangeType = iota // Added is a new file (old side is /dev/null). Added // Deleted is a removed file (new side is /dev/null). Deleted // Renamed is a move, possibly with edits. Renamed // Copied is a copy, possibly with edits. Copied )
func (ChangeType) String ¶
func (c ChangeType) String() string
type FileChange ¶
type FileChange struct {
OldPath string
NewPath string
Type ChangeType
IsBinary bool
// OldMode and NewMode are the unix mode strings when git reports them
// (e.g. "100644"), otherwise empty.
OldMode string
NewMode string
// Additions and Deletions count added and removed lines across all hunks.
Additions int
Deletions int
Hunks []Hunk
}
FileChange is the diff for a single file.
func ParseDiff ¶
func ParseDiff(diff string) ([]FileChange, error)
ParseDiff parses a unified diff (git or plain) into per-file changes. It accepts the output of `git diff`/`git format-patch` as well as a bare "--- / +++ / @@" diff with no "diff --git" headers. Unrecognized lines are ignored, so a diff embedded in surrounding text still parses.
func (FileChange) Path ¶
func (f FileChange) Path() string
Path returns the file's current path: NewPath, or OldPath for a deletion.
type Hunk ¶
type Hunk struct {
OldStart int
OldLines int
NewStart int
NewLines int
// Section is the text after the closing "@@" (often the enclosing
// function), trimmed.
Section string
Lines []Line
}
Hunk is one "@@ ... @@" section of a file diff.
type Patch ¶
type Patch struct {
// From is the raw From header (decoded from any RFC 2047 encoding).
From string
// AuthorName and AuthorEmail are From split into its parts, best effort.
AuthorName string
AuthorEmail string
// Date is the parsed Date header; the zero time if it was absent or
// unparseable.
Date time.Time
// Subject is the subject with any "[PATCH ...]" prefix stripped.
Subject string
// RawSubject is the original, undecoded-prefix subject line.
RawSubject string
// MessageID, InReplyTo and References come from the corresponding headers
// (angle brackets stripped). They thread a series together.
MessageID string
InReplyTo string
References []string
// Series is the position parsed from the subject prefix.
Series SeriesInfo
// Body is the commit message: everything between the headers and the
// diffstat/diff separator.
Body string
// Diff is the raw unified diff text, signature stripped. Empty for a
// cover letter.
Diff string
// Files is Diff parsed into per-file changes.
Files []FileChange
// Stat is the diffstat computed from Files.
Stat DiffStat
// Header is the full set of decoded message headers, for callers that
// need a field this struct does not surface.
Header mail.Header
}
Patch is a single parsed format-patch email.
A message that carries no diff — most often a "0/n" cover letter — still parses into a Patch; its Diff is empty and HasDiff reports false.
func ParseBytes ¶
ParseBytes is Parse over an in-memory message.
func ParseMbox ¶
ParseMbox parses every message in an mbox stream into a Patch, in file order. Messages without a diff (cover letters) are included.
func (*Patch) IsCoverLetter ¶
IsCoverLetter reports whether this is a series cover letter: a "0/n" subject prefix, or simply a patch mail with no diff.
type Series ¶
type Series struct {
// Cover is the "0/n" cover letter, or nil if the series had none.
Cover *Patch
// Patches are the numbered patches, sorted by SeriesInfo.Index.
Patches []*Patch
// Version is the series revision (1, 2, ... from "[PATCH vN ...]").
Version int
// Total is the expected patch count (m in "[PATCH n/m]"), 0 if unknown.
Total int
}
Series is a patch series: an optional cover letter plus the numbered patches, ordered by their position in the series.
func ParseSeries ¶
ParseSeries parses an mbox and groups it into a single Series: the cover letter (if any) and the numbered patches sorted by index.
type SeriesInfo ¶
type SeriesInfo struct {
// Index is n in "[PATCH n/m]"; 0 for a cover letter or a lone patch with
// no "n/m".
Index int
// Total is m in "[PATCH n/m]"; 0 when the subject had no count.
Total int
// Version is the revision: 2 for "[PATCH v2 ...]", 1 when unspecified.
Version int
// Prefix is the prefix words other than the version and count, e.g.
// "PATCH" or "RFC PATCH".
Prefix string
// IsCover is true for the "0/m" message.
IsCover bool
}
SeriesInfo is the position of a patch within a series, parsed from the "[PATCH n/m]" (or "[RFC PATCH v2 n/m]") subject prefix.