vacation

package
v2.14.0 Latest Latest
Warning

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

Go to latest
Published: May 2, 2024 License: Apache-2.0 Imports: 12 Imported by: 12

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

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/v2/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

func NewArchive(inputReader io.Reader) Archive

NewArchive returns a new Archive that reads from inputReader.

func (Archive) Decompress

func (a Archive) Decompress(destination string) error

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 - "application/x-executable" - "text/plain; charset=utf-8" - "application/jar" - "application/octet-stream" and write the contents of the input stream to a file name specified by the `Archive.WithName()` option in the destination directory.

func (Archive) StripComponents

func (a Archive) StripComponents(components int) Archive

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/v2/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

func (Archive) WithName

func (a Archive) WithName(name string) Archive

WithName provides a way of overriding the name of the file that the decompressed file will be copied into.

type Bzip2Archive

type Bzip2Archive struct {
	// contains filtered or unexported fields
}

A Bzip2Archive decompresses bzip2 files from an input stream.

Example
package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path/filepath"

	dsnetBzip2 "github.com/dsnet/compress/bzip2"
	"github.com/paketo-buildpacks/packit/v2/vacation"
)

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)
	}

	_, err = bz.Write([]byte(`Bzip2 file contents`))
	if err != nil {
		log.Fatal(err)
	}

	bz.Close()

	destination, err := os.MkdirTemp("", "destination")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(destination)

	archive := vacation.NewBzip2Archive(bytes.NewReader(buffer.Bytes())).WithName("bzip2-file")
	if err := archive.Decompress(destination); err != nil {
		log.Fatal(err)
	}

	contents, err := os.ReadFile(filepath.Join(destination, "bzip2-file"))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(contents))

}
Output:

Bzip2 file contents

func NewBzip2Archive

func NewBzip2Archive(inputReader io.Reader) Bzip2Archive

NewBzip2Archive returns a new Bzip2Archive that reads from inputReader.

func (Bzip2Archive) Decompress

func (bz Bzip2Archive) Decompress(destination string) error

Decompress reads from Bzip2Archive and writes files into the destination specified.

func (Bzip2Archive) StripComponents

func (bz Bzip2Archive) StripComponents(components int) Bzip2Archive

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/v2/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.NewBzip2Archive(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

func (Bzip2Archive) WithName

func (bz Bzip2Archive) WithName(name string) Bzip2Archive

WithName provides a way of overriding the name of the file that the decompressed file will be copied into.

type Decompressor

type Decompressor interface {
	Decompress(destination string) error
}

type Executable

type Executable struct {
	// contains filtered or unexported fields
}

An Executable writes an executable files from an input stream to the with a file name specified by the option `Executable.WithName()` (or defaults to `artifact`) in the destination directory with executable permissions (0755).

func NewExecutable

func NewExecutable(inputReader io.Reader) Executable

NewExecutable returns a new Executable that reads from inputReader.

func (Executable) Decompress

func (e Executable) Decompress(destination string) error

Decompress copies the reader contents into the destination specified and sets executable permissions.

func (Executable) WithName

func (e Executable) WithName(name string) Executable

WithName provides a way of overriding the name of the file that the decompressed file will be copied into.

type GzipArchive

type GzipArchive struct {
	// contains filtered or unexported fields
}

A GzipArchive decompresses gzipped files from an input stream.

Example
package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/paketo-buildpacks/packit/v2/vacation"
)

func main() {
	buffer := bytes.NewBuffer(nil)
	gw := gzip.NewWriter(buffer)

	_, err := gw.Write([]byte(`Gzip file contents`))
	if err != nil {
		log.Fatal(err)
	}

	gw.Close()

	destination, err := os.MkdirTemp("", "destination")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(destination)

	archive := vacation.NewGzipArchive(bytes.NewReader(buffer.Bytes())).WithName("gzip-file")
	if err := archive.Decompress(destination); err != nil {
		log.Fatal(err)
	}

	content, err := os.ReadFile(filepath.Join(destination, "gzip-file"))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(content))

}
Output:

Gzip file contents

func NewGzipArchive

func NewGzipArchive(inputReader io.Reader) GzipArchive

NewGzipArchive returns a new GzipArchive that reads from inputReader.

func (GzipArchive) Decompress

func (gz GzipArchive) Decompress(destination string) error

Decompress reads from GzipArchive and writes files into the destination specified.

func (GzipArchive) StripComponents

func (gz GzipArchive) StripComponents(components int) GzipArchive

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/v2/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.NewGzipArchive(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

func (GzipArchive) WithName

func (gz GzipArchive) WithName(name string) GzipArchive

WithName provides a way of overriding the name of the file that the decompressed file will be copied into.

type NopArchive

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 with a file name specified by the option `NopArchive.WithName()` (or defaults to `artifact`) in the destination directory.

func NewNopArchive

func NewNopArchive(r io.Reader) NopArchive

NewNopArchive returns a new NopArchive

func (NopArchive) Decompress

func (na NopArchive) Decompress(destination string) error

Decompress copies the reader contents into the destination specified.

func (NopArchive) WithName

func (na NopArchive) WithName(name string) NopArchive

WithName provides a way of overriding the name of the file that the decompressed file will be copied into.

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/v2/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/v2/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 XZArchive

type XZArchive struct {
	// contains filtered or unexported fields
}

A XZArchive decompresses xz files from an input stream.

Example
package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/paketo-buildpacks/packit/v2/vacation"
	"github.com/ulikunitz/xz"
)

func main() {
	buffer := bytes.NewBuffer(nil)
	xw, err := xz.NewWriter(buffer)
	if err != nil {
		log.Fatal(err)
	}

	_, err = xw.Write([]byte(`XZ file contents`))
	if err != nil {
		log.Fatal(err)
	}

	xw.Close()

	destination, err := os.MkdirTemp("", "destination")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(destination)

	archive := vacation.NewXZArchive(bytes.NewReader(buffer.Bytes())).WithName("xz-file")
	if err := archive.Decompress(destination); err != nil {
		log.Fatal(err)
	}

	contents, err := os.ReadFile(filepath.Join(destination, "xz-file"))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(contents))

}
Output:

XZ file contents

func NewXZArchive

func NewXZArchive(inputReader io.Reader) XZArchive

NewXZArchive returns a new XZArchive that reads from inputReader.

func (XZArchive) Decompress

func (xzArchive XZArchive) Decompress(destination string) error

Decompress reads from XZArchive and writes files into the destination specified.

func (XZArchive) StripComponents

func (xzArchive XZArchive) StripComponents(components int) XZArchive

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/v2/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.NewXZArchive(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

func (XZArchive) WithName

func (xzArchive XZArchive) WithName(name string) XZArchive

WithName provides a way of overriding the name of the file that the decompressed file will be copied into.

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/v2/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

func (z ZipArchive) StripComponents(components int) ZipArchive

StripComponents removes the first n levels from the final decompression destination.

Jump to

Keyboard shortcuts

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