hrx

package module
v1.1.4 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2024 License: Apache-2.0 Imports: 11 Imported by: 1

README

godoc codecov Go Report Card

hrx - human readable archive utilities

A collection of utilities for working with .hrx files.

Installation

> go get github.com/go-corelibs/hrx@latest

Examples

Archive

func main() {
    a := hrx.New("", "file-level comment")
    _ = a.Set("file.txt", "this is a simple test file\nwith multiple lines")
    if err := a.WriteFile("/path/to/new.hrx"); err != nil {
        panic(err)
    }
    // there is now a /path/to/new.hrx with one file.txt archived
}

Go-CoreLibs

Go-CoreLibs is a repository of shared code between the Go-Curses and Go-Enjin projects.

License

Copyright 2024 The Go-CoreLibs Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use file except in compliance with the License.
You may obtain a copy of the license at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Documentation

Overview

Package hrx provides human-readable archive utilities

Introduction

This package implements support for reading, manipulating and writing "human-readable archive" (`.hrx`) files. These archives are like `tar` archives except that they only store plain text files and the internal structure is easily editable by humans.

Here's the summary from the official specification:

This is a specification for a plain-text, human-friendly format for
defining multiple virtual text files in a single physical file, for
situations when creating many physical files is undesirable, such as
defining test cases for a text format.

See: https://github.com/google/hrx

Index

Constants

View Source
const (
	// OpExtracted is the ReporterFn note used when a file is extracted
	OpExtracted = "extracted"
	// OpCreated is the ReporterFn note used when creating a directory
	OpCreated = "created"
	// OpSkipped is the ReporterFn note used when a file is skipped from
	// extraction because it was not included with the other pathnames
	// given for specific extraction
	OpSkipped = "skipped"
	// OpDeleted is the ReporterFn note used when a file is deleted from
	// an Archive instance
	OpDeleted = "deleted"
	// OpAppended is the ReporterFn note used when a file is appended to
	// an Archive instance during Archive.Set
	OpAppended = "appended"
	// OpUpdated is the ReporterFn note used when a file is updated within
	// an Archive instance during Archive.Set
	OpUpdated = "updated"
	// OpBoundary is the ReporterFn note used when the Archive boundary is
	// changed. Note that all nested archives also emit this report when
	// the top-level Archive.SetBoundary call is made. The top-level report
	// will have an empty pathname argument
	OpBoundary = "boundary"
)

The following constants are the ReporterFn note strings used when reporting progress

View Source
const (
	// DefaultBoundary is the boundary size for New archives created
	DefaultBoundary = 5
)

Variables

View Source
var (
	ErrMalformedInput       = errors.New("malformed input")
	ErrSequentialComments   = errors.New("sequential comments")
	ErrBadFileEntry         = errors.New("bad file entry")
	ErrDirectoryHasContents = errors.New("directory has contents")
	ErrDuplicatePath        = errors.New("duplicate path")
	ErrFileAsParentDir      = errors.New("file as parent directory")
)

HRX specification errors

View Source
var (
	ErrNotFound          = errors.New("pathname not found")
	ErrEmptyArchive      = errors.New("empty archive")
	ErrNotAnArchive      = errors.New("not an archive (.hrx)")
	ErrBadArchiveHeader  = errors.New("bad archive header")
	ErrBadBoundary       = errors.New("bad archive boundary")
	ErrNoSpaceBeforePath = errors.New("no space before pathname")
	ErrInvalidUnicode    = errors.New("contains invalid unicode")
	ErrStartsWithDirSep  = errors.New("pathname starts with a path separator")
	ErrInvalidCharRange  = errors.New("pathname contains invalid ascii")
	ErrContainsColon     = errors.New("pathname contains a colon")
	ErrEscapeCharacter   = errors.New("pathname contains escape characters")
	ErrContainsRelPath   = errors.New("pathname contains relative names (//, . or ..)")
)

Specific error messages

View Source
var (
	// DefaultFileMode is the os.FileMode setting used to extract files
	DefaultFileMode os.FileMode = 0640
)
View Source
var (
	ErrDstIsFile = errors.New("destination directory is a file")
)

General package errors

Functions

This section is empty.

Types

type Archive

type Archive interface {
	// FileName is the filename given when constructing this Archive instance
	FileName() (filename string)
	// SetBoundary changes this archive's boundary to the size given and if
	// there are any nested archives within this archive, they are all updated
	// with nested increments of the size given
	SetBoundary(size int) (err error)

	// GetBoundary returns this archive's boundary size (number of equal signs
	// within the HRX headers)
	GetBoundary() (size int)

	// SetComment specifies a general comment for this archive
	SetComment(comment string)

	// GetComment returns the general comment for this archive, if one exists
	GetComment() (comment string, ok bool)

	// DeleteComment removes the general comment for this archive
	DeleteComment()

	// Set adds or overwrites pathname with the given body and comment. Empty
	// comments are ignored. Set may return an error if another HRX file is
	// being set and a parsing error happened while adjusting the nested
	// archive's boundary size
	Set(pathname, body, comment string) (err error)

	// Get returns the body and any comment for the given pathname
	Get(pathname string) (body, comment string, ok bool)

	// Delete removes the pathname entry
	Delete(pathname string)

	// Entry returns a read-only interface for a specific pathname. Returns
	// nil if there is no entry for the specified pathname
	Entry(pathname string) Entry

	// Len returns the number of entries stored within this archive. Len does
	// not recurse into nested HRX files and does not include any general
	// comment for this archive
	Len() (entries int)

	// List returns a list of all entry pathnames, in the order they are found
	// within this archive. List does not recurse into nested HRX files
	List() (pathnames []string)

	// Entries returns a list of all file and directory entries within this
	// Archive instance. Entries does not recurse into embedded HRX Archive
	// files
	Entries() (entries []Entry)

	// ParseHRX looks for the entry associated with the given pathname and if
	// the pathname has the `.hrx` extension, attempts to parse the contents
	// into a new Archive instance
	ParseHRX(pathname string) (parsed Archive, err error)

	// String returns the actual contents of this archive
	String() (archive string)

	// WriteFile takes the String of this Archive and writes the contents to
	// the local filesystem, at the path given. WriteFile will attempt to
	// make all parent directories for the destination file
	WriteFile(destination string) (err error)

	// ExtractTo extracts all of this Archive's entries to their individual
	// files on the local filesystem. If any pathnames are also given then
	// only those will be extracted. If no pathnames are given, all files are
	// extracted
	ExtractTo(destination string, pathnames ...string) (err error)

	// SetReporter configures the internal event reporter function. This is
	// only really useful for user-interfaces requiring notifications whenever
	// an operation is performed
	SetReporter(fn ReporterFn)
}

Archive is a computer-readable parsing of a human-readable archive

func New

func New(filename, comment string) Archive

New creates a new Archive instance with a DefaultBoundary

func ParseData

func ParseData[V string | []byte | []rune](filename string, data V) (hrx Archive, err error)

ParseData parses the given data and associates the resulting Archive with the filename given

func ParseFile

func ParseFile(path string) (hrx Archive, err error)

ParseFile reads the given file and creates an Archive instance

func ParseReader

func ParseReader(filename string, reader io.Reader) (hrx Archive, err error)

ParseReader parses data from the given reader and associates the resulting Archive with the filename given

type Entry

type Entry interface {
	// IsComment reports true when the boundary pathname is empty
	IsComment() bool
	// IsFile reports true when the boundary pathname is not empty and does not
	// end with a directory separator
	IsFile() bool
	// Size returns zero and false for directories and for comments and
	// files, returns the number of bytes and true
	Size() (size int, ok bool)
	// IsDir reports true when the boundary pathname is not empty and ends with
	// a directory separator
	IsDir() bool
	// IsHRX reports true when the boundary pathname is not empty and ends with
	// a `.hrx` extension
	IsHRX() bool

	// ParseHRX checks if this entry IsHRX and parses the body content into a
	// new Archive instance. Note that modifying the parsed Archive will not
	// update this specific entry's body content
	//
	// Example of modifying and saving a nested Archive instance:
	//
	//  a := ParseData("example.hrx", ...)
	//  if entry := a.GetEntry("nested.hrx"); entry != nil {
	//      if b, err := entry.ParseHRX(); err != nil {
	//          ... handle error ...
	//      } else {
	//          b.Set("filename", "new contents", "")
	//          a.Set("nested.hrx", b.GetBody(), b.GetComment())
	//          if err = a.WriteFile("example.hrx"); err != nil {
	//              ... handle error ...
	//          }
	//      }
	//  }
	//
	ParseHRX() (a Archive, err error)

	// GetPathname returns the pathname from the HRX header line for this entry
	GetPathname() (pathname string)
	// GetBody returns the body contents of this HRX entry
	GetBody() (body string)
	// GetComment returns the comment associated with this HRX entry
	GetComment() (comment string)

	// String is the complete boundary pathname body newline contents for this
	// entry, even if it is itself another .hrx file and includes any preceding
	// comment
	String() (data string)
}

Entry is a read-only interface for a specific HRX entry

type Error

type Error struct {
	// File is the filename given to ParseData or ParseFile
	File string
	// Base is the related HRX error message
	Base error
	// Wrap is the specific error message
	Wrap error
	// Line is the line number of the archive where this error has occurred
	Line int
}

Error is the type for all error instances returned from this package

func AsError

func AsError(err error) (e *Error, ok bool)

AsError is a convenience wrapper around errors.As for an *Error

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is added in v1.1.1

func (e *Error) Is(err error) (ok bool)

type ReporterFn

type ReporterFn func(archive, pathname, note string, argv ...interface{})

ReporterFn is the function signature for Archive progress reporting

type Scanner

type Scanner struct {
	scanners.LineScanner
	// contains filtered or unexported fields
}

Scanner is a line-reading text scanner for parsing HRX archive contents

func NewScanner

func NewScanner(reader io.Reader) *Scanner

NewScanner constructs a new Scanner instance

func (*Scanner) Get

func (s *Scanner) Get() (content string, line, boundary int, pathname string, header bool, err error)

Get returns the current Scan results

content    is the entire line read as-is
line       is the current line number
boundary   is the number of equal signs in the parsed HRX `<====>` boundary
pathname   is the pathname component of the HRX boundary line
header     reports if the boundary and pathname values are valid
err        reports any error detected on this line

func (*Scanner) Peek

func (s *Scanner) Peek() (content string, boundary int, pathname string, header bool, err error, ok bool)

func (*Scanner) Scan

func (s *Scanner) Scan() (ok bool)

Scan is the main iterator of the Scanner and returns false when the end of the buffer is reached

Jump to

Keyboard shortcuts

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