Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.

Commit 3ce15a5

Browse files
committed
Deprecation
1 parent e1f152f commit 3ce15a5

File tree

2 files changed

+6
-322
lines changed

2 files changed

+6
-322
lines changed

.github/SECURITY.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
## Supported Versions
44

5+
This repository is no longer maintained. Please see [mholt/archives](https://github.com/mholt/archives) instead.
6+
57
| Version | Supported |
68
| ------- | ------------------ |
7-
| >= 4.x | :white_check_mark: |
9+
| >= 4.x | :x: |
810
| < 4.0 | :x: |
911

1012
## Reporting a Vulnerability

README.md

Lines changed: 3 additions & 321 deletions
Original file line numberDiff line numberDiff line change
@@ -1,323 +1,5 @@
1-
# archiver [![Go Reference](https://pkg.go.dev/badge/github.com/mholt/archiver/v4.svg)](https://pkg.go.dev/github.com/mholt/archiver/v4) [![Ubuntu-latest](https://github.com/mholt/archiver/actions/workflows/ubuntu-latest.yml/badge.svg)](https://github.com/mholt/archiver/actions/workflows/ubuntu-latest.yml) [![Macos-latest](https://github.com/mholt/archiver/actions/workflows/macos-latest.yml/badge.svg)](https://github.com/mholt/archiver/actions/workflows/macos-latest.yml) [![Windows-latest](https://github.com/mholt/archiver/actions/workflows/windows-latest.yml/badge.svg)](https://github.com/mholt/archiver/actions/workflows/windows-latest.yml)
1+
# archiver v4 alpha (DEPRECATED)
22

3-
Introducing **Archiver 4.0 (alpha)** - a cross-platform, multi-format archive utility and Go library. A powerful and flexible library meets an elegant CLI in this generic replacement for several platform-specific or format-specific archive utilities.
4-
5-
**:warning: v4 is in ALPHA. The core library APIs work pretty well but the command has not been implemented yet, nor have most automated tests. If you need the `arc` command, stick with v3 for now.**
6-
7-
## Features
8-
9-
- Stream-oriented APIs
10-
- Automatically identify archive and compression formats:
11-
- By file name
12-
- By header
13-
- Traverse directories, archive files, and any other file uniformly as [`io/fs`](https://pkg.go.dev/io/fs) file systems:
14-
- [`FileFS`](https://pkg.go.dev/github.com/mholt/archiver/v4#FileFS)
15-
- [`DirFS`](https://pkg.go.dev/github.com/mholt/archiver/v4#DirFS)
16-
- [`ArchiveFS`](https://pkg.go.dev/github.com/mholt/archiver/v4#ArchiveFS)
17-
- Compress and decompress files
18-
- Create and extract archive files
19-
- Walk or traverse into archive files
20-
- Extract only specific files from archives
21-
- Insert (append) into .tar and .zip archives
22-
- Read from password-protected 7-Zip files
23-
- Numerous archive and compression formats supported
24-
- Extensible (add more formats just by registering them)
25-
- Cross-platform, static binary
26-
- Pure Go (no cgo)
27-
- Multithreaded Gzip
28-
- Adjust compression levels
29-
- Automatically add compressed files to zip archives without re-compressing
30-
- Open password-protected RAR archives
31-
32-
### Supported compression formats
33-
34-
- brotli (.br)
35-
- bzip2 (.bz2)
36-
- flate (.zip)
37-
- gzip (.gz)
38-
- lz4 (.lz4)
39-
- lzip (.lz)
40-
- snappy (.sz)
41-
- xz (.xz)
42-
- zlib (.zz)
43-
- zstandard (.zst)
44-
45-
### Supported archive formats
46-
47-
- .zip
48-
- .tar (including any compressed variants like .tar.gz)
49-
- .rar (read-only)
50-
- .7z (read-only)
51-
52-
Tar files can optionally be compressed using any compression format.
53-
54-
## Command use
55-
56-
Coming soon for v4. See [the last v3 docs](https://github.com/mholt/archiver/tree/v3.5.1).
57-
58-
59-
## Library use
60-
61-
```bash
62-
$ go get github.com/mholt/archiver/v4
63-
```
64-
65-
66-
### Create archive
67-
68-
Creating archives can be done entirely without needing a real disk or storage device since all you need is a list of [`File` structs](https://pkg.go.dev/github.com/mholt/archiver/v4#File) to pass in.
69-
70-
However, creating archives from files on disk is very common, so you can use the [`FilesFromDisk()` function](https://pkg.go.dev/github.com/mholt/archiver/v4#FilesFromDisk) to help you map filenames on disk to their paths in the archive. Then create and customize the format type.
71-
72-
In this example, we add 4 files and a directory (which includes its contents recursively) to a .tar.gz file:
73-
74-
```go
75-
// map files on disk to their paths in the archive
76-
files, err := archiver.FilesFromDisk(nil, map[string]string{
77-
"/path/on/disk/file1.txt": "file1.txt",
78-
"/path/on/disk/file2.txt": "subfolder/file2.txt",
79-
"/path/on/disk/file3.txt": "", // put in root of archive as file3.txt
80-
"/path/on/disk/file4.txt": "subfolder/", // put in subfolder as file4.txt
81-
"/path/on/disk/folder": "Custom Folder", // contents added recursively
82-
})
83-
if err != nil {
84-
return err
85-
}
86-
87-
// create the output file we'll write to
88-
out, err := os.Create("example.tar.gz")
89-
if err != nil {
90-
return err
91-
}
92-
defer out.Close()
93-
94-
// we can use the Archive type to gzip a tarball
95-
// (compression is not required; you could use Tar directly)
96-
format := archiver.Archive{
97-
Compression: archiver.Gz{},
98-
Archival: archiver.Tar{},
99-
Extraction: archiver.Tar{},
100-
}
101-
102-
// create the archive
103-
err = format.Archive(context.Background(), out, files)
104-
if err != nil {
105-
return err
106-
}
107-
```
108-
109-
The first parameter to `FilesFromDisk()` is an optional options struct, allowing you to customize how files are added.
110-
111-
### Extract archive
112-
113-
Extracting an archive, extracting _from_ an archive, and walking an archive are all the same function.
114-
115-
Simply use your format type (e.g. `Zip`) to call `Extract()`. You'll pass in a context (for cancellation), the input stream, and a callback function to handle each file.
116-
117-
```go
118-
// the type that will be used to read the input stream
119-
var format archiver.Zip
120-
121-
err := format.Extract(ctx, input, func(ctx context.Context, f archiver.File) error {
122-
// do something with the file
123-
return nil
124-
})
125-
if err != nil {
126-
return err
127-
}
128-
```
129-
130-
### Identifying formats
131-
132-
Have an input stream with unknown contents? No problem, archiver can identify it for you. It will try matching based on filename and/or the header (which peeks at the stream):
133-
134-
```go
135-
format, input, err := archiver.Identify(ctx, "filename.tar.zst", input)
136-
if err != nil {
137-
return err
138-
}
139-
// you can now type-assert format to whatever you need;
140-
// be sure to use returned stream to re-read consumed bytes during Identify()
141-
142-
// want to extract something?
143-
if ex, ok := format.(archiver.Extractor); ok {
144-
// ... proceed to extract
145-
}
146-
147-
// or maybe it's compressed and you want to decompress it?
148-
if decomp, ok := format.(archiver.Decompressor); ok {
149-
rc, err := decomp.OpenReader(unknownFile)
150-
if err != nil {
151-
return err
152-
}
153-
defer rc.Close()
154-
155-
// read from rc to get decompressed data
156-
}
157-
```
158-
159-
`Identify()` works by reading an arbitrary number of bytes from the beginning of the stream (just enough to check for file headers). It buffers them and returns a new reader that lets you re-read them anew. If your input stream is `io.Seeker` however, no buffer is created (it uses `Seek()` instead).
160-
161-
### Virtual file systems
162-
163-
This is my favorite feature.
164-
165-
Let's say you have a file. It could be a real directory on disk, an archive, a compressed archive, or any other regular file (or stream!). You don't really care; you just want to use it uniformly no matter what it is.
166-
167-
Use archiver to simply create a file system:
168-
169-
```go
170-
// filename could be:
171-
// - a folder ("/home/you/Desktop")
172-
// - an archive ("example.zip")
173-
// - a compressed archive ("example.tar.gz")
174-
// - a regular file ("example.txt")
175-
// - a compressed regular file ("example.txt.gz")
176-
fsys, err := archiver.FileSystem(ctx, filename, nil)
177-
if err != nil {
178-
return err
179-
}
180-
```
181-
182-
This is a fully-featured `fs.FS`, so you can open files and read directories, no matter what kind of file the input was.
183-
184-
For example, to open a specific file:
185-
186-
```go
187-
f, err := fsys.Open("file")
188-
if err != nil {
189-
return err
190-
}
191-
defer f.Close()
192-
```
193-
194-
If you opened a regular file, you can read from it. If it's a compressed file, reads are automatically decompressed.
195-
196-
If you opened a directory, you can list its contents:
197-
198-
```go
199-
if dir, ok := f.(fs.ReadDirFile); ok {
200-
// 0 gets all entries, but you can pass > 0 to paginate
201-
entries, err := dir.ReadDir(0)
202-
if err != nil {
203-
return err
204-
}
205-
for _, e := range entries {
206-
fmt.Println(e.Extension())
207-
}
208-
}
209-
```
210-
211-
Or get a directory listing this way:
212-
213-
```go
214-
entries, err := fsys.ReadDir("Playlists")
215-
if err != nil {
216-
return err
217-
}
218-
for _, e := range entries {
219-
fmt.Println(e.Extension())
220-
}
221-
```
222-
223-
Or maybe you want to walk all or part of the file system, but skip a folder named `.git`:
224-
225-
```go
226-
err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
227-
if err != nil {
228-
return err
229-
}
230-
if path == ".git" {
231-
return fs.SkipDir
232-
}
233-
fmt.Println("Walking:", path, "Dir?", d.IsDir())
234-
return nil
235-
})
236-
if err != nil {
237-
return err
238-
}
239-
```
240-
241-
**Important .tar note:** Tar files do not efficiently implement file system semantics due to their roots in sequential-access design for tapes. File systems inherently assume random access, but tar files need to be read from the beginning to access something at the end. This is especially slow when the archive is compressed. Optimizations have been implemented to amortize `ReadDir()` calls so that `fs.WalkDir()` only has to scan the archive once, but they use more memory. Open calls require another scan to find the file. It may be more efficient to use `Tar.Extract()` directly if file system semantics are not important to you.
242-
243-
#### Use with `http.FileServer`
244-
245-
It can be used with http.FileServer to browse archives and directories in a browser. However, due to how http.FileServer works, don't directly use http.FileServer with compressed files; instead wrap it like following:
246-
247-
```go
248-
fileServer := http.FileServer(http.FS(archiveFS))
249-
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
250-
// disable range request
251-
writer.Header().Set("Accept-Ranges", "none")
252-
request.Header.Del("Range")
253-
254-
// disable content-type sniffing
255-
ctype := mime.TypeByExtension(filepath.Ext(request.URL.Path))
256-
writer.Header()["Content-Type"] = nil
257-
if ctype != "" {
258-
writer.Header().Set("Content-Type", ctype)
259-
}
260-
fileServer.ServeHTTP(writer, request)
261-
})
262-
```
263-
264-
http.FileServer will try to sniff the Content-Type by default if it can't be inferred from file name. To do this, the http package will try to read from the file and then Seek back to file start, which the libray can't achieve currently. The same goes with Range requests. Seeking in archives is not currently supported by archiver due to limitations in dependencies.
265-
266-
If content-type is desirable, you can [register it](https://pkg.go.dev/mime#AddExtensionType) yourself.
267-
268-
### Compress data
269-
270-
Compression formats let you open writers to compress data:
271-
272-
```go
273-
// wrap underlying writer w
274-
compressor, err := archiver.Zstd{}.OpenWriter(w)
275-
if err != nil {
276-
return err
277-
}
278-
defer compressor.Close()
279-
280-
// writes to compressor will be compressed
281-
```
282-
283-
### Decompress data
284-
285-
Similarly, compression formats let you open readers to decompress data:
286-
287-
```go
288-
// wrap underlying reader r
289-
decompressor, err := archiver.Brotli{}.OpenReader(r)
290-
if err != nil {
291-
return err
292-
}
293-
defer decompressor.Close()
294-
295-
// reads from decompressor will be decompressed
296-
```
297-
298-
### Append to tarball and zip archives
299-
300-
Tar and Zip archives can be appended to without creating a whole new archive by calling `Insert()` on a tar or zip stream. However, for tarballs, this requires that the tarball is not compressed (due to complexities with modifying compression dictionaries).
301-
302-
Here is an example that appends a file to a tarball on disk:
303-
304-
```go
305-
tarball, err := os.OpenFile("example.tar", os.O_RDWR, 0644)
306-
if err != nil {
307-
return err
308-
}
309-
defer tarball.Close()
310-
311-
// prepare a text file for the root of the archive
312-
files, err := archiver.FilesFromDisk(nil, map[string]string{
313-
"/home/you/lastminute.txt": "",
314-
})
315-
316-
err := archiver.Tar{}.Insert(context.Background(), tarball, files)
317-
if err != nil {
318-
return err
319-
}
320-
```
321-
322-
The code is similar for inserting into a Zip archive, except you'll call `Insert()` on the `Zip` type instead.
3+
This package is no longer developed; it has been superceded by **[mholt/archives](https://github.com/mholt/archives)** with an improved, more conventional exported API, significant performance improvements, and new features.
3234

5+
Thank you to [all 71 contributors](https://github.com/mholt/archiver/graphs/contributors) over the 8 years this version of the project was developed! It lives at **[mholt/archives](https://github.com/mholt/archives)**.

0 commit comments

Comments
 (0)