feat: Add compressionn support to update cmd

This commit is contained in:
Felicitas Pojtinger
2021-11-30 23:05:01 +01:00
parent 5f97bd692c
commit 002d4df82f
2 changed files with 111 additions and 35 deletions

View File

@@ -61,20 +61,7 @@ var archiveCmd = &cobra.Command{
return err
}
compressionLevelIsKnown := false
compressionLevel := viper.GetString(compressionLevelFlag)
for _, candidate := range knownCompressionLevels {
if compressionLevel == candidate {
compressionLevelIsKnown = true
}
}
if !compressionLevelIsKnown {
return errUnknownCompressionLevel
}
return nil
return checkCompressionLevel(viper.GetString(compressionLevelFlag))
},
RunE: func(cmd *cobra.Command, args []string) error {
if viper.GetBool(verboseFlag) {
@@ -234,10 +221,6 @@ func archive(
return err
}
if err := file.Close(); err != nil {
return err
}
if hdr.PAXRecords == nil {
hdr.PAXRecords = map[string]string{}
}
@@ -302,18 +285,30 @@ func archive(
return err
}
if err := file.Close(); err != nil {
return err
}
dirty = true
return nil
})
}
func checkCompressionLevel(compressionLevel string) error {
compressionLevelIsKnown := false
for _, candidate := range knownCompressionLevels {
if compressionLevel == candidate {
compressionLevelIsKnown = true
}
}
if !compressionLevelIsKnown {
return errUnknownCompressionLevel
}
return nil
}
func compress(
file io.Reader,
file io.ReadCloser,
tw io.Writer,
compressionFormat string,
compressionLevel string,
@@ -384,6 +379,9 @@ func compress(
if err := gz.Close(); err != nil {
return err
}
if err := file.Close(); err != nil {
return err
}
case compressionFormatLZ4Key:
l := lz4.Level5
switch compressionLevel {
@@ -420,6 +418,9 @@ func compress(
if err := lz.Close(); err != nil {
return err
}
if err := file.Close(); err != nil {
return err
}
case compressionFormatZStandardKey:
l := zstd.SpeedDefault
switch compressionLevel {
@@ -459,6 +460,9 @@ func compress(
if err := zz.Close(); err != nil {
return err
}
if err := file.Close(); err != nil {
return err
}
case compressionFormatBrotliKey:
l := brotli.DefaultCompression
switch compressionLevel {
@@ -495,6 +499,9 @@ func compress(
if err := br.Close(); err != nil {
return err
}
if err := file.Close(); err != nil {
return err
}
case compressionFormatBzip2Key:
fallthrough
case compressionFormatBzip2ParallelKey:
@@ -535,6 +542,9 @@ func compress(
if err := bz.Close(); err != nil {
return err
}
if err := file.Close(); err != nil {
return err
}
case compressionFormatNoneKey:
if isRegular {
if _, err := io.Copy(tw, file); err != nil {
@@ -546,6 +556,10 @@ func compress(
return err
}
}
if err := file.Close(); err != nil {
return err
}
default:
return errUnsupportedCompressionFormat
}

View File

@@ -3,13 +3,15 @@ package cmd
import (
"archive/tar"
"context"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strconv"
"github.com/pojntfx/stfs/pkg/adapters"
"github.com/pojntfx/stfs/pkg/controllers"
"github.com/pojntfx/stfs/pkg/counters"
"github.com/pojntfx/stfs/pkg/formatting"
"github.com/pojntfx/stfs/pkg/pax"
"github.com/pojntfx/stfs/pkg/persisters"
@@ -22,6 +24,13 @@ var updateCmd = &cobra.Command{
Use: "update",
Aliases: []string{"upd", "u"},
Short: "Update a file or directory's content and metadata on tape or tar file",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err
}
return checkCompressionLevel(viper.GetString(compressionLevelFlag))
},
RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err
@@ -46,6 +55,8 @@ var updateCmd = &cobra.Command{
viper.GetInt(recordSizeFlag),
viper.GetString(srcFlag),
viper.GetBool(overwriteFlag),
viper.GetString(compressionFlag),
viper.GetString(compressionLevelFlag),
); err != nil {
return err
}
@@ -67,6 +78,8 @@ func update(
recordSize int,
src string,
replacesContent bool,
compressionFormat string,
compressionLevel string,
) error {
dirty := false
tw, isRegular, cleanup, err := openTapeWriter(tape)
@@ -105,6 +118,55 @@ func update(
hdr.PAXRecords[pax.STFSRecordVersion] = pax.STFSRecordVersion1
hdr.PAXRecords[pax.STFSRecordAction] = pax.STFSRecordActionUpdate
if info.Mode().IsRegular() && replacesContent {
// Get the compressed size for the header
file, err := os.Open(path)
if err != nil {
return err
}
fileSizeCounter := counters.CounterWriter{
Writer: io.Discard,
}
if err := compress(
file,
&fileSizeCounter,
compressionFormat,
compressionLevel,
isRegular,
recordSize,
); err != nil {
return err
}
if hdr.PAXRecords == nil {
hdr.PAXRecords = map[string]string{}
}
hdr.PAXRecords[pax.STFSRecordUncompressedSize] = strconv.Itoa(int(hdr.Size))
hdr.Size = int64(fileSizeCounter.BytesRead)
switch compressionFormat {
case compressionFormatGZipKey:
fallthrough
case compressionFormatParallelGZipKey:
hdr.Name += compressionFormatGZipSuffix
case compressionFormatLZ4Key:
hdr.Name += compressionFormatLZ4Suffix
case compressionFormatZStandardKey:
hdr.Name += compressionFormatZStandardSuffix
case compressionFormatBrotliKey:
hdr.Name += compressionFormatBrotliSuffix
case compressionFormatBzip2Key:
fallthrough
case compressionFormatBzip2ParallelKey:
hdr.Name += compressionFormatBzip2Suffix
case compressionFormatNoneKey:
default:
return errUnsupportedCompressionFormat
}
}
if first {
if err := formatting.PrintCSV(formatting.TARHeaderCSV); err != nil {
return err
@@ -128,22 +190,21 @@ func update(
return nil
}
// TODO: Implement compression
// Compress and write the file
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
if isRegular {
if _, err := io.Copy(tw, file); err != nil {
return err
}
} else {
buf := make([]byte, controllers.BlockSize*recordSize)
if _, err := io.CopyBuffer(tw, file, buf); err != nil {
return err
}
if err := compress(
file,
tw,
compressionFormat,
compressionLevel,
isRegular,
recordSize,
); err != nil {
return err
}
} else {
hdr.Size = 0 // Don't try to seek after the record
@@ -167,6 +228,7 @@ func init() {
updateCmd.PersistentFlags().IntP(recordSizeFlag, "e", 20, "Amount of 512-bit blocks per record")
updateCmd.PersistentFlags().StringP(srcFlag, "s", "", "Path of the file or directory to update")
updateCmd.PersistentFlags().BoolP(overwriteFlag, "o", false, "Replace the content on the tape or tar file")
updateCmd.PersistentFlags().StringP(compressionLevelFlag, "l", compressionLevelBalanced, fmt.Sprintf("Compression level to use (default %v, available are %v)", compressionLevelBalanced, knownCompressionLevels))
viper.AutomaticEnv()