Source File
archive.go
Belonging Package
internal/txtar
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package txtar implements a trivial text-based file archive format.
//
// The goals for the format are:
//
// - be trivial enough to create and edit by hand.
// - be able to store trees of text files describing go command test cases.
// - diff nicely in git history and code reviews.
//
// Non-goals include being a completely general archive format,
// storing binary data, storing file modes, storing special files like
// symbolic links, and so on.
//
// # Txtar format
//
// A txtar archive is zero or more comment lines and then a sequence of file entries.
// Each file entry begins with a file marker line of the form "-- FILENAME --"
// and is followed by zero or more file content lines making up the file data.
// The comment or file content ends at the next file marker line.
// The file marker line must begin with the three-byte sequence "-- "
// and end with the three-byte sequence " --", but the enclosed
// file name can be surrounding by additional white space,
// all of which is stripped.
//
// If the txtar file is missing a trailing newline on the final line,
// parsers should consider a final newline to be present anyway.
//
// There are no possible syntax errors in a txtar archive.
package txtar
import (
)
// An Archive is a collection of files.
type Archive struct {
Comment []byte
Files []File
}
// A File is a single file in an archive.
type File struct {
Name string // name of file ("foo/bar.txt")
Data []byte // text content of file
}
// Format returns the serialized form of an Archive.
// It is assumed that the Archive data structure is well-formed:
// a.Comment and all a.File[i].Data contain no file marker lines,
// and all a.File[i].Name is non-empty.
func ( *Archive) []byte {
var bytes.Buffer
.Write(fixNL(.Comment))
for , := range .Files {
fmt.Fprintf(&, "-- %s --\n", .Name)
.Write(fixNL(.Data))
}
return .Bytes()
}
// ParseFile parses the named file as an archive.
func ( string) (*Archive, error) {
, := os.ReadFile()
if != nil {
return nil,
}
return Parse(), nil
}
// Parse parses the serialized form of an Archive.
// The returned Archive holds slices of data.
func ( []byte) *Archive {
:= new(Archive)
var string
.Comment, , = findFileMarker()
for != "" {
:= File{, nil}
.Data, , = findFileMarker()
.Files = append(.Files, )
}
return
}
var (
newlineMarker = []byte("\n-- ")
marker = []byte("-- ")
markerEnd = []byte(" --")
)
// findFileMarker finds the next file marker in data,
// extracts the file name, and returns the data before the marker,
// the file name, and the data after the marker.
// If there is no next marker, findFileMarker returns before = fixNL(data), name = "", after = nil.
func findFileMarker( []byte) ( []byte, string, []byte) {
var int
for {
if , = isMarker([:]); != "" {
return [:], ,
}
:= bytes.Index([:], newlineMarker)
if < 0 {
return fixNL(), "", nil
}
+= + 1 // positioned at start of new possible marker
}
}
// isMarker checks whether data begins with a file marker line.
// If so, it returns the name from the line and the data after the line.
// Otherwise it returns name == "" with an unspecified after.
func isMarker( []byte) ( string, []byte) {
if !bytes.HasPrefix(, marker) {
return "", nil
}
if := bytes.IndexByte(, '\n'); >= 0 {
, = [:], [+1:]
}
if !(bytes.HasSuffix(, markerEnd) && len() >= len(marker)+len(markerEnd)) {
return "", nil
}
return strings.TrimSpace(string([len(marker) : len()-len(markerEnd)])),
}
// If data is empty or ends in \n, fixNL returns data.
// Otherwise fixNL returns a new slice consisting of data with a final \n added.
func fixNL( []byte) []byte {
if len() == 0 || [len()-1] == '\n' {
return
}
:= make([]byte, len()+1)
copy(, )
[len()] = '\n'
return
}
The pages are generated with Golds v0.7.0-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |