1package main
2
3import (
4	"flag"
5	"fmt"
6	"io"
7	"os"
8	"strings"
9
10	"github.com/schollz/progressbar"
11
12	"github.com/pierrec/cmdflag"
13	"github.com/pierrec/lz4"
14)
15
16// Uncompress uncompresses a set of files or from stdin to stdout.
17func Uncompress(_ *flag.FlagSet) cmdflag.Handler {
18	return func(args ...string) (int, error) {
19		zr := lz4.NewReader(nil)
20
21		// Use stdin/stdout if no file provided.
22		if len(args) == 0 {
23			zr.Reset(os.Stdin)
24			_, err := io.Copy(os.Stdout, zr)
25			return 0, err
26		}
27
28		for fidx, zfilename := range args {
29			// Input file.
30			zfile, err := os.Open(zfilename)
31			if err != nil {
32				return fidx, err
33			}
34			zinfo, err := zfile.Stat()
35			if err != nil {
36				return fidx, err
37			}
38			mode := zinfo.Mode() // use the same mode for the output file
39
40			// Output file.
41			filename := strings.TrimSuffix(zfilename, lz4.Extension)
42			file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, mode)
43			if err != nil {
44				return fidx, err
45			}
46			zr.Reset(zfile)
47
48			zfinfo, err := zfile.Stat()
49			if err != nil {
50				return fidx, err
51			}
52			var (
53				size  int
54				out   io.Writer = file
55				zsize           = zfinfo.Size()
56				bar   *progressbar.ProgressBar
57			)
58			if zsize > 0 {
59				bar = progressbar.NewOptions64(zsize,
60					// File transfers are usually slow, make sure we display the bar at 0%.
61					progressbar.OptionSetRenderBlankState(true),
62					// Display the filename.
63					progressbar.OptionSetDescription(filename),
64					progressbar.OptionClearOnFinish(),
65				)
66				out = io.MultiWriter(out, bar)
67				zr.OnBlockDone = func(n int) {
68					size += n
69				}
70			}
71
72			// Uncompress.
73			_, err = io.Copy(out, zr)
74			if err != nil {
75				return fidx, err
76			}
77			for _, c := range []io.Closer{zfile, file} {
78				err := c.Close()
79				if err != nil {
80					return fidx, err
81				}
82			}
83
84			if bar != nil {
85				_ = bar.Clear()
86				fmt.Printf("%s %d\n", zfilename, size)
87			}
88		}
89
90		return len(args), nil
91	}
92}
93