Documentation
¶
Overview ¶
Package vacation provides a set of functions that enable input stream decompression logic from several popular decompression formats. This allows from decompression from either a file or any other byte stream, which is useful for decompressing files that are being downloaded.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Archive ¶ added in v0.2.8
type Archive struct {
// contains filtered or unexported fields
}
An Archive decompresses tar, gzip, xz, and bzip2 compressed tar, and zip files from an input stream.
Example ¶
package main import ( "archive/tar" "archive/zip" "bytes" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { tarBuffer := bytes.NewBuffer(nil) tw := tar.NewWriter(tarBuffer) tarFiles := []ArchiveFile{ {Name: "some-tar-dir/"}, {Name: "some-tar-dir/some-tar-file", Content: []byte("some-tar-dir/some-tar-file")}, {Name: "tar-file", Content: []byte("tar-file")}, } for _, file := range tarFiles { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() zipBuffer := bytes.NewBuffer(nil) zw := zip.NewWriter(zipBuffer) zipFiles := []ArchiveFile{ {Name: "some-zip-dir/"}, {Name: "some-zip-dir/some-zip-file", Content: []byte("some-zip-dir/some-zip-file")}, {Name: "zip-file", Content: []byte("zip-file")}, } for _, file := range zipFiles { header := &zip.FileHeader{Name: file.Name} header.SetMode(0755) f, err := zw.CreateHeader(header) if err != nil { log.Fatal(err) } if _, err := f.Write(file.Content); err != nil { log.Fatal(err) } } zw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewArchive(bytes.NewReader(tarBuffer.Bytes())) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } archive = vacation.NewArchive(bytes.NewReader(zipBuffer.Bytes())) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: some-tar-dir/some-tar-file some-zip-dir/some-zip-file tar-file zip-file
func NewArchive ¶ added in v0.2.8
NewArchive returns a new Archive that reads from inputReader.
func (Archive) Decompress ¶ added in v0.2.8
Decompress reads from Archive, determines the archive type of the input stream, and writes files into the destination specified.
Archive decompression will also handle files that are types "text/plain; charset=utf-8" and write the contents of the input stream to a file name specified by the `Archive.WithName()` option (or defaults to "artifact") in the destination directory.
func (Archive) StripComponents ¶ added in v0.2.8
StripComponents behaves like the --strip-components flag on tar command removing the first n levels from the final decompression destination. Setting this is a no-op for archive types that do not use --strip-components (such as zip).
Example ¶
package main import ( "archive/tar" "archive/zip" "bytes" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { tarBuffer := bytes.NewBuffer(nil) tw := tar.NewWriter(tarBuffer) tarFiles := []ArchiveFile{ {Name: "some-tar-dir/"}, {Name: "some-tar-dir/some-tar-file", Content: []byte("some-tar-dir/some-tar-file")}, {Name: "tar-file", Content: []byte("tar-file")}, } for _, file := range tarFiles { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() zipBuffer := bytes.NewBuffer(nil) zw := zip.NewWriter(zipBuffer) zipFiles := []ArchiveFile{ {Name: "some-zip-dir/"}, {Name: "some-zip-dir/some-zip-file", Content: []byte("some-zip-dir/some-zip-file")}, {Name: "zip-file", Content: []byte("zip-file")}, } for _, file := range zipFiles { header := &zip.FileHeader{Name: file.Name} header.SetMode(0755) f, err := zw.CreateHeader(header) if err != nil { log.Fatal(err) } if _, err := f.Write(file.Content); err != nil { log.Fatal(err) } } zw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewArchive(bytes.NewReader(tarBuffer.Bytes())).StripComponents(1) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } archive = vacation.NewArchive(bytes.NewReader(zipBuffer.Bytes())).StripComponents(1) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: some-tar-file some-zip-file
type Decompressor ¶ added in v0.14.0
type NopArchive ¶ added in v0.14.0
type NopArchive struct {
// contains filtered or unexported fields
}
A NopArchive implements the common archive interface, but acts as a no-op, simply copying the reader to the destination.
func NewNopArchive ¶ added in v0.14.0
func NewNopArchive(r io.Reader) NopArchive
NewNopArchive returns a new NopArchive
func (NopArchive) Decompress ¶ added in v0.14.0
func (na NopArchive) Decompress(destination string) error
Decompress copies the reader contents into the destination specified.
type TarArchive ¶
type TarArchive struct {
// contains filtered or unexported fields
}
A TarArchive decompresses tar files from an input stream.
Example ¶
package main import ( "archive/tar" "bytes" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) tw := tar.NewWriter(buffer) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarArchive(bytes.NewReader(buffer.Bytes())) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: first second some-dir/some-other-dir/some-file third
func NewTarArchive ¶
func NewTarArchive(inputReader io.Reader) TarArchive
NewTarArchive returns a new TarArchive that reads from inputReader.
func (TarArchive) Decompress ¶
func (ta TarArchive) Decompress(destination string) error
Decompress reads from TarArchive and writes files into the destination specified.
func (TarArchive) StripComponents ¶
func (ta TarArchive) StripComponents(components int) TarArchive
StripComponents behaves like the --strip-components flag on tar command removing the first n levels from the final decompression destination.
Example ¶
package main import ( "archive/tar" "bytes" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) tw := tar.NewWriter(buffer) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarArchive(bytes.NewReader(buffer.Bytes())).StripComponents(1) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: some-other-dir/some-file
type TarBzip2Archive ¶ added in v0.12.1
type TarBzip2Archive struct {
// contains filtered or unexported fields
}
A TarBzip2Archive decompresses bzip2 files from an input stream.
Example ¶
package main import ( "archive/tar" "bytes" "fmt" "log" "os" "path/filepath" dsnetBzip2 "github.com/dsnet/compress/bzip2" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) // Using the dsnet library because the Go compression library does not // have a writer. There is recent discussion on this issue // https://github.com/golang/go/issues/4828 to add an encoder. The // library should be removed once there is a native encoder bz, err := dsnetBzip2.NewWriter(buffer, nil) if err != nil { log.Fatal(err) } tw := tar.NewWriter(bz) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() bz.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarBzip2Archive(bytes.NewReader(buffer.Bytes())) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: first second some-dir/some-other-dir/some-file third
func NewTarBzip2Archive ¶ added in v0.12.1
func NewTarBzip2Archive(inputReader io.Reader) TarBzip2Archive
NewTarBzip2Archive returns a new Bzip2Archive that reads from inputReader.
func (TarBzip2Archive) Decompress ¶ added in v0.12.1
func (tbz TarBzip2Archive) Decompress(destination string) error
Decompress reads from TarBzip2Archive and writes files into the destination specified.
func (TarBzip2Archive) StripComponents ¶ added in v0.12.1
func (tbz TarBzip2Archive) StripComponents(components int) TarBzip2Archive
StripComponents behaves like the --strip-components flag on tar command removing the first n levels from the final decompression destination.
Example ¶
package main import ( "archive/tar" "bytes" "fmt" "log" "os" "path/filepath" dsnetBzip2 "github.com/dsnet/compress/bzip2" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) // Using the dsnet library because the Go compression library does not // have a writer. There is recent discussion on this issue // https://github.com/golang/go/issues/4828 to add an encoder. The // library should be removed once there is a native encoder bz, err := dsnetBzip2.NewWriter(buffer, nil) if err != nil { log.Fatal(err) } tw := tar.NewWriter(bz) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() bz.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarBzip2Archive(bytes.NewReader(buffer.Bytes())).StripComponents(1) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: some-other-dir/some-file
type TarGzipArchive ¶
type TarGzipArchive struct {
// contains filtered or unexported fields
}
A TarGzipArchive decompresses gziped tar files from an input stream.
Example ¶
package main import ( "archive/tar" "bytes" "compress/gzip" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) gw := gzip.NewWriter(buffer) tw := tar.NewWriter(gw) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() gw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarGzipArchive(bytes.NewReader(buffer.Bytes())) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: first second some-dir/some-other-dir/some-file third
func NewTarGzipArchive ¶
func NewTarGzipArchive(inputReader io.Reader) TarGzipArchive
NewTarGzipArchive returns a new TarGzipArchive that reads from inputReader.
func (TarGzipArchive) Decompress ¶
func (gz TarGzipArchive) Decompress(destination string) error
Decompress reads from TarGzipArchive and writes files into the destination specified.
func (TarGzipArchive) StripComponents ¶
func (gz TarGzipArchive) StripComponents(components int) TarGzipArchive
StripComponents behaves like the --strip-components flag on tar command removing the first n levels from the final decompression destination.
Example ¶
package main import ( "archive/tar" "bytes" "compress/gzip" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) gw := gzip.NewWriter(buffer) tw := tar.NewWriter(gw) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() gw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarGzipArchive(bytes.NewReader(buffer.Bytes())).StripComponents(1) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: some-other-dir/some-file
type TarXZArchive ¶
type TarXZArchive struct {
// contains filtered or unexported fields
}
A TarXZArchive decompresses xz tar files from an input stream.
Example ¶
package main import ( "archive/tar" "bytes" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" "github.com/ulikunitz/xz" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) xw, err := xz.NewWriter(buffer) if err != nil { log.Fatal(err) } tw := tar.NewWriter(xw) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() xw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarXZArchive(bytes.NewReader(buffer.Bytes())) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: first second some-dir/some-other-dir/some-file third
func NewTarXZArchive ¶
func NewTarXZArchive(inputReader io.Reader) TarXZArchive
NewTarXZArchive returns a new TarXZArchive that reads from inputReader.
func (TarXZArchive) Decompress ¶
func (txz TarXZArchive) Decompress(destination string) error
Decompress reads from TarXZArchive and writes files into the destination specified.
func (TarXZArchive) StripComponents ¶
func (txz TarXZArchive) StripComponents(components int) TarXZArchive
StripComponents behaves like the --strip-components flag on tar command removing the first n levels from the final decompression destination.
Example ¶
package main import ( "archive/tar" "bytes" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" "github.com/ulikunitz/xz" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) xw, err := xz.NewWriter(buffer) if err != nil { log.Fatal(err) } tw := tar.NewWriter(xw) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { err := tw.WriteHeader(&tar.Header{Name: file.Name, Mode: 0755, Size: int64(len(file.Content))}) if err != nil { log.Fatal(err) } _, err = tw.Write(file.Content) if err != nil { log.Fatal(err) } } tw.Close() xw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewTarXZArchive(bytes.NewReader(buffer.Bytes())).StripComponents(1) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: some-other-dir/some-file
type ZipArchive ¶
type ZipArchive struct {
// contains filtered or unexported fields
}
A ZipArchive decompresses zip files from an input stream.
Example ¶
package main import ( "archive/zip" "bytes" "fmt" "log" "os" "path/filepath" "github.com/paketo-buildpacks/packit/vacation" ) type ArchiveFile struct { Name string Content []byte } func main() { buffer := bytes.NewBuffer(nil) zw := zip.NewWriter(buffer) files := []ArchiveFile{ {Name: "some-dir/"}, {Name: "some-dir/some-other-dir/"}, {Name: "some-dir/some-other-dir/some-file", Content: []byte("some-dir/some-other-dir/some-file")}, {Name: "first", Content: []byte("first")}, {Name: "second", Content: []byte("second")}, {Name: "third", Content: []byte("third")}, } for _, file := range files { header := &zip.FileHeader{Name: file.Name} header.SetMode(0755) f, err := zw.CreateHeader(header) if err != nil { log.Fatal(err) } if _, err := f.Write(file.Content); err != nil { log.Fatal(err) } } zw.Close() destination, err := os.MkdirTemp("", "destination") if err != nil { log.Fatal(err) } defer os.RemoveAll(destination) archive := vacation.NewZipArchive(bytes.NewReader(buffer.Bytes())) if err := archive.Decompress(destination); err != nil { log.Fatal(err) } err = filepath.Walk(destination, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { rel, err := filepath.Rel(destination, path) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", rel) return nil } return nil }) if err != nil { log.Fatal(err) } }
Output: first second some-dir/some-other-dir/some-file third
func NewZipArchive ¶
func NewZipArchive(inputReader io.Reader) ZipArchive
NewZipArchive returns a new ZipArchive that reads from inputReader.
func (ZipArchive) Decompress ¶
func (z ZipArchive) Decompress(destination string) error
Decompress reads from ZipArchive and writes files into the destination specified.
func (ZipArchive) StripComponents ¶ added in v0.14.2
func (z ZipArchive) StripComponents(components int) ZipArchive
StripComponents removes the first n levels from the final decompression destination.