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