Documentation
¶
Index ¶
- Constants
- Variables
- func Debugf(format string, args ...interface{})
- func DiscardByRead(source Source, delta int64) error
- func NopConsumer() *state.Consumer
- type AfterSaveAction
- type CallbackSourceSaveConsumer
- type Copier
- type CopyParams
- type EmitProgressFunc
- type Entry
- type EntryKind
- type EntryWriter
- type Extractor
- type ExtractorCheckpoint
- type ExtractorFeatures
- type ExtractorResult
- type FolderSink
- func (fs *FolderSink) Close() error
- func (fs *FolderSink) GetWriter(entry *Entry) (EntryWriter, error)
- func (fs *FolderSink) Mkdir(entry *Entry) error
- func (fs *FolderSink) Nuke() error
- func (fs *FolderSink) Preallocate(entry *Entry) error
- func (fs *FolderSink) Symlink(entry *Entry, linkname string) error
- type ResumeSupport
- type Savable
- type SaveConsumer
- type SeekSource
- type Sink
- type Source
- type SourceCheckpoint
- type SourceSaveConsumer
Constants ¶
const ( // ModeMask is or'd with files walked by butler ModeMask = 0666 // LuckyMode is used when wiping in last-chance mode LuckyMode = 0777 // DirMode is the default mode for directories created by butler DirMode = 0755 )
const ( // EntryKindDir is the kind for a directory EntryKindDir = 0 // EntryKindSymlink is the kind for a symlink EntryKindSymlink = 1 // EntryKindFile is the kind for a file EntryKindFile = 2 )
Variables ¶
var ErrStop = errors.New("copy was stopped after save!")
var ErrUninitializedSource = errors.New("tried to read from source before Resume() was called")
Functions ¶
func Debugf ¶
func Debugf(format string, args ...interface{})
Debugf prints a message if the environment variable SAVIOR_DEBUG is set to "1"
func DiscardByRead ¶
DiscardByRead advances a source by `delta` bytes by reading data then throwing it away. This is useful in case a source made a checkpoint shortly before the offset we actually need to resume from.
func NopConsumer ¶
Types ¶
type AfterSaveAction ¶
type AfterSaveAction int
const ( AfterSaveContinue AfterSaveAction = 1 AfterSaveStop AfterSaveAction = 2 )
type CallbackSourceSaveConsumer ¶
type CallbackSourceSaveConsumer struct {
OnSave func(checkpoint *SourceCheckpoint) error
}
func (*CallbackSourceSaveConsumer) Save ¶
func (cssc *CallbackSourceSaveConsumer) Save(checkpoint *SourceCheckpoint) error
type Copier ¶
type Copier struct { // params SaveConsumer SaveConsumer // contains filtered or unexported fields }
func NewCopier ¶
func NewCopier(SaveConsumer SaveConsumer) *Copier
func (*Copier) Do ¶
func (c *Copier) Do(params *CopyParams) error
type CopyParams ¶
type EmitProgressFunc ¶
type EmitProgressFunc func()
type Entry ¶
type Entry struct { // CanonicalPath is a slash-separated path relative to the // root of the archive CanonicalPath string // Kind describes whether it's a regular file, a directory, or a symlink Kind EntryKind // Mode contains read/write/execute permissions, we're mostly interested in execute Mode os.FileMode // CompressedSize may be 0, if the extractor doesn't have the information CompressedSize int64 // UncompressedSize may be 0, if the extractor doesn't have the information UncompressedSize int64 // WriteOffset is useful if this entry struct is included in an extractor // checkpoint WriteOffset int64 // Linkname describes the target of a symlink if the entry is a symlink // and the format we're extracting has symlinks in metadata rather than its contents Linkname string }
An Entry is a struct that should have *just the right fields* to be useful in an extractor checkpoint. They represent a file, directory, or symlink
type EntryWriter ¶
type EntryWriter interface { io.WriteCloser // Sync should commit (to disk or otherwise) all the data written so far // to the entry. Sync() error }
An EntryWriter is an io.WriteCloser that you can Sync(). This is important as saving a checkpoint (while in the middle of decompressing an archive) is only useful if we *know* that all the data we say we've decompressed is actually on disk (and not just stuck in a OS buffer somewhere).
type Extractor ¶
type Extractor interface { SetSaveConsumer(saveConsumer SaveConsumer) SetConsumer(consumer *state.Consumer) Resume(checkpoint *ExtractorCheckpoint, sink Sink) (*ExtractorResult, error) Features() ExtractorFeatures }
type ExtractorCheckpoint ¶
type ExtractorCheckpoint struct { SourceCheckpoint *SourceCheckpoint EntryIndex int64 Entry *Entry Progress float64 Data interface{} }
type ExtractorFeatures ¶
type ExtractorFeatures struct { Name string ResumeSupport ResumeSupport Preallocate bool RandomAccess bool }
func (ExtractorFeatures) String ¶
func (ef ExtractorFeatures) String() string
type ExtractorResult ¶
type ExtractorResult struct {
Entries []*Entry
}
func (*ExtractorResult) Size ¶
func (er *ExtractorResult) Size() int64
func (*ExtractorResult) Stats ¶
func (er *ExtractorResult) Stats() string
type FolderSink ¶
type FolderSink struct { Directory string Consumer *state.Consumer // contains filtered or unexported fields }
func (*FolderSink) Close ¶
func (fs *FolderSink) Close() error
func (*FolderSink) GetWriter ¶
func (fs *FolderSink) GetWriter(entry *Entry) (EntryWriter, error)
func (*FolderSink) Mkdir ¶
func (fs *FolderSink) Mkdir(entry *Entry) error
func (*FolderSink) Nuke ¶
func (fs *FolderSink) Nuke() error
func (*FolderSink) Preallocate ¶
func (fs *FolderSink) Preallocate(entry *Entry) error
type ResumeSupport ¶
type ResumeSupport int
const ( // While the extractor exposes Save/Resume, in practice, resuming // will probably waste I/O and processing redoing a lot of work // that was already done, so it's not recommended to run it against // a networked resource ResumeSupportNone ResumeSupport = 0 // The extractor can save/resume between each entry, but not in the middle of an entry ResumeSupportEntry ResumeSupport = 1 // The extractor can save/resume within an entry, on a deflate/bzip2 block boundary for example ResumeSupportBlock ResumeSupport = 2 )
func (ResumeSupport) String ¶
func (rs ResumeSupport) String() string
type SaveConsumer ¶
type SaveConsumer interface { ShouldSave(copiedBytes int64) bool Save(checkpoint *ExtractorCheckpoint) (AfterSaveAction, error) }
func NopSaveConsumer ¶
func NopSaveConsumer() SaveConsumer
type SeekSource ¶
type SeekSource interface { Source // Tell returns the current offset of the seeksource Tell() int64 // Size returns the total number of bytes the seeksource reads Size() int64 // Section returns a SeekSource that reads from start to start+size // Note that the returned SeekSource will use the same underlying // io.ReadSeeker, so the original SeekSource cannot be used anymore. // The returned SeekSource should be Resume()'d before being used Section(start int64, size int64) (SeekSource, error) }
SeekSource is a Source with extra powers: you can know its size, tell which offset it's currently at, and ask for a view of a subsection of it.
type Sink ¶
type Sink interface { // Mkdir creates a directory (and parents if needed) Mkdir(entry *Entry) error // Symlink creates a symlink Symlink(entry *Entry, linkname string) error // GetWriter returns a writer at entry.WriteOffset GetWriter(entry *Entry) (EntryWriter, error) // Preallocate space for a file based on the entry's UncompressedSize Preallocate(entry *Entry) error // Remove everything written so far Nuke() error // Close this sink, including all pending writers Close() error }
A Sink is what extractors extract to. Typically, that would be a folder on a filesystem, but it could be anything else: repackaging as another archive type, uploading transparently as small blocks.
Think of it as a very thin portion of `os.{Create,Mkdir,Symlink}` and friends that can be implemented completely independently of the filesystem
type Source ¶
type Source interface { // Resume tries to use a checkpoint to start reading again at the checkpoint. // It *must be called* before using the source, whether or not checkpoint is // an actual mid-stream checkpoint or just the nil checkpoint (for Offset=0) Resume(checkpoint *SourceCheckpoint) (int64, error) // Register a source save consumer for this source SetSourceSaveConsumer(ssc SourceSaveConsumer) // Let the source know that it should emit a checkpoint as soon as it can. WantSave() // Progress returns how much of the stream has been consumed, in a [0,1] range. // If this source does not support progress reporting (ie. the total size of // the stream is unknown), then Progress returns a negative value (typically -1). Progress() float64 io.Reader // io.ByteReader is embedded in Source so it can be used by the `flate` package // without it wrapping it in a `bufio.Reader` io.ByteReader }
A Source represents a data stream that does not provide random access, is not seekable, but for which checkpoints can be emitted, allowing the consumer to resume reading from the stream later.
Sources typically are either a limited interface for a more powerful resource (*os.File, eos.File, both of which provide seeking and random access), or a more powerful interface to resources typically exposed as simply an `io.Reader` in the golang standard library (flate streams, gzip streams, bzip2 streams)
Sources that expose a random access resource tend to be able to `Save()` at any given byte, whereas sources that are decompressors are typically only able to save on a block boundary.
type SourceCheckpoint ¶
type SourceCheckpoint struct { // Offset is the position in the stream, in bytes // It should be non-zero, as the checkpoint for offset 0 is simply nil Offset int64 // Data is a source-specific pointer to a struct, which must be // registered with `gob` so that it can be serialized and deserialized Data interface{} }
SourceCheckpoint contains all the information needed for a source to resume from a given offset.
type SourceSaveConsumer ¶
type SourceSaveConsumer interface { // Send a checkpoint to the consumer. The consumer may // retain the checkpoint, so its contents must not change // after it is sent. Save(checkpoint *SourceCheckpoint) error }