1package archiver
2
3import (
4	"fmt"
5	"io"
6	"log"
7	"net/http"
8	"os"
9	"strconv"
10)
11
12// The simplest use of this package: create an archive file
13// from a list of filenames. This is the recommended way to
14// do so using a default configuration, as it guarantees
15// the file format matches the file extension, because the
16// format to write is determined by the given extension.
17func ExampleArchive() {
18	// any files in this list are added
19	// to the top level of the archive;
20	// directories are recursively added
21	files := []string{
22		"index.html",
23		"photo.jpg",
24		"blog", // directory
25		"/home/website/copyright.txt",
26	}
27
28	// archive format is determined by file extension
29	err := Archive(files, "blog_site.zip")
30	if err != nil {
31		log.Fatal(err)
32	}
33}
34
35// The simplest use of this package: extract all of an archive's
36// contents to a folder on disk using the default configuration.
37// The archive format is determined automatically.
38func ExampleUnarchive() {
39	err := Unarchive("blog_site.zip", "extracted/mysite")
40	if err != nil {
41		log.Fatal(err)
42	}
43}
44
45// In this example, the DefaultZip is being customized so that
46// all calls to its methods will use that configuration.
47func ExampleZip_default() {
48	DefaultZip.OverwriteExisting = true
49	DefaultZip.ImplicitTopLevelFolder = true
50	// any subsequent use of DefaultZip uses
51	// this modified configuration
52}
53
54// Here we create our own instance of the Zip format. No need
55// to use the constructor function (NewZip) or the default
56// instance (DefaultZip) if we do not want to. Instantiating
57// the type like this allows us to easily be very explicit
58// about our configuration.
59func ExampleZip_custom() {
60	z := &Zip{
61		CompressionLevel:       3,
62		OverwriteExisting:      false,
63		MkdirAll:               true,
64		SelectiveCompression:   true,
65		ImplicitTopLevelFolder: true,
66		ContinueOnError:        false,
67	}
68	// z is now ready to use for whatever (this is a dumb example)
69	fmt.Println(z.CheckExt("test.zip"))
70}
71
72// Much like the package-level Archive function, this creates an
73// archive using the configuration of the Zip instance it is called
74// on. The output filename must match the format's recognized file
75// extension(s).
76func ExampleZip_Archive() {
77	err := DefaultZip.Archive([]string{"..."}, "example.zip")
78	if err != nil {
79		log.Fatal(err)
80	}
81}
82
83// It's easy to list the items in an archive. This example
84// prints the name and size of each file in the archive. Like
85// other top-level functions in this package, the format is
86// inferred automatically for you.
87func ExampleWalk() {
88	err := Walk("example.tar.gz", func(f File) error {
89		fmt.Println(f.Name(), f.Size())
90		// you could also read the contents; f is an io.Reader!
91		return nil
92	})
93	if err != nil {
94		log.Fatal(err)
95	}
96}
97
98// This example extracts target.txt from inside example.rar
99// and puts it into a folder on disk called output/dir.
100func ExampleExtract() {
101	err := Extract("example.rar", "target.txt", "output/dir")
102	if err != nil {
103		log.Fatal(err)
104	}
105}
106
107// This example demonstrates how to read an
108// archive in a streaming fashion. The idea
109// is that you can stream the bytes of an
110// archive from a stream, regardless of
111// whether it is an actual file on disk.
112// This means that you can read a huge
113// archive file-by-file rather than having
114// to store it all on disk first. In this
115// example, we read a hypothetical archive
116// from a (fake) HTTP request body and
117// print its file names and sizes. The
118// files can be read, of course, but they
119// do not have to be.
120func ExampleZip_streamingRead() {
121	// for the sake of the example compiling, pretend we have an HTTP request
122	req := new(http.Request)
123	contentLen, err := strconv.Atoi(req.Header.Get("Content-Length"))
124	if err != nil {
125		log.Fatal(err)
126	}
127
128	// the Zip format requires knowing the length of the stream,
129	// but other formats don't generally require it, so it
130	// could be left as 0 when using those
131	err = DefaultZip.Open(req.Body, int64(contentLen))
132	if err != nil {
133		log.Fatal(err)
134	}
135	defer DefaultZip.Close()
136
137	// Note that DefaultZip now contains some state that
138	// is critical to reading the stream until it is closed,
139	// so do not reuse it until then.
140
141	// iterate each file in the archive until EOF
142	for {
143		f, err := DefaultZip.Read()
144		if err == io.EOF {
145			break
146		}
147		if err != nil {
148			log.Fatal(err)
149		}
150
151		// f is an io.ReadCloser, so you can read its contents
152		// if you wish; or you can access its header info through
153		// f.Header or the embedded os.FileInfo
154		fmt.Println("File name:", f.Name(), "File size:", f.Size())
155
156		// be sure to close f before moving on!!
157		err = f.Close()
158		if err != nil {
159			log.Fatal(err)
160		}
161	}
162}
163
164// This example demonstrates how to write an
165// archive in a streaming fashion. The idea
166// is that you can stream the bytes of a new
167// archive that is created on-the-fly from
168// generic streams. Those streams could be
169// actual files on disk, or they could be over
170// a network, or standard output, or any other
171// io.Reader/io.Writer. This example only adds
172// one file to the archive and writes the
173// resulting archive to standard output, but you
174// could add as many files as needed with a loop.
175func ExampleZip_streamingWrite() {
176	err := DefaultZip.Create(os.Stdout)
177	if err != nil {
178		log.Fatal(err)
179	}
180	defer DefaultZip.Close()
181
182	// Note that DefaultZip now contains state
183	// critical to a successful write until it
184	// is closed, so don't reuse it for anything
185	// else until then.
186
187	// At this point, you can open an actual file
188	// to add to the archive, or the "file" could
189	// come from any io.ReadCloser stream. If you
190	// only have an io.Reader, you can use
191	// ReadFakeCloser to make it into an
192	// io.ReadCloser.
193
194	// The next part is a little tricky if you
195	// don't have an actual file because you will
196	// need an os.FileInfo. Fortunately, that's an
197	// interface! So go ahead and implement it in
198	// whatever way makes the most sense to you.
199	// You'll also need to give the file a name
200	// for within the archive. In this example,
201	// we'll open a real file.
202
203	file, err := os.Open("foo.txt")
204	if err != nil {
205		log.Fatal(err)
206	}
207	defer file.Close()
208	fileInfo, err := file.Stat()
209	if err != nil {
210		log.Fatal(err)
211	}
212
213	err = DefaultZip.Write(File{
214		FileInfo: FileInfo{
215			FileInfo:   fileInfo,
216			CustomName: "name/in/archive.txt",
217		},
218		ReadCloser: file, // does not have to be an actual file
219	})
220	if err != nil {
221		log.Fatal(err)
222	}
223}
224
225// This example compresses a standard tar file into a tar.gz file.
226// Compression formats are selected by file extension.
227func ExampleCompressFile() {
228	err := CompressFile("example.tar", "example.tar.gz")
229	if err != nil {
230		log.Fatal(err)
231	}
232}
233
234// This example changes the default configuration for
235// the Gz compression format.
236func ExampleCompressFile_custom() {
237	DefaultGz.CompressionLevel = 5
238	// any calls to DefaultGz now use the modified configuration
239}
240
241// This example creates a new Gz instance and
242// uses it to compress a stream, writing to
243// another stream. This is sometimes preferable
244// over modifying the DefaultGz.
245func ExampleGz_Compress_custom() {
246	gz := &Gz{CompressionLevel: 5}
247	err := gz.Compress(os.Stdin, os.Stdout)
248	if err != nil {
249		log.Fatal(err)
250	}
251}
252
253// This example decompresses a gzipped tarball and writes
254// it to an adjacent file.
255func ExampleDecompressFile() {
256	err := DecompressFile("example.tar.gz", "example.tar")
257	if err != nil {
258		log.Fatal(err)
259	}
260}
261